180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c103de24SGrant Likely /*
3c103de24SGrant Likely * GPIO driver for Analog Devices ADP5520 MFD PMICs
4c103de24SGrant Likely *
5c103de24SGrant Likely * Copyright 2009 Analog Devices Inc.
6c103de24SGrant Likely */
7c103de24SGrant Likely
8c103de24SGrant Likely #include <linux/module.h>
9c103de24SGrant Likely #include <linux/slab.h>
10c103de24SGrant Likely #include <linux/kernel.h>
11c103de24SGrant Likely #include <linux/init.h>
12c103de24SGrant Likely #include <linux/platform_device.h>
13c103de24SGrant Likely #include <linux/mfd/adp5520.h>
148a3b4f20SLinus Walleij #include <linux/gpio/driver.h>
15c103de24SGrant Likely
16c103de24SGrant Likely struct adp5520_gpio {
17c103de24SGrant Likely struct device *master;
18c103de24SGrant Likely struct gpio_chip gpio_chip;
19c103de24SGrant Likely unsigned char lut[ADP5520_MAXGPIOS];
20c103de24SGrant Likely unsigned long output;
21c103de24SGrant Likely };
22c103de24SGrant Likely
adp5520_gpio_get_value(struct gpio_chip * chip,unsigned off)23c103de24SGrant Likely static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
24c103de24SGrant Likely {
25c103de24SGrant Likely struct adp5520_gpio *dev;
26c103de24SGrant Likely uint8_t reg_val;
27c103de24SGrant Likely
285060e0e8SLinus Walleij dev = gpiochip_get_data(chip);
29c103de24SGrant Likely
30c103de24SGrant Likely /*
31c103de24SGrant Likely * There are dedicated registers for GPIO IN/OUT.
32c103de24SGrant Likely * Make sure we return the right value, even when configured as output
33c103de24SGrant Likely */
34c103de24SGrant Likely
35c103de24SGrant Likely if (test_bit(off, &dev->output))
36c103de24SGrant Likely adp5520_read(dev->master, ADP5520_GPIO_OUT, ®_val);
37c103de24SGrant Likely else
38c103de24SGrant Likely adp5520_read(dev->master, ADP5520_GPIO_IN, ®_val);
39c103de24SGrant Likely
40c103de24SGrant Likely return !!(reg_val & dev->lut[off]);
41c103de24SGrant Likely }
42c103de24SGrant Likely
adp5520_gpio_set_value(struct gpio_chip * chip,unsigned off,int val)43c103de24SGrant Likely static void adp5520_gpio_set_value(struct gpio_chip *chip,
44c103de24SGrant Likely unsigned off, int val)
45c103de24SGrant Likely {
46c103de24SGrant Likely struct adp5520_gpio *dev;
475060e0e8SLinus Walleij dev = gpiochip_get_data(chip);
48c103de24SGrant Likely
49c103de24SGrant Likely if (val)
50c103de24SGrant Likely adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
51c103de24SGrant Likely else
52c103de24SGrant Likely adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
53c103de24SGrant Likely }
54c103de24SGrant Likely
adp5520_gpio_direction_input(struct gpio_chip * chip,unsigned off)55c103de24SGrant Likely static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
56c103de24SGrant Likely {
57c103de24SGrant Likely struct adp5520_gpio *dev;
585060e0e8SLinus Walleij dev = gpiochip_get_data(chip);
59c103de24SGrant Likely
60c103de24SGrant Likely clear_bit(off, &dev->output);
61c103de24SGrant Likely
62c103de24SGrant Likely return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
63c103de24SGrant Likely dev->lut[off]);
64c103de24SGrant Likely }
65c103de24SGrant Likely
adp5520_gpio_direction_output(struct gpio_chip * chip,unsigned off,int val)66c103de24SGrant Likely static int adp5520_gpio_direction_output(struct gpio_chip *chip,
67c103de24SGrant Likely unsigned off, int val)
68c103de24SGrant Likely {
69c103de24SGrant Likely struct adp5520_gpio *dev;
70c103de24SGrant Likely int ret = 0;
715060e0e8SLinus Walleij dev = gpiochip_get_data(chip);
72c103de24SGrant Likely
73c103de24SGrant Likely set_bit(off, &dev->output);
74c103de24SGrant Likely
75c103de24SGrant Likely if (val)
76c103de24SGrant Likely ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
77c103de24SGrant Likely dev->lut[off]);
78c103de24SGrant Likely else
79c103de24SGrant Likely ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
80c103de24SGrant Likely dev->lut[off]);
81c103de24SGrant Likely
82c103de24SGrant Likely ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
83c103de24SGrant Likely dev->lut[off]);
84c103de24SGrant Likely
85c103de24SGrant Likely return ret;
86c103de24SGrant Likely }
87c103de24SGrant Likely
adp5520_gpio_probe(struct platform_device * pdev)883836309dSBill Pemberton static int adp5520_gpio_probe(struct platform_device *pdev)
89c103de24SGrant Likely {
90e56aee18SJingoo Han struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
91c103de24SGrant Likely struct adp5520_gpio *dev;
92c103de24SGrant Likely struct gpio_chip *gc;
93c103de24SGrant Likely int ret, i, gpios;
94c103de24SGrant Likely unsigned char ctl_mask = 0;
95c103de24SGrant Likely
96c103de24SGrant Likely if (pdata == NULL) {
97c103de24SGrant Likely dev_err(&pdev->dev, "missing platform data\n");
98c103de24SGrant Likely return -ENODEV;
99c103de24SGrant Likely }
100c103de24SGrant Likely
101c103de24SGrant Likely if (pdev->id != ID_ADP5520) {
102c103de24SGrant Likely dev_err(&pdev->dev, "only ADP5520 supports GPIO\n");
103c103de24SGrant Likely return -ENODEV;
104c103de24SGrant Likely }
105c103de24SGrant Likely
10624bb3813SJingoo Han dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
107e8a71aaaSJingoo Han if (dev == NULL)
108c103de24SGrant Likely return -ENOMEM;
109c103de24SGrant Likely
110c103de24SGrant Likely dev->master = pdev->dev.parent;
111c103de24SGrant Likely
112c103de24SGrant Likely for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++)
113c103de24SGrant Likely if (pdata->gpio_en_mask & (1 << i))
114c103de24SGrant Likely dev->lut[gpios++] = 1 << i;
115c103de24SGrant Likely
116*6681db5eSAlexandru Ardelean if (gpios < 1)
117*6681db5eSAlexandru Ardelean return -EINVAL;
118c103de24SGrant Likely
119c103de24SGrant Likely gc = &dev->gpio_chip;
120c103de24SGrant Likely gc->direction_input = adp5520_gpio_direction_input;
121c103de24SGrant Likely gc->direction_output = adp5520_gpio_direction_output;
122c103de24SGrant Likely gc->get = adp5520_gpio_get_value;
123c103de24SGrant Likely gc->set = adp5520_gpio_set_value;
1249fb1f39eSLinus Walleij gc->can_sleep = true;
125c103de24SGrant Likely
126c103de24SGrant Likely gc->base = pdata->gpio_start;
127c103de24SGrant Likely gc->ngpio = gpios;
128c103de24SGrant Likely gc->label = pdev->name;
129c103de24SGrant Likely gc->owner = THIS_MODULE;
130c103de24SGrant Likely
131c103de24SGrant Likely ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
132c103de24SGrant Likely pdata->gpio_en_mask);
133c103de24SGrant Likely
134c103de24SGrant Likely if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
135c103de24SGrant Likely ctl_mask |= ADP5520_C3_MODE;
136c103de24SGrant Likely
137c103de24SGrant Likely if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
138c103de24SGrant Likely ctl_mask |= ADP5520_R3_MODE;
139c103de24SGrant Likely
140c103de24SGrant Likely if (ctl_mask)
141c103de24SGrant Likely ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
142c103de24SGrant Likely ctl_mask);
143c103de24SGrant Likely
144c103de24SGrant Likely ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
145c103de24SGrant Likely pdata->gpio_pullup_mask);
146c103de24SGrant Likely
147c103de24SGrant Likely if (ret) {
148c103de24SGrant Likely dev_err(&pdev->dev, "failed to write\n");
149*6681db5eSAlexandru Ardelean return ret;
150c103de24SGrant Likely }
151c103de24SGrant Likely
152*6681db5eSAlexandru Ardelean return devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev);
153c103de24SGrant Likely }
154c103de24SGrant Likely
155c103de24SGrant Likely static struct platform_driver adp5520_gpio_driver = {
156c103de24SGrant Likely .driver = {
157c103de24SGrant Likely .name = "adp5520-gpio",
158c103de24SGrant Likely },
159c103de24SGrant Likely .probe = adp5520_gpio_probe,
160c103de24SGrant Likely };
161c103de24SGrant Likely
1626f61415eSMark Brown module_platform_driver(adp5520_gpio_driver);
163c103de24SGrant Likely
164be887843SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
165c103de24SGrant Likely MODULE_DESCRIPTION("GPIO ADP5520 Driver");
166c103de24SGrant Likely MODULE_LICENSE("GPL");
167c103de24SGrant Likely MODULE_ALIAS("platform:adp5520-gpio");
168