• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/mfd/
1/*
2 * Core driver for TI TPS6586x PMIC family
3 *
4 * Copyright (c) 2010 CompuLab Ltd.
5 * Mike Rapoport <mike@compulab.co.il>
6 *
7 * Based on da903x.c.
8 * Copyright (C) 2008 Compulab, Ltd.
9 * Mike Rapoport <mike@compulab.co.il>
10 * Copyright (C) 2006-2008 Marvell International Ltd.
11 * Eric Miao <eric.miao@marvell.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/mutex.h>
21#include <linux/slab.h>
22#include <linux/gpio.h>
23#include <linux/i2c.h>
24
25#include <linux/mfd/core.h>
26#include <linux/mfd/tps6586x.h>
27
28/* GPIO control registers */
29#define TPS6586X_GPIOSET1	0x5d
30#define TPS6586X_GPIOSET2	0x5e
31
32/* device id */
33#define TPS6586X_VERSIONCRC	0xcd
34#define TPS658621A_VERSIONCRC	0x15
35
36struct tps6586x {
37	struct mutex		lock;
38	struct device		*dev;
39	struct i2c_client	*client;
40
41	struct gpio_chip	gpio;
42};
43
44static inline int __tps6586x_read(struct i2c_client *client,
45				  int reg, uint8_t *val)
46{
47	int ret;
48
49	ret = i2c_smbus_read_byte_data(client, reg);
50	if (ret < 0) {
51		dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
52		return ret;
53	}
54
55	*val = (uint8_t)ret;
56
57	return 0;
58}
59
60static inline int __tps6586x_reads(struct i2c_client *client, int reg,
61				   int len, uint8_t *val)
62{
63	int ret;
64
65	ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
66	if (ret < 0) {
67		dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
68		return ret;
69	}
70
71	return 0;
72}
73
74static inline int __tps6586x_write(struct i2c_client *client,
75				 int reg, uint8_t val)
76{
77	int ret;
78
79	ret = i2c_smbus_write_byte_data(client, reg, val);
80	if (ret < 0) {
81		dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
82				val, reg);
83		return ret;
84	}
85
86	return 0;
87}
88
89static inline int __tps6586x_writes(struct i2c_client *client, int reg,
90				  int len, uint8_t *val)
91{
92	int ret;
93
94	ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
95	if (ret < 0) {
96		dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
97		return ret;
98	}
99
100	return 0;
101}
102
103int tps6586x_write(struct device *dev, int reg, uint8_t val)
104{
105	return __tps6586x_write(to_i2c_client(dev), reg, val);
106}
107EXPORT_SYMBOL_GPL(tps6586x_write);
108
109int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
110{
111	return __tps6586x_writes(to_i2c_client(dev), reg, len, val);
112}
113EXPORT_SYMBOL_GPL(tps6586x_writes);
114
115int tps6586x_read(struct device *dev, int reg, uint8_t *val)
116{
117	return __tps6586x_read(to_i2c_client(dev), reg, val);
118}
119EXPORT_SYMBOL_GPL(tps6586x_read);
120
121int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
122{
123	return __tps6586x_reads(to_i2c_client(dev), reg, len, val);
124}
125EXPORT_SYMBOL_GPL(tps6586x_reads);
126
127int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
128{
129	struct tps6586x *tps6586x = dev_get_drvdata(dev);
130	uint8_t reg_val;
131	int ret = 0;
132
133	mutex_lock(&tps6586x->lock);
134
135	ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
136	if (ret)
137		goto out;
138
139	if ((reg_val & bit_mask) == 0) {
140		reg_val |= bit_mask;
141		ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
142	}
143out:
144	mutex_unlock(&tps6586x->lock);
145	return ret;
146}
147EXPORT_SYMBOL_GPL(tps6586x_set_bits);
148
149int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
150{
151	struct tps6586x *tps6586x = dev_get_drvdata(dev);
152	uint8_t reg_val;
153	int ret = 0;
154
155	mutex_lock(&tps6586x->lock);
156
157	ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
158	if (ret)
159		goto out;
160
161	if (reg_val & bit_mask) {
162		reg_val &= ~bit_mask;
163		ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
164	}
165out:
166	mutex_unlock(&tps6586x->lock);
167	return ret;
168}
169EXPORT_SYMBOL_GPL(tps6586x_clr_bits);
170
171int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
172{
173	struct tps6586x *tps6586x = dev_get_drvdata(dev);
174	uint8_t reg_val;
175	int ret = 0;
176
177	mutex_lock(&tps6586x->lock);
178
179	ret = __tps6586x_read(tps6586x->client, reg, &reg_val);
180	if (ret)
181		goto out;
182
183	if ((reg_val & mask) != val) {
184		reg_val = (reg_val & ~mask) | val;
185		ret = __tps6586x_write(tps6586x->client, reg, reg_val);
186	}
187out:
188	mutex_unlock(&tps6586x->lock);
189	return ret;
190}
191EXPORT_SYMBOL_GPL(tps6586x_update);
192
193static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
194{
195	struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
196	uint8_t val;
197	int ret;
198
199	ret = __tps6586x_read(tps6586x->client, TPS6586X_GPIOSET2, &val);
200	if (ret)
201		return ret;
202
203	return !!(val & (1 << offset));
204}
205
206
207static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
208			      int value)
209{
210	struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
211
212	__tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
213			 value << offset);
214}
215
216static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
217				int value)
218{
219	struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
220	uint8_t val, mask;
221
222	tps6586x_gpio_set(gc, offset, value);
223
224	val = 0x1 << (offset * 2);
225	mask = 0x3 << (offset * 2);
226
227	return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
228}
229
230static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
231{
232	int ret;
233
234	if (!gpio_base)
235		return;
236
237	tps6586x->gpio.owner		= THIS_MODULE;
238	tps6586x->gpio.label		= tps6586x->client->name;
239	tps6586x->gpio.dev		= tps6586x->dev;
240	tps6586x->gpio.base		= gpio_base;
241	tps6586x->gpio.ngpio		= 4;
242	tps6586x->gpio.can_sleep	= 1;
243
244	tps6586x->gpio.direction_output	= tps6586x_gpio_output;
245	tps6586x->gpio.set		= tps6586x_gpio_set;
246	tps6586x->gpio.get		= tps6586x_gpio_get;
247
248	ret = gpiochip_add(&tps6586x->gpio);
249	if (ret)
250		dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
251}
252
253static int __remove_subdev(struct device *dev, void *unused)
254{
255	platform_device_unregister(to_platform_device(dev));
256	return 0;
257}
258
259static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
260{
261	return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
262}
263
264static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
265					  struct tps6586x_platform_data *pdata)
266{
267	struct tps6586x_subdev_info *subdev;
268	struct platform_device *pdev;
269	int i, ret = 0;
270
271	for (i = 0; i < pdata->num_subdevs; i++) {
272		subdev = &pdata->subdevs[i];
273
274		pdev = platform_device_alloc(subdev->name, subdev->id);
275
276		pdev->dev.parent = tps6586x->dev;
277		pdev->dev.platform_data = subdev->platform_data;
278
279		ret = platform_device_add(pdev);
280		if (ret)
281			goto failed;
282	}
283	return 0;
284
285failed:
286	tps6586x_remove_subdevs(tps6586x);
287	return ret;
288}
289
290static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
291					const struct i2c_device_id *id)
292{
293	struct tps6586x_platform_data *pdata = client->dev.platform_data;
294	struct tps6586x *tps6586x;
295	int ret;
296
297	if (!pdata) {
298		dev_err(&client->dev, "tps6586x requires platform data\n");
299		return -ENOTSUPP;
300	}
301
302	ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
303	if (ret < 0) {
304		dev_err(&client->dev, "Chip ID read failed: %d\n", ret);
305		return -EIO;
306	}
307
308	if (ret != TPS658621A_VERSIONCRC) {
309		dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
310		return -ENODEV;
311	}
312
313	tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
314	if (tps6586x == NULL)
315		return -ENOMEM;
316
317	tps6586x->client = client;
318	tps6586x->dev = &client->dev;
319	i2c_set_clientdata(client, tps6586x);
320
321	mutex_init(&tps6586x->lock);
322
323	ret = tps6586x_add_subdevs(tps6586x, pdata);
324	if (ret) {
325		dev_err(&client->dev, "add devices failed: %d\n", ret);
326		goto err_add_devs;
327	}
328
329	tps6586x_gpio_init(tps6586x, pdata->gpio_base);
330
331	return 0;
332
333err_add_devs:
334	kfree(tps6586x);
335	return ret;
336}
337
338static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
339{
340	return 0;
341}
342
343static const struct i2c_device_id tps6586x_id_table[] = {
344	{ "tps6586x", 0 },
345	{ },
346};
347MODULE_DEVICE_TABLE(i2c, tps6586x_id_table);
348
349static struct i2c_driver tps6586x_driver = {
350	.driver	= {
351		.name	= "tps6586x",
352		.owner	= THIS_MODULE,
353	},
354	.probe		= tps6586x_i2c_probe,
355	.remove		= __devexit_p(tps6586x_i2c_remove),
356	.id_table	= tps6586x_id_table,
357};
358
359static int __init tps6586x_init(void)
360{
361	return i2c_add_driver(&tps6586x_driver);
362}
363subsys_initcall(tps6586x_init);
364
365static void __exit tps6586x_exit(void)
366{
367	i2c_del_driver(&tps6586x_driver);
368}
369module_exit(tps6586x_exit);
370
371MODULE_DESCRIPTION("TPS6586X core driver");
372MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
373MODULE_LICENSE("GPL");
374