xref: /openbmc/linux/drivers/mfd/tc3589x.c (revision 593e9d70)
1 /*
2  * Copyright (C) ST-Ericsson SA 2010
3  *
4  * License Terms: GNU General Public License, version 2
5  * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
6  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
7  */
8 
9 #include <linux/module.h>
10 #include <linux/interrupt.h>
11 #include <linux/irq.h>
12 #include <linux/slab.h>
13 #include <linux/i2c.h>
14 #include <linux/mfd/core.h>
15 #include <linux/mfd/tc3589x.h>
16 
17 #define TC3589x_CLKMODE_MODCTL_SLEEP		0x0
18 #define TC3589x_CLKMODE_MODCTL_OPERATION	(1 << 0)
19 
20 /**
21  * tc3589x_reg_read() - read a single TC3589x register
22  * @tc3589x:	Device to read from
23  * @reg:	Register to read
24  */
25 int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
26 {
27 	int ret;
28 
29 	ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
30 	if (ret < 0)
31 		dev_err(tc3589x->dev, "failed to read reg %#x: %d\n",
32 			reg, ret);
33 
34 	return ret;
35 }
36 EXPORT_SYMBOL_GPL(tc3589x_reg_read);
37 
38 /**
39  * tc3589x_reg_read() - write a single TC3589x register
40  * @tc3589x:	Device to write to
41  * @reg:	Register to read
42  * @data:	Value to write
43  */
44 int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
45 {
46 	int ret;
47 
48 	ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
49 	if (ret < 0)
50 		dev_err(tc3589x->dev, "failed to write reg %#x: %d\n",
51 			reg, ret);
52 
53 	return ret;
54 }
55 EXPORT_SYMBOL_GPL(tc3589x_reg_write);
56 
57 /**
58  * tc3589x_block_read() - read multiple TC3589x registers
59  * @tc3589x:	Device to read from
60  * @reg:	First register
61  * @length:	Number of registers
62  * @values:	Buffer to write to
63  */
64 int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
65 {
66 	int ret;
67 
68 	ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
69 	if (ret < 0)
70 		dev_err(tc3589x->dev, "failed to read regs %#x: %d\n",
71 			reg, ret);
72 
73 	return ret;
74 }
75 EXPORT_SYMBOL_GPL(tc3589x_block_read);
76 
77 /**
78  * tc3589x_block_write() - write multiple TC3589x registers
79  * @tc3589x:	Device to write to
80  * @reg:	First register
81  * @length:	Number of registers
82  * @values:	Values to write
83  */
84 int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
85 			const u8 *values)
86 {
87 	int ret;
88 
89 	ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
90 					     values);
91 	if (ret < 0)
92 		dev_err(tc3589x->dev, "failed to write regs %#x: %d\n",
93 			reg, ret);
94 
95 	return ret;
96 }
97 EXPORT_SYMBOL_GPL(tc3589x_block_write);
98 
99 /**
100  * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register
101  * @tc3589x:	Device to write to
102  * @reg:	Register to write
103  * @mask:	Mask of bits to set
104  * @values:	Value to set
105  */
106 int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
107 {
108 	int ret;
109 
110 	mutex_lock(&tc3589x->lock);
111 
112 	ret = tc3589x_reg_read(tc3589x, reg);
113 	if (ret < 0)
114 		goto out;
115 
116 	ret &= ~mask;
117 	ret |= val;
118 
119 	ret = tc3589x_reg_write(tc3589x, reg, ret);
120 
121 out:
122 	mutex_unlock(&tc3589x->lock);
123 	return ret;
124 }
125 EXPORT_SYMBOL_GPL(tc3589x_set_bits);
126 
127 static struct resource gpio_resources[] = {
128 	{
129 		.start	= TC3589x_INT_GPIIRQ,
130 		.end	= TC3589x_INT_GPIIRQ,
131 		.flags	= IORESOURCE_IRQ,
132 	},
133 };
134 
135 static struct mfd_cell tc3589x_dev_gpio[] = {
136 	{
137 		.name		= "tc3589x-gpio",
138 		.num_resources	= ARRAY_SIZE(gpio_resources),
139 		.resources	= &gpio_resources[0],
140 	},
141 };
142 
143 static irqreturn_t tc3589x_irq(int irq, void *data)
144 {
145 	struct tc3589x *tc3589x = data;
146 	int status;
147 
148 again:
149 	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
150 	if (status < 0)
151 		return IRQ_NONE;
152 
153 	while (status) {
154 		int bit = __ffs(status);
155 
156 		handle_nested_irq(tc3589x->irq_base + bit);
157 		status &= ~(1 << bit);
158 	}
159 
160 	/*
161 	 * A dummy read or write (to any register) appears to be necessary to
162 	 * have the last interrupt clear (for example, GPIO IC write) take
163 	 * effect. In such a case, recheck for any interrupt which is still
164 	 * pending.
165 	 */
166 	status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
167 	if (status)
168 		goto again;
169 
170 	return IRQ_HANDLED;
171 }
172 
173 static void tc3589x_irq_dummy(unsigned int irq)
174 {
175 	/* No mask/unmask at this level */
176 }
177 
178 static struct irq_chip tc3589x_irq_chip = {
179 	.name	= "tc3589x",
180 	.mask	= tc3589x_irq_dummy,
181 	.unmask	= tc3589x_irq_dummy,
182 };
183 
184 static int tc3589x_irq_init(struct tc3589x *tc3589x)
185 {
186 	int base = tc3589x->irq_base;
187 	int irq;
188 
189 	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
190 		set_irq_chip_data(irq, tc3589x);
191 		set_irq_chip_and_handler(irq, &tc3589x_irq_chip,
192 					 handle_edge_irq);
193 		set_irq_nested_thread(irq, 1);
194 #ifdef CONFIG_ARM
195 		set_irq_flags(irq, IRQF_VALID);
196 #else
197 		set_irq_noprobe(irq);
198 #endif
199 	}
200 
201 	return 0;
202 }
203 
204 static void tc3589x_irq_remove(struct tc3589x *tc3589x)
205 {
206 	int base = tc3589x->irq_base;
207 	int irq;
208 
209 	for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
210 #ifdef CONFIG_ARM
211 		set_irq_flags(irq, 0);
212 #endif
213 		set_irq_chip_and_handler(irq, NULL, NULL);
214 		set_irq_chip_data(irq, NULL);
215 	}
216 }
217 
218 static int tc3589x_chip_init(struct tc3589x *tc3589x)
219 {
220 	int manf, ver, ret;
221 
222 	manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
223 	if (manf < 0)
224 		return manf;
225 
226 	ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
227 	if (ver < 0)
228 		return ver;
229 
230 	if (manf != TC3589x_MANFCODE_MAGIC) {
231 		dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
232 		return -EINVAL;
233 	}
234 
235 	dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
236 
237 	/*
238 	 * Put everything except the IRQ module into reset;
239 	 * also spare the GPIO module for any pin initialization
240 	 * done during pre-kernel boot
241 	 */
242 	ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
243 				TC3589x_RSTCTRL_TIMRST
244 				| TC3589x_RSTCTRL_ROTRST
245 				| TC3589x_RSTCTRL_KBDRST);
246 	if (ret < 0)
247 		return ret;
248 
249 	/* Clear the reset interrupt. */
250 	return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
251 }
252 
253 static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
254 {
255 	int ret = 0;
256 	unsigned int blocks = tc3589x->pdata->block;
257 
258 	if (blocks & TC3589x_BLOCK_GPIO) {
259 		ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
260 				ARRAY_SIZE(tc3589x_dev_gpio), NULL,
261 				tc3589x->irq_base);
262 		if (ret) {
263 			dev_err(tc3589x->dev, "failed to add gpio child\n");
264 			return ret;
265 		}
266 		dev_info(tc3589x->dev, "added gpio block\n");
267 	}
268 
269 	return ret;
270 
271 }
272 
273 static int __devinit tc3589x_probe(struct i2c_client *i2c,
274 				   const struct i2c_device_id *id)
275 {
276 	struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
277 	struct tc3589x *tc3589x;
278 	int ret;
279 
280 	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
281 				     | I2C_FUNC_SMBUS_I2C_BLOCK))
282 		return -EIO;
283 
284 	tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL);
285 	if (!tc3589x)
286 		return -ENOMEM;
287 
288 	mutex_init(&tc3589x->lock);
289 
290 	tc3589x->dev = &i2c->dev;
291 	tc3589x->i2c = i2c;
292 	tc3589x->pdata = pdata;
293 	tc3589x->irq_base = pdata->irq_base;
294 	tc3589x->num_gpio = id->driver_data;
295 
296 	i2c_set_clientdata(i2c, tc3589x);
297 
298 	ret = tc3589x_chip_init(tc3589x);
299 	if (ret)
300 		goto out_free;
301 
302 	ret = tc3589x_irq_init(tc3589x);
303 	if (ret)
304 		goto out_free;
305 
306 	ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
307 				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
308 				   "tc3589x", tc3589x);
309 	if (ret) {
310 		dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
311 		goto out_removeirq;
312 	}
313 
314 	ret = tc3589x_device_init(tc3589x);
315 	if (ret) {
316 		dev_err(tc3589x->dev, "failed to add child devices\n");
317 		goto out_freeirq;
318 	}
319 
320 	return 0;
321 
322 out_freeirq:
323 	free_irq(tc3589x->i2c->irq, tc3589x);
324 out_removeirq:
325 	tc3589x_irq_remove(tc3589x);
326 out_free:
327 	kfree(tc3589x);
328 	return ret;
329 }
330 
331 static int __devexit tc3589x_remove(struct i2c_client *client)
332 {
333 	struct tc3589x *tc3589x = i2c_get_clientdata(client);
334 
335 	mfd_remove_devices(tc3589x->dev);
336 
337 	free_irq(tc3589x->i2c->irq, tc3589x);
338 	tc3589x_irq_remove(tc3589x);
339 
340 	kfree(tc3589x);
341 
342 	return 0;
343 }
344 
345 static int tc3589x_suspend(struct device *dev)
346 {
347 	struct tc3589x *tc3589x = dev_get_drvdata(dev);
348 	struct i2c_client *client = tc3589x->i2c;
349 	int ret = 0;
350 
351 	/* put the system to sleep mode */
352 	if (!device_may_wakeup(&client->dev))
353 		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
354 				TC3589x_CLKMODE_MODCTL_SLEEP);
355 
356 	return ret;
357 }
358 
359 static int tc3589x_resume(struct device *dev)
360 {
361 	struct tc3589x *tc3589x = dev_get_drvdata(dev);
362 	struct i2c_client *client = tc3589x->i2c;
363 	int ret = 0;
364 
365 	/* enable the system into operation */
366 	if (!device_may_wakeup(&client->dev))
367 		ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
368 				TC3589x_CLKMODE_MODCTL_OPERATION);
369 
370 	return ret;
371 }
372 
373 static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend,
374 						tc3589x_resume);
375 
376 static const struct i2c_device_id tc3589x_id[] = {
377 	{ "tc3589x", 24 },
378 	{ }
379 };
380 MODULE_DEVICE_TABLE(i2c, tc3589x_id);
381 
382 static struct i2c_driver tc3589x_driver = {
383 	.driver.name	= "tc3589x",
384 	.driver.owner	= THIS_MODULE,
385 #ifdef CONFIG_PM
386 	.driver.pm	= &tc3589x_dev_pm_ops,
387 #endif
388 	.probe		= tc3589x_probe,
389 	.remove		= __devexit_p(tc3589x_remove),
390 	.id_table	= tc3589x_id,
391 };
392 
393 static int __init tc3589x_init(void)
394 {
395 	return i2c_add_driver(&tc3589x_driver);
396 }
397 subsys_initcall(tc3589x_init);
398 
399 static void __exit tc3589x_exit(void)
400 {
401 	i2c_del_driver(&tc3589x_driver);
402 }
403 module_exit(tc3589x_exit);
404 
405 MODULE_LICENSE("GPL v2");
406 MODULE_DESCRIPTION("TC3589x MFD core driver");
407 MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
408