xref: /linux/drivers/gpio/gpio-adp5520.c (revision 0227b49b50276657243e54f5609e65c4f0eaaf4d)
180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ef72af40SMichael Hennerich /*
3ef72af40SMichael Hennerich  * GPIO driver for Analog Devices ADP5520 MFD PMICs
4ef72af40SMichael Hennerich  *
5ef72af40SMichael Hennerich  * Copyright 2009 Analog Devices Inc.
6ef72af40SMichael Hennerich  */
7ef72af40SMichael Hennerich 
8ef72af40SMichael Hennerich #include <linux/module.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
10ef72af40SMichael Hennerich #include <linux/kernel.h>
11ef72af40SMichael Hennerich #include <linux/init.h>
12ef72af40SMichael Hennerich #include <linux/platform_device.h>
13ef72af40SMichael Hennerich #include <linux/mfd/adp5520.h>
148a3b4f20SLinus Walleij #include <linux/gpio/driver.h>
15ef72af40SMichael Hennerich 
16ef72af40SMichael Hennerich struct adp5520_gpio {
17ef72af40SMichael Hennerich 	struct device *master;
18ef72af40SMichael Hennerich 	struct gpio_chip gpio_chip;
19ef72af40SMichael Hennerich 	unsigned char lut[ADP5520_MAXGPIOS];
20ef72af40SMichael Hennerich 	unsigned long output;
21ef72af40SMichael Hennerich };
22ef72af40SMichael Hennerich 
adp5520_gpio_get_value(struct gpio_chip * chip,unsigned off)23ef72af40SMichael Hennerich static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
24ef72af40SMichael Hennerich {
25ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
26ef72af40SMichael Hennerich 	uint8_t reg_val;
27ef72af40SMichael Hennerich 
285060e0e8SLinus Walleij 	dev = gpiochip_get_data(chip);
29ef72af40SMichael Hennerich 
30ef72af40SMichael Hennerich 	/*
31ef72af40SMichael Hennerich 	 * There are dedicated registers for GPIO IN/OUT.
32ef72af40SMichael Hennerich 	 * Make sure we return the right value, even when configured as output
33ef72af40SMichael Hennerich 	 */
34ef72af40SMichael Hennerich 
35ef72af40SMichael Hennerich 	if (test_bit(off, &dev->output))
367c29a476SMichael Hennerich 		adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
37ef72af40SMichael Hennerich 	else
387c29a476SMichael Hennerich 		adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
39ef72af40SMichael Hennerich 
40ef72af40SMichael Hennerich 	return !!(reg_val & dev->lut[off]);
41ef72af40SMichael Hennerich }
42ef72af40SMichael Hennerich 
adp5520_gpio_set_value(struct gpio_chip * chip,unsigned int off,int val)438a9bc5a5SBartosz Golaszewski static int adp5520_gpio_set_value(struct gpio_chip *chip,
448a9bc5a5SBartosz Golaszewski 				  unsigned int off, int val)
45ef72af40SMichael Hennerich {
46ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
475060e0e8SLinus Walleij 	dev = gpiochip_get_data(chip);
48ef72af40SMichael Hennerich 
49ef72af40SMichael Hennerich 	if (val)
508a9bc5a5SBartosz Golaszewski 		return adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
518a9bc5a5SBartosz Golaszewski 					dev->lut[off]);
52ef72af40SMichael Hennerich 	else
538a9bc5a5SBartosz Golaszewski 		return adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
548a9bc5a5SBartosz Golaszewski 					dev->lut[off]);
55ef72af40SMichael Hennerich }
56ef72af40SMichael Hennerich 
adp5520_gpio_direction_input(struct gpio_chip * chip,unsigned off)57ef72af40SMichael Hennerich static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
58ef72af40SMichael Hennerich {
59ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
605060e0e8SLinus Walleij 	dev = gpiochip_get_data(chip);
61ef72af40SMichael Hennerich 
62ef72af40SMichael Hennerich 	clear_bit(off, &dev->output);
63ef72af40SMichael Hennerich 
647c29a476SMichael Hennerich 	return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
657c29a476SMichael Hennerich 				dev->lut[off]);
66ef72af40SMichael Hennerich }
67ef72af40SMichael Hennerich 
adp5520_gpio_direction_output(struct gpio_chip * chip,unsigned off,int val)68ef72af40SMichael Hennerich static int adp5520_gpio_direction_output(struct gpio_chip *chip,
69ef72af40SMichael Hennerich 		unsigned off, int val)
70ef72af40SMichael Hennerich {
71ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
72ef72af40SMichael Hennerich 	int ret = 0;
735060e0e8SLinus Walleij 	dev = gpiochip_get_data(chip);
74ef72af40SMichael Hennerich 
75ef72af40SMichael Hennerich 	set_bit(off, &dev->output);
76ef72af40SMichael Hennerich 
77ef72af40SMichael Hennerich 	if (val)
787c29a476SMichael Hennerich 		ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
797c29a476SMichael Hennerich 					dev->lut[off]);
80ef72af40SMichael Hennerich 	else
817c29a476SMichael Hennerich 		ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
827c29a476SMichael Hennerich 					dev->lut[off]);
83ef72af40SMichael Hennerich 
847c29a476SMichael Hennerich 	ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
857c29a476SMichael Hennerich 					dev->lut[off]);
86ef72af40SMichael Hennerich 
87ef72af40SMichael Hennerich 	return ret;
88ef72af40SMichael Hennerich }
89ef72af40SMichael Hennerich 
adp5520_gpio_probe(struct platform_device * pdev)903836309dSBill Pemberton static int adp5520_gpio_probe(struct platform_device *pdev)
91ef72af40SMichael Hennerich {
92e56aee18SJingoo Han 	struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
93ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
94ef72af40SMichael Hennerich 	struct gpio_chip *gc;
95ef72af40SMichael Hennerich 	int ret, i, gpios;
96ef72af40SMichael Hennerich 	unsigned char ctl_mask = 0;
97ef72af40SMichael Hennerich 
98ef72af40SMichael Hennerich 	if (pdata == NULL) {
99ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "missing platform data\n");
100ef72af40SMichael Hennerich 		return -ENODEV;
101ef72af40SMichael Hennerich 	}
102ef72af40SMichael Hennerich 
103ef72af40SMichael Hennerich 	if (pdev->id != ID_ADP5520) {
104ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "only ADP5520 supports GPIO\n");
105ef72af40SMichael Hennerich 		return -ENODEV;
106ef72af40SMichael Hennerich 	}
107ef72af40SMichael Hennerich 
10824bb3813SJingoo Han 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
109e8a71aaaSJingoo Han 	if (dev == NULL)
110ef72af40SMichael Hennerich 		return -ENOMEM;
111ef72af40SMichael Hennerich 
112ef72af40SMichael Hennerich 	dev->master = pdev->dev.parent;
113ef72af40SMichael Hennerich 
114ef72af40SMichael Hennerich 	for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++)
115ef72af40SMichael Hennerich 		if (pdata->gpio_en_mask & (1 << i))
116ef72af40SMichael Hennerich 			dev->lut[gpios++] = 1 << i;
117ef72af40SMichael Hennerich 
1186681db5eSAlexandru Ardelean 	if (gpios < 1)
1196681db5eSAlexandru Ardelean 		return -EINVAL;
120ef72af40SMichael Hennerich 
121ef72af40SMichael Hennerich 	gc = &dev->gpio_chip;
122ef72af40SMichael Hennerich 	gc->direction_input  = adp5520_gpio_direction_input;
123ef72af40SMichael Hennerich 	gc->direction_output = adp5520_gpio_direction_output;
124ef72af40SMichael Hennerich 	gc->get = adp5520_gpio_get_value;
125*d9d87d90SBartosz Golaszewski 	gc->set = adp5520_gpio_set_value;
1269fb1f39eSLinus Walleij 	gc->can_sleep = true;
127ef72af40SMichael Hennerich 
128ef72af40SMichael Hennerich 	gc->base = pdata->gpio_start;
129ef72af40SMichael Hennerich 	gc->ngpio = gpios;
130ef72af40SMichael Hennerich 	gc->label = pdev->name;
131ef72af40SMichael Hennerich 	gc->owner = THIS_MODULE;
132ef72af40SMichael Hennerich 
1337c29a476SMichael Hennerich 	ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
134ef72af40SMichael Hennerich 		pdata->gpio_en_mask);
135ef72af40SMichael Hennerich 
1367c29a476SMichael Hennerich 	if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
1377c29a476SMichael Hennerich 		ctl_mask |= ADP5520_C3_MODE;
138ef72af40SMichael Hennerich 
1397c29a476SMichael Hennerich 	if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
1407c29a476SMichael Hennerich 		ctl_mask |= ADP5520_R3_MODE;
141ef72af40SMichael Hennerich 
142ef72af40SMichael Hennerich 	if (ctl_mask)
1437c29a476SMichael Hennerich 		ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
144ef72af40SMichael Hennerich 			ctl_mask);
145ef72af40SMichael Hennerich 
1467c29a476SMichael Hennerich 	ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
147ef72af40SMichael Hennerich 		pdata->gpio_pullup_mask);
148ef72af40SMichael Hennerich 
149ef72af40SMichael Hennerich 	if (ret) {
150ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "failed to write\n");
1516681db5eSAlexandru Ardelean 		return ret;
152ef72af40SMichael Hennerich 	}
153ef72af40SMichael Hennerich 
1546681db5eSAlexandru Ardelean 	return devm_gpiochip_add_data(&pdev->dev, &dev->gpio_chip, dev);
155ef72af40SMichael Hennerich }
156ef72af40SMichael Hennerich 
157ef72af40SMichael Hennerich static struct platform_driver adp5520_gpio_driver = {
158ef72af40SMichael Hennerich 	.driver	= {
159ef72af40SMichael Hennerich 		.name	= "adp5520-gpio",
160ef72af40SMichael Hennerich 	},
161ef72af40SMichael Hennerich 	.probe		= adp5520_gpio_probe,
162ef72af40SMichael Hennerich };
163ef72af40SMichael Hennerich 
1646f61415eSMark Brown module_platform_driver(adp5520_gpio_driver);
165ef72af40SMichael Hennerich 
166be887843SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
167ef72af40SMichael Hennerich MODULE_DESCRIPTION("GPIO ADP5520 Driver");
168ef72af40SMichael Hennerich MODULE_LICENSE("GPL");
169ef72af40SMichael Hennerich MODULE_ALIAS("platform:adp5520-gpio");
170