cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio-da9052.c (5792B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * GPIO Driver for Dialog DA9052 PMICs.
      4 *
      5 * Copyright(c) 2011 Dialog Semiconductor Ltd.
      6 *
      7 * Author: David Dajun Chen <dchen@diasemi.com>
      8 */
      9#include <linux/module.h>
     10#include <linux/fs.h>
     11#include <linux/uaccess.h>
     12#include <linux/platform_device.h>
     13#include <linux/gpio/driver.h>
     14#include <linux/syscalls.h>
     15#include <linux/seq_file.h>
     16
     17#include <linux/mfd/da9052/da9052.h>
     18#include <linux/mfd/da9052/reg.h>
     19#include <linux/mfd/da9052/pdata.h>
     20
     21#define DA9052_INPUT				1
     22#define DA9052_OUTPUT_OPENDRAIN		2
     23#define DA9052_OUTPUT_PUSHPULL			3
     24
     25#define DA9052_SUPPLY_VDD_IO1			0
     26
     27#define DA9052_DEBOUNCING_OFF			0
     28#define DA9052_DEBOUNCING_ON			1
     29
     30#define DA9052_OUTPUT_LOWLEVEL			0
     31
     32#define DA9052_ACTIVE_LOW			0
     33#define DA9052_ACTIVE_HIGH			1
     34
     35#define DA9052_GPIO_MAX_PORTS_PER_REGISTER	8
     36#define DA9052_GPIO_SHIFT_COUNT(no)		(no%8)
     37#define DA9052_GPIO_MASK_UPPER_NIBBLE		0xF0
     38#define DA9052_GPIO_MASK_LOWER_NIBBLE		0x0F
     39#define DA9052_GPIO_NIBBLE_SHIFT		4
     40#define DA9052_IRQ_GPI0			16
     41#define DA9052_GPIO_ODD_SHIFT			7
     42#define DA9052_GPIO_EVEN_SHIFT			3
     43
     44struct da9052_gpio {
     45	struct da9052 *da9052;
     46	struct gpio_chip gp;
     47};
     48
     49static unsigned char da9052_gpio_port_odd(unsigned offset)
     50{
     51	return offset % 2;
     52}
     53
     54static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
     55{
     56	struct da9052_gpio *gpio = gpiochip_get_data(gc);
     57	int da9052_port_direction = 0;
     58	int ret;
     59
     60	ret = da9052_reg_read(gpio->da9052,
     61			      DA9052_GPIO_0_1_REG + (offset >> 1));
     62	if (ret < 0)
     63		return ret;
     64
     65	if (da9052_gpio_port_odd(offset)) {
     66		da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN;
     67		da9052_port_direction >>= 4;
     68	} else {
     69		da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN;
     70	}
     71
     72	switch (da9052_port_direction) {
     73	case DA9052_INPUT:
     74		if (offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER)
     75			ret = da9052_reg_read(gpio->da9052,
     76					      DA9052_STATUS_C_REG);
     77		else
     78			ret = da9052_reg_read(gpio->da9052,
     79					      DA9052_STATUS_D_REG);
     80		if (ret < 0)
     81			return ret;
     82		return !!(ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)));
     83	case DA9052_OUTPUT_PUSHPULL:
     84		if (da9052_gpio_port_odd(offset))
     85			return !!(ret & DA9052_GPIO_ODD_PORT_MODE);
     86		else
     87			return !!(ret & DA9052_GPIO_EVEN_PORT_MODE);
     88	default:
     89		return -EINVAL;
     90	}
     91}
     92
     93static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
     94{
     95	struct da9052_gpio *gpio = gpiochip_get_data(gc);
     96	int ret;
     97
     98	if (da9052_gpio_port_odd(offset)) {
     99			ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    100						DA9052_GPIO_0_1_REG,
    101						DA9052_GPIO_ODD_PORT_MODE,
    102						value << DA9052_GPIO_ODD_SHIFT);
    103			if (ret != 0)
    104				dev_err(gpio->da9052->dev,
    105					"Failed to updated gpio odd reg,%d",
    106					ret);
    107	} else {
    108			ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    109						DA9052_GPIO_0_1_REG,
    110						DA9052_GPIO_EVEN_PORT_MODE,
    111						value << DA9052_GPIO_EVEN_SHIFT);
    112			if (ret != 0)
    113				dev_err(gpio->da9052->dev,
    114					"Failed to updated gpio even reg,%d",
    115					ret);
    116	}
    117}
    118
    119static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
    120{
    121	struct da9052_gpio *gpio = gpiochip_get_data(gc);
    122	unsigned char register_value;
    123	int ret;
    124
    125	/* Format: function - 2 bits type - 1 bit mode - 1 bit */
    126	register_value = DA9052_INPUT | DA9052_ACTIVE_LOW << 2 |
    127			 DA9052_DEBOUNCING_ON << 3;
    128
    129	if (da9052_gpio_port_odd(offset))
    130		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    131					DA9052_GPIO_0_1_REG,
    132					DA9052_GPIO_MASK_UPPER_NIBBLE,
    133					(register_value <<
    134					DA9052_GPIO_NIBBLE_SHIFT));
    135	else
    136		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    137					DA9052_GPIO_0_1_REG,
    138					DA9052_GPIO_MASK_LOWER_NIBBLE,
    139					register_value);
    140
    141	return ret;
    142}
    143
    144static int da9052_gpio_direction_output(struct gpio_chip *gc,
    145					unsigned offset, int value)
    146{
    147	struct da9052_gpio *gpio = gpiochip_get_data(gc);
    148	unsigned char register_value;
    149	int ret;
    150
    151	/* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */
    152	register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 << 2 |
    153			 value << 3;
    154
    155	if (da9052_gpio_port_odd(offset))
    156		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    157					DA9052_GPIO_0_1_REG,
    158					DA9052_GPIO_MASK_UPPER_NIBBLE,
    159					(register_value <<
    160					DA9052_GPIO_NIBBLE_SHIFT));
    161	else
    162		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
    163					DA9052_GPIO_0_1_REG,
    164					DA9052_GPIO_MASK_LOWER_NIBBLE,
    165					register_value);
    166
    167	return ret;
    168}
    169
    170static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
    171{
    172	struct da9052_gpio *gpio = gpiochip_get_data(gc);
    173	struct da9052 *da9052 = gpio->da9052;
    174
    175	int irq;
    176
    177	irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset);
    178
    179	return irq;
    180}
    181
    182static const struct gpio_chip reference_gp = {
    183	.label = "da9052-gpio",
    184	.owner = THIS_MODULE,
    185	.get = da9052_gpio_get,
    186	.set = da9052_gpio_set,
    187	.direction_input = da9052_gpio_direction_input,
    188	.direction_output = da9052_gpio_direction_output,
    189	.to_irq = da9052_gpio_to_irq,
    190	.can_sleep = true,
    191	.ngpio = 16,
    192	.base = -1,
    193};
    194
    195static int da9052_gpio_probe(struct platform_device *pdev)
    196{
    197	struct da9052_gpio *gpio;
    198	struct da9052_pdata *pdata;
    199
    200	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
    201	if (!gpio)
    202		return -ENOMEM;
    203
    204	gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
    205	pdata = dev_get_platdata(gpio->da9052->dev);
    206
    207	gpio->gp = reference_gp;
    208	if (pdata && pdata->gpio_base)
    209		gpio->gp.base = pdata->gpio_base;
    210
    211	return devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
    212}
    213
    214static struct platform_driver da9052_gpio_driver = {
    215	.probe = da9052_gpio_probe,
    216	.driver = {
    217		.name	= "da9052-gpio",
    218	},
    219};
    220
    221module_platform_driver(da9052_gpio_driver);
    222
    223MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
    224MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
    225MODULE_LICENSE("GPL");
    226MODULE_ALIAS("platform:da9052-gpio");