1ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich/*
2ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich * GPIO driver for Analog Devices ADP5520 MFD PMICs
3ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich *
4ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich * Copyright 2009 Analog Devices Inc.
5ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich *
6ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich * Licensed under the GPL-2 or later.
7ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich */
8ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
9ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/module.h>
105a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
11ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/kernel.h>
12ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/init.h>
13ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/platform_device.h>
14ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/mfd/adp5520.h>
15ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
16ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich#include <linux/gpio.h>
17ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
18ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstruct adp5520_gpio {
19ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct device *master;
20ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct gpio_chip gpio_chip;
21ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	unsigned char lut[ADP5520_MAXGPIOS];
22ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	unsigned long output;
23ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich};
24ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
25ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic int adp5520_gpio_get_value(struct gpio_chip *chip, unsigned off)
26ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
27ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
28ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	uint8_t reg_val;
29ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
30ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
31ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
32ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	/*
33ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	 * There are dedicated registers for GPIO IN/OUT.
34ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	 * Make sure we return the right value, even when configured as output
35ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	 */
36ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
37ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (test_bit(off, &dev->output))
387c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		adp5520_read(dev->master, ADP5520_GPIO_OUT, &reg_val);
39ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	else
407c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		adp5520_read(dev->master, ADP5520_GPIO_IN, &reg_val);
41ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
42ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	return !!(reg_val & dev->lut[off]);
43ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
44ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
45ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic void adp5520_gpio_set_value(struct gpio_chip *chip,
46ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		unsigned off, int val)
47ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
48ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
49ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
50ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
51ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (val)
527c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		adp5520_set_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
53ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	else
547c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT, dev->lut[off]);
55ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
56ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
57ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic int adp5520_gpio_direction_input(struct gpio_chip *chip, unsigned off)
58ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
59ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
60ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
61ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
62ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	clear_bit(off, &dev->output);
63ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
647c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	return adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_2,
657c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich				dev->lut[off]);
66ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
67ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
68ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic int adp5520_gpio_direction_output(struct gpio_chip *chip,
69ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		unsigned off, int val)
70ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
71ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
72ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	int ret = 0;
73ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = container_of(chip, struct adp5520_gpio, gpio_chip);
74ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
75ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	set_bit(off, &dev->output);
76ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
77ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (val)
787c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_OUT,
797c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich					dev->lut[off]);
80ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	else
817c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		ret |= adp5520_clr_bits(dev->master, ADP5520_GPIO_OUT,
827c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich					dev->lut[off]);
83ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
847c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_CFG_2,
857c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich					dev->lut[off]);
86ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
87ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	return ret;
88ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
89ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
90ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic int __devinit adp5520_gpio_probe(struct platform_device *pdev)
91ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
927c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
93ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
94ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct gpio_chip *gc;
95ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	int ret, i, gpios;
96ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	unsigned char ctl_mask = 0;
97ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
98ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (pdata == NULL) {
99ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		dev_err(&pdev->dev, "missing platform data\n");
100ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		return -ENODEV;
101ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
102ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
103ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (pdev->id != ID_ADP5520) {
104ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		dev_err(&pdev->dev, "only ADP5520 supports GPIO\n");
105ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		return -ENODEV;
106ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
107ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
108ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
109ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (dev == NULL) {
110ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		dev_err(&pdev->dev, "failed to alloc memory\n");
111ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		return -ENOMEM;
112ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
113ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
114ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev->master = pdev->dev.parent;
115ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
116ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	for (gpios = 0, i = 0; i < ADP5520_MAXGPIOS; i++)
117ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		if (pdata->gpio_en_mask & (1 << i))
118ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich			dev->lut[gpios++] = 1 << i;
119ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
120ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (gpios < 1) {
121ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		ret = -EINVAL;
122ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		goto err;
123ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
124ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
125ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc = &dev->gpio_chip;
126ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->direction_input  = adp5520_gpio_direction_input;
127ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->direction_output = adp5520_gpio_direction_output;
128ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->get = adp5520_gpio_get_value;
129ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->set = adp5520_gpio_set_value;
130ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->can_sleep = 1;
131ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
132ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->base = pdata->gpio_start;
133ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->ngpio = gpios;
134ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->label = pdev->name;
135ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	gc->owner = THIS_MODULE;
136ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
1377c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	ret = adp5520_clr_bits(dev->master, ADP5520_GPIO_CFG_1,
138ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		pdata->gpio_en_mask);
139ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
1407c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	if (pdata->gpio_en_mask & ADP5520_GPIO_C3)
1417c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		ctl_mask |= ADP5520_C3_MODE;
142ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
1437c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	if (pdata->gpio_en_mask & ADP5520_GPIO_R3)
1447c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		ctl_mask |= ADP5520_R3_MODE;
145ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
146ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (ctl_mask)
1477c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich		ret = adp5520_set_bits(dev->master, ADP5520_LED_CONTROL,
148ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich			ctl_mask);
149ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
1507c29a47668a922bd99f3e69a833dc1000b603134Michael Hennerich	ret |= adp5520_set_bits(dev->master, ADP5520_GPIO_PULLUP,
151ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		pdata->gpio_pullup_mask);
152ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
153ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (ret) {
154ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		dev_err(&pdev->dev, "failed to write\n");
155ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		goto err;
156ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
157ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
158ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	ret = gpiochip_add(&dev->gpio_chip);
159ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (ret)
160ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		goto err;
161ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
162ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	platform_set_drvdata(pdev, dev);
163ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	return 0;
164ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
165ef72af408259f0ff26a733dfa2088d570a111550Michael Hennericherr:
166ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	kfree(dev);
167ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	return ret;
168ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
169ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
170ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic int __devexit adp5520_gpio_remove(struct platform_device *pdev)
171ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich{
172ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	struct adp5520_gpio *dev;
173ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	int ret;
174ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
175ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	dev = platform_get_drvdata(pdev);
176ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	ret = gpiochip_remove(&dev->gpio_chip);
177ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	if (ret) {
178ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		dev_err(&pdev->dev, "%s failed, %d\n",
179ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich				"gpiochip_remove()", ret);
180ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		return ret;
181ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	}
182ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
183ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	kfree(dev);
184ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	return 0;
185ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich}
186ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
187ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerichstatic struct platform_driver adp5520_gpio_driver = {
188ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	.driver	= {
189ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		.name	= "adp5520-gpio",
190ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich		.owner	= THIS_MODULE,
191ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	},
192ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	.probe		= adp5520_gpio_probe,
193ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich	.remove		= __devexit_p(adp5520_gpio_remove),
194ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich};
195ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
1966f61415e9c4c0ab02c8eda7671bb652db4863cc0Mark Brownmodule_platform_driver(adp5520_gpio_driver);
197ef72af408259f0ff26a733dfa2088d570a111550Michael Hennerich
198ef72af408259f0ff26a733dfa2088d570a111550Michael HennerichMODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
199ef72af408259f0ff26a733dfa2088d570a111550Michael HennerichMODULE_DESCRIPTION("GPIO ADP5520 Driver");
200ef72af408259f0ff26a733dfa2088d570a111550Michael HennerichMODULE_LICENSE("GPL");
201ef72af408259f0ff26a733dfa2088d570a111550Michael HennerichMODULE_ALIAS("platform:adp5520-gpio");
202