Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * GPIO driver for Analog Devices ADP5520 MFD PMICs
0004  *
0005  * Copyright 2009 Analog Devices Inc.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/mfd/adp5520.h>
0014 #include <linux/gpio/driver.h>
0015 
0016 struct adp5520_gpio {
0017     struct device *master;
0018     struct gpio_chip gpio_chip;
0019     unsigned char lut[ADP5520_MAXGPIOS];
0020     unsigned long output;
0021 };
0022 
0023 static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
0024 {
0025     struct adp5520_gpio *dev;
0026     uint8_t reg_val;
0027 
0028     dev = gpiochip_get_data(chip);
0029 
0030     /*
0031      * There are dedicated registers for GPIO IN/OUT.
0032      * Make sure we return the right value, even when configured as output
0033      */
0034 
0035     if (test_bit(off, &dev->output))
0036         adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
0037     else
0038         adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
0039 
0040     return !!(reg_val & dev->lut[off]);
0041 }
0042 
0043 static void adp5520_gpio_set_value(struct gpio_chip *chip,
0044         unsigned off, int val)
0045 {
0046     struct adp5520_gpio *dev;
0047     dev = gpiochip_get_data(chip);
0048 
0049     if (val)
0050         adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
0051     else
0052         adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
0053 }
0054 
0055 static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
0056 {
0057     struct adp5520_gpio *dev;
0058     dev = gpiochip_get_data(chip);
0059 
0060     clear_bit(off, &dev->output);
0061 
0062     return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
0063                 dev->lut[off]);
0064 }
0065 
0066 static int adp5520_gpio_direction_output(struct gpio_chip *chip,
0067         unsigned off, int val)
0068 {
0069     struct adp5520_gpio *dev;
0070     int ret = 0;
0071     dev = gpiochip_get_data(chip);
0072 
0073     set_bit(off, &dev->output);
0074 
0075     if (val)
0076         ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
0077                     dev->lut[off]);
0078     else
0079         ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
0080                     dev->lut[off]);
0081 
0082     ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
0083                     dev->lut[off]);
0084 
0085     return ret;
0086 }
0087 
0088 static int adp5520_gpio_probe(struct platform_device *pdev)
0089 {
0090     struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
0091     struct adp5520_gpio *dev;
0092     struct gpio_chip *gc;
0093     int ret, i, gpios;
0094     unsigned char ctl_mask = 0;
0095 
0096     if (pdata == NULL) {
0097         dev_err(&pdev->dev, "missing platform data\n");
0098         return -ENODEV;
0099     }
0100 
0101     if (pdev->id != ID_ADP5520) {
0102         dev_err(&pdev->dev, "only ADP5520 supports GPIO\n");
0103         return -ENODEV;
0104     }
0105 
0106     dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
0107     if (dev == NULL)
0108         return -ENOMEM;
0109 
0110     dev->master = pdev->dev.parent;
0111 
0112     for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++)
0113         if (pdata->gpio_en_mask & (1 << i))
0114             dev->lut[gpios++] = 1 << i;
0115 
0116     if (gpios < 1)
0117         return -EINVAL;
0118 
0119     gc = &dev->gpio_chip;
0120     gc->direction_input  = adp5520_gpio_direction_input;
0121     gc->direction_output = adp5520_gpio_direction_output;
0122     gc->get = adp5520_gpio_get_value;
0123     gc->set = adp5520_gpio_set_value;
0124     gc->can_sleep = true;
0125 
0126     gc->base = pdata->gpio_start;
0127     gc->ngpio = gpios;
0128     gc->label = pdev->name;
0129     gc->owner = THIS_MODULE;
0130 
0131     ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
0132         pdata->gpio_en_mask);
0133 
0134     if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
0135         ctl_mask |= ADP5520_C3_MODE;
0136 
0137     if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
0138         ctl_mask |= ADP5520_R3_MODE;
0139 
0140     if (ctl_mask)
0141         ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
0142             ctl_mask);
0143 
0144     ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
0145         pdata->gpio_pullup_mask);
0146 
0147     if (ret) {
0148         dev_err(&pdev->dev, "failed to write\n");
0149         return ret;
0150     }
0151 
0152     return devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev);
0153 }
0154 
0155 static struct platform_driver adp5520_gpio_driver = {
0156     .driver = {
0157         .name   = "adp5520-gpio",
0158     },
0159     .probe      = adp5520_gpio_probe,
0160 };
0161 
0162 module_platform_driver(adp5520_gpio_driver);
0163 
0164 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
0165 MODULE_DESCRIPTION("GPIO ADP5520 Driver");
0166 MODULE_LICENSE("GPL");
0167 MODULE_ALIAS("platform:adp5520-gpio");