xref: /openbmc/linux/drivers/gpio/gpio-da9052.c (revision 615c36f5)
1 /*
2  * GPIO Driver for Dialog DA9052 PMICs.
3  *
4  * Copyright(c) 2011 Dialog Semiconductor Ltd.
5  *
6  * Author: David Dajun Chen <dchen@diasemi.com>
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  *
13  */
14 #include <linux/module.h>
15 #include <linux/fs.h>
16 #include <linux/uaccess.h>
17 #include <linux/platform_device.h>
18 #include <linux/gpio.h>
19 #include <linux/syscalls.h>
20 #include <linux/seq_file.h>
21 
22 #include <linux/mfd/da9052/da9052.h>
23 #include <linux/mfd/da9052/reg.h>
24 #include <linux/mfd/da9052/pdata.h>
25 #include <linux/mfd/da9052/gpio.h>
26 
27 #define DA9052_INPUT				1
28 #define DA9052_OUTPUT_OPENDRAIN		2
29 #define DA9052_OUTPUT_PUSHPULL			3
30 
31 #define DA9052_SUPPLY_VDD_IO1			0
32 
33 #define DA9052_DEBOUNCING_OFF			0
34 #define DA9052_DEBOUNCING_ON			1
35 
36 #define DA9052_OUTPUT_LOWLEVEL			0
37 
38 #define DA9052_ACTIVE_LOW			0
39 #define DA9052_ACTIVE_HIGH			1
40 
41 #define DA9052_GPIO_MAX_PORTS_PER_REGISTER	8
42 #define DA9052_GPIO_SHIFT_COUNT(no)		(no%8)
43 #define DA9052_GPIO_MASK_UPPER_NIBBLE		0xF0
44 #define DA9052_GPIO_MASK_LOWER_NIBBLE		0x0F
45 #define DA9052_GPIO_NIBBLE_SHIFT		4
46 
47 struct da9052_gpio {
48 	struct da9052 *da9052;
49 	struct gpio_chip gp;
50 };
51 
52 static inline struct da9052_gpio *to_da9052_gpio(struct gpio_chip *chip)
53 {
54 	return container_of(chip, struct da9052_gpio, gp);
55 }
56 
57 static unsigned char da9052_gpio_port_odd(unsigned offset)
58 {
59 	return offset % 2;
60 }
61 
62 static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset)
63 {
64 	struct da9052_gpio *gpio = to_da9052_gpio(gc);
65 	int da9052_port_direction = 0;
66 	int ret;
67 
68 	ret = da9052_reg_read(gpio->da9052,
69 			      DA9052_GPIO_0_1_REG + (offset >> 1));
70 	if (ret < 0)
71 		return ret;
72 
73 	if (da9052_gpio_port_odd(offset)) {
74 		da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN;
75 		da9052_port_direction >>= 4;
76 	} else {
77 		da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN;
78 	}
79 
80 	switch (da9052_port_direction) {
81 	case DA9052_INPUT:
82 		if (offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER)
83 			ret = da9052_reg_read(gpio->da9052,
84 					      DA9052_STATUS_C_REG);
85 		else
86 			ret = da9052_reg_read(gpio->da9052,
87 					      DA9052_STATUS_D_REG);
88 		if (ret < 0)
89 			return ret;
90 		if (ret & (1 << DA9052_GPIO_SHIFT_COUNT(offset)))
91 			return 1;
92 		else
93 			return 0;
94 	case DA9052_OUTPUT_PUSHPULL:
95 		if (da9052_gpio_port_odd(offset))
96 			return ret & DA9052_GPIO_ODD_PORT_MODE;
97 		else
98 			return ret & DA9052_GPIO_EVEN_PORT_MODE;
99 	default:
100 		return -EINVAL;
101 	}
102 }
103 
104 static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
105 {
106 	struct da9052_gpio *gpio = to_da9052_gpio(gc);
107 	unsigned char register_value = 0;
108 	int ret;
109 
110 	if (da9052_gpio_port_odd(offset)) {
111 		if (value) {
112 			register_value = DA9052_GPIO_ODD_PORT_MODE;
113 			ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
114 						DA9052_GPIO_0_1_REG,
115 						DA9052_GPIO_ODD_PORT_MODE,
116 						register_value);
117 			if (ret != 0)
118 				dev_err(gpio->da9052->dev,
119 					"Failed to updated gpio odd reg,%d",
120 					ret);
121 		}
122 	} else {
123 		if (value) {
124 			register_value = DA9052_GPIO_EVEN_PORT_MODE;
125 			ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
126 						DA9052_GPIO_0_1_REG,
127 						DA9052_GPIO_EVEN_PORT_MODE,
128 						register_value);
129 			if (ret != 0)
130 				dev_err(gpio->da9052->dev,
131 					"Failed to updated gpio even reg,%d",
132 					ret);
133 		}
134 	}
135 }
136 
137 static int da9052_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
138 {
139 	struct da9052_gpio *gpio = to_da9052_gpio(gc);
140 	unsigned char register_value;
141 	int ret;
142 
143 	/* Format: function - 2 bits type - 1 bit mode - 1 bit */
144 	register_value = DA9052_INPUT | DA9052_ACTIVE_LOW << 2 |
145 			 DA9052_DEBOUNCING_ON << 3;
146 
147 	if (da9052_gpio_port_odd(offset))
148 		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
149 					DA9052_GPIO_0_1_REG,
150 					DA9052_GPIO_MASK_UPPER_NIBBLE,
151 					(register_value <<
152 					DA9052_GPIO_NIBBLE_SHIFT));
153 	else
154 		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
155 					DA9052_GPIO_0_1_REG,
156 					DA9052_GPIO_MASK_LOWER_NIBBLE,
157 					register_value);
158 
159 	return ret;
160 }
161 
162 static int da9052_gpio_direction_output(struct gpio_chip *gc,
163 					unsigned offset, int value)
164 {
165 	struct da9052_gpio *gpio = to_da9052_gpio(gc);
166 	unsigned char register_value;
167 	int ret;
168 
169 	/* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */
170 	register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 << 2 |
171 			 value << 3;
172 
173 	if (da9052_gpio_port_odd(offset))
174 		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
175 					DA9052_GPIO_0_1_REG,
176 					DA9052_GPIO_MASK_UPPER_NIBBLE,
177 					(register_value <<
178 					DA9052_GPIO_NIBBLE_SHIFT));
179 	else
180 		ret = da9052_reg_update(gpio->da9052, (offset >> 1) +
181 					DA9052_GPIO_0_1_REG,
182 					DA9052_GPIO_MASK_LOWER_NIBBLE,
183 					register_value);
184 
185 	return ret;
186 }
187 
188 static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
189 {
190 	struct da9052_gpio *gpio = to_da9052_gpio(gc);
191 	struct da9052 *da9052 = gpio->da9052;
192 
193 	return da9052->irq_base + DA9052_IRQ_GPI0 + offset;
194 }
195 
196 static struct gpio_chip reference_gp __devinitdata = {
197 	.label = "da9052-gpio",
198 	.owner = THIS_MODULE,
199 	.get = da9052_gpio_get,
200 	.set = da9052_gpio_set,
201 	.direction_input = da9052_gpio_direction_input,
202 	.direction_output = da9052_gpio_direction_output,
203 	.to_irq = da9052_gpio_to_irq,
204 	.can_sleep = 1;
205 	.ngpio = 16;
206 	.base = -1;
207 };
208 
209 static int __devinit da9052_gpio_probe(struct platform_device *pdev)
210 {
211 	struct da9052_gpio *gpio;
212 	struct da9052_pdata *pdata;
213 	int ret;
214 
215 	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
216 	if (gpio == NULL)
217 		return -ENOMEM;
218 
219 	gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
220 	pdata = gpio->da9052->dev->platform_data;
221 
222 	gpio->gp = reference_gp;
223 	if (pdata && pdata->gpio_base)
224 		gpio->gp.base = pdata->gpio_base;
225 
226 	ret = gpiochip_add(&gpio->gp);
227 	if (ret < 0) {
228 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
229 		goto err_mem;
230 	}
231 
232 	platform_set_drvdata(pdev, gpio);
233 
234 	return 0;
235 
236 err_mem:
237 	kfree(gpio);
238 	return ret;
239 }
240 
241 static int __devexit da9052_gpio_remove(struct platform_device *pdev)
242 {
243 	struct da9052_gpio *gpio = platform_get_drvdata(pdev);
244 	int ret;
245 
246 	ret = gpiochip_remove(&gpio->gp);
247 	if (ret == 0)
248 		kfree(gpio);
249 
250 	return ret;
251 }
252 
253 static struct platform_driver da9052_gpio_driver = {
254 	.probe = da9052_gpio_probe,
255 	.remove = __devexit_p(da9052_gpio_remove),
256 	.driver = {
257 		.name	= "da9052-gpio",
258 		.owner	= THIS_MODULE,
259 	},
260 };
261 
262 static int __init da9052_gpio_init(void)
263 {
264 	return platform_driver_register(&da9052_gpio_driver);
265 }
266 module_init(da9052_gpio_init);
267 
268 static void __exit da9052_gpio_exit(void)
269 {
270 	return platform_driver_unregister(&da9052_gpio_driver);
271 }
272 module_exit(da9052_gpio_exit);
273 
274 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
275 MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
276 MODULE_LICENSE("GPL");
277 MODULE_ALIAS("platform:da9052-gpio");
278