xref: /linux/drivers/gpio/gpio-adp5520.c (revision e56aee1897fd27631c1cb28e12b0fb8f8f9736f7)
1ef72af40SMichael Hennerich /*
2ef72af40SMichael Hennerich  * GPIO driver for Analog Devices ADP5520 MFD PMICs
3ef72af40SMichael Hennerich  *
4ef72af40SMichael Hennerich  * Copyright 2009 Analog Devices Inc.
5ef72af40SMichael Hennerich  *
6ef72af40SMichael Hennerich  * Licensed under the GPL-2 or later.
7ef72af40SMichael Hennerich  */
8ef72af40SMichael Hennerich 
9ef72af40SMichael Hennerich #include <linux/module.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
11ef72af40SMichael Hennerich #include <linux/kernel.h>
12ef72af40SMichael Hennerich #include <linux/init.h>
13ef72af40SMichael Hennerich #include <linux/platform_device.h>
14ef72af40SMichael Hennerich #include <linux/mfd/adp5520.h>
15ef72af40SMichael Hennerich 
16ef72af40SMichael Hennerich #include <linux/gpio.h>
17ef72af40SMichael Hennerich 
18ef72af40SMichael Hennerich struct adp5520_gpio {
19ef72af40SMichael Hennerich 	struct device *master;
20ef72af40SMichael Hennerich 	struct gpio_chip gpio_chip;
21ef72af40SMichael Hennerich 	unsigned char lut[ADP5520_MAXGPIOS];
22ef72af40SMichael Hennerich 	unsigned long output;
23ef72af40SMichael Hennerich };
24ef72af40SMichael Hennerich 
25ef72af40SMichael Hennerich static int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
26ef72af40SMichael Hennerich {
27ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
28ef72af40SMichael Hennerich 	uint8_t reg_val;
29ef72af40SMichael Hennerich 
30ef72af40SMichael Hennerich 	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
31ef72af40SMichael Hennerich 
32ef72af40SMichael Hennerich 	/*
33ef72af40SMichael Hennerich 	 * There are dedicated registers for GPIO IN/OUT.
34ef72af40SMichael Hennerich 	 * Make sure we return the right value, even when configured as output
35ef72af40SMichael Hennerich 	 */
36ef72af40SMichael Hennerich 
37ef72af40SMichael Hennerich 	if (test_bit(off, &dev->output))
387c29a476SMichael Hennerich 		adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
39ef72af40SMichael Hennerich 	else
407c29a476SMichael Hennerich 		adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
41ef72af40SMichael Hennerich 
42ef72af40SMichael Hennerich 	return !!(reg_val & dev->lut[off]);
43ef72af40SMichael Hennerich }
44ef72af40SMichael Hennerich 
45ef72af40SMichael Hennerich static void adp5520_gpio_set_value(struct gpio_chip *chip,
46ef72af40SMichael Hennerich 		unsigned off, int val)
47ef72af40SMichael Hennerich {
48ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
49ef72af40SMichael Hennerich 	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
50ef72af40SMichael Hennerich 
51ef72af40SMichael Hennerich 	if (val)
527c29a476SMichael Hennerich 		adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
53ef72af40SMichael Hennerich 	else
547c29a476SMichael Hennerich 		adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
55ef72af40SMichael Hennerich }
56ef72af40SMichael Hennerich 
57ef72af40SMichael Hennerich static int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
58ef72af40SMichael Hennerich {
59ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
60ef72af40SMichael Hennerich 	dev = container_of(chip, struct adp5520_gpio, gpio_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 
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;
73ef72af40SMichael Hennerich 	dev = container_of(chip, struct adp5520_gpio, gpio_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 
903836309dSBill Pemberton static int adp5520_gpio_probe(struct platform_device *pdev)
91ef72af40SMichael Hennerich {
92*e56aee18SJingoo 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);
109ef72af40SMichael Hennerich 	if (dev == NULL) {
110ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "failed to alloc memory\n");
111ef72af40SMichael Hennerich 		return -ENOMEM;
112ef72af40SMichael Hennerich 	}
113ef72af40SMichael Hennerich 
114ef72af40SMichael Hennerich 	dev->master = pdev->dev.parent;
115ef72af40SMichael Hennerich 
116ef72af40SMichael Hennerich 	for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++)
117ef72af40SMichael Hennerich 		if (pdata->gpio_en_mask & (1 << i))
118ef72af40SMichael Hennerich 			dev->lut[gpios++] = 1 << i;
119ef72af40SMichael Hennerich 
120ef72af40SMichael Hennerich 	if (gpios < 1) {
121ef72af40SMichael Hennerich 		ret = -EINVAL;
122ef72af40SMichael Hennerich 		goto err;
123ef72af40SMichael Hennerich 	}
124ef72af40SMichael Hennerich 
125ef72af40SMichael Hennerich 	gc = &dev->gpio_chip;
126ef72af40SMichael Hennerich 	gc->direction_input  = adp5520_gpio_direction_input;
127ef72af40SMichael Hennerich 	gc->direction_output = adp5520_gpio_direction_output;
128ef72af40SMichael Hennerich 	gc->get = adp5520_gpio_get_value;
129ef72af40SMichael Hennerich 	gc->set = adp5520_gpio_set_value;
130ef72af40SMichael Hennerich 	gc->can_sleep = 1;
131ef72af40SMichael Hennerich 
132ef72af40SMichael Hennerich 	gc->base = pdata->gpio_start;
133ef72af40SMichael Hennerich 	gc->ngpio = gpios;
134ef72af40SMichael Hennerich 	gc->label = pdev->name;
135ef72af40SMichael Hennerich 	gc->owner = THIS_MODULE;
136ef72af40SMichael Hennerich 
1377c29a476SMichael Hennerich 	ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
138ef72af40SMichael Hennerich 		pdata->gpio_en_mask);
139ef72af40SMichael Hennerich 
1407c29a476SMichael Hennerich 	if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
1417c29a476SMichael Hennerich 		ctl_mask |= ADP5520_C3_MODE;
142ef72af40SMichael Hennerich 
1437c29a476SMichael Hennerich 	if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
1447c29a476SMichael Hennerich 		ctl_mask |= ADP5520_R3_MODE;
145ef72af40SMichael Hennerich 
146ef72af40SMichael Hennerich 	if (ctl_mask)
1477c29a476SMichael Hennerich 		ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
148ef72af40SMichael Hennerich 			ctl_mask);
149ef72af40SMichael Hennerich 
1507c29a476SMichael Hennerich 	ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
151ef72af40SMichael Hennerich 		pdata->gpio_pullup_mask);
152ef72af40SMichael Hennerich 
153ef72af40SMichael Hennerich 	if (ret) {
154ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "failed to write\n");
155ef72af40SMichael Hennerich 		goto err;
156ef72af40SMichael Hennerich 	}
157ef72af40SMichael Hennerich 
158ef72af40SMichael Hennerich 	ret = gpiochip_add(&dev->gpio_chip);
159ef72af40SMichael Hennerich 	if (ret)
160ef72af40SMichael Hennerich 		goto err;
161ef72af40SMichael Hennerich 
162ef72af40SMichael Hennerich 	platform_set_drvdata(pdev, dev);
163ef72af40SMichael Hennerich 	return 0;
164ef72af40SMichael Hennerich 
165ef72af40SMichael Hennerich err:
166ef72af40SMichael Hennerich 	return ret;
167ef72af40SMichael Hennerich }
168ef72af40SMichael Hennerich 
169206210ceSBill Pemberton static int adp5520_gpio_remove(struct platform_device *pdev)
170ef72af40SMichael Hennerich {
171ef72af40SMichael Hennerich 	struct adp5520_gpio *dev;
172ef72af40SMichael Hennerich 	int ret;
173ef72af40SMichael Hennerich 
174ef72af40SMichael Hennerich 	dev = platform_get_drvdata(pdev);
175ef72af40SMichael Hennerich 	ret = gpiochip_remove(&dev->gpio_chip);
176ef72af40SMichael Hennerich 	if (ret) {
177ef72af40SMichael Hennerich 		dev_err(&pdev->dev, "%s failed, %d\n",
178ef72af40SMichael Hennerich 				"gpiochip_remove()", ret);
179ef72af40SMichael Hennerich 		return ret;
180ef72af40SMichael Hennerich 	}
181ef72af40SMichael Hennerich 
182ef72af40SMichael Hennerich 	return 0;
183ef72af40SMichael Hennerich }
184ef72af40SMichael Hennerich 
185ef72af40SMichael Hennerich static struct platform_driver adp5520_gpio_driver = {
186ef72af40SMichael Hennerich 	.driver	= {
187ef72af40SMichael Hennerich 		.name	= "adp5520-gpio",
188ef72af40SMichael Hennerich 		.owner	= THIS_MODULE,
189ef72af40SMichael Hennerich 	},
190ef72af40SMichael Hennerich 	.probe		= adp5520_gpio_probe,
1918283c4ffSBill Pemberton 	.remove		= adp5520_gpio_remove,
192ef72af40SMichael Hennerich };
193ef72af40SMichael Hennerich 
1946f61415eSMark Brown module_platform_driver(adp5520_gpio_driver);
195ef72af40SMichael Hennerich 
196ef72af40SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
197ef72af40SMichael Hennerich MODULE_DESCRIPTION("GPIO ADP5520 Driver");
198ef72af40SMichael Hennerich MODULE_LICENSE("GPL");
199ef72af40SMichael Hennerich MODULE_ALIAS("platform:adp5520-gpio");
200