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