xref: /linux/drivers/gpio/gpio-adp5520.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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, &reg_val);
37c103de24SGrant Likely 	else
38c103de24SGrant Likely 		adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_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