linux/drivers/gpio/gpio-da9052.c
<<
>>
Prefs
   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");
 227