diff options
Diffstat (limited to 'drivers/power/smb349-charger.c')
-rw-r--r-- | drivers/power/smb349-charger.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c new file mode 100644 index 00000000000..1f230baadcb --- /dev/null +++ b/drivers/power/smb349-charger.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * drivers/power/smb349-charger.c | ||
3 | * | ||
4 | * Battery charger driver for smb349 from summit microelectronics | ||
5 | * | ||
6 | * Copyright (c) 2012, NVIDIA Corporation. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/power_supply.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/regulator/driver.h> | ||
32 | #include <linux/regulator/machine.h> | ||
33 | #include <linux/smb349-charger.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/gpio.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/irq.h> | ||
38 | #include <linux/usb/otg.h> | ||
39 | |||
40 | #define SMB349_CHARGE 0x00 | ||
41 | #define SMB349_CHRG_CRNTS 0x01 | ||
42 | #define SMB349_VRS_FUNC 0x02 | ||
43 | #define SMB349_FLOAT_VLTG 0x03 | ||
44 | #define SMB349_CHRG_CTRL 0x04 | ||
45 | #define SMB349_STAT_TIME_CTRL 0x05 | ||
46 | #define SMB349_PIN_CTRL 0x06 | ||
47 | #define SMB349_THERM_CTRL 0x07 | ||
48 | #define SMB349_CTRL_REG 0x09 | ||
49 | |||
50 | #define SMB349_OTG_TLIM_REG 0x0A | ||
51 | #define SMB349_HRD_SFT_TEMP 0x0B | ||
52 | #define SMB349_FAULT_INTR 0x0C | ||
53 | #define SMB349_STS_INTR_1 0x0D | ||
54 | #define SMB349_SYSOK_USB3 0x0E | ||
55 | #define SMB349_IN_CLTG_DET 0x10 | ||
56 | #define SMB349_STS_INTR_2 0x11 | ||
57 | |||
58 | #define SMB349_CMD_REG 0x30 | ||
59 | #define SMB349_CMD_REG_B 0x31 | ||
60 | #define SMB349_CMD_REG_c 0x33 | ||
61 | |||
62 | #define SMB349_INTR_STS_A 0x35 | ||
63 | #define SMB349_INTR_STS_B 0x36 | ||
64 | #define SMB349_INTR_STS_C 0x37 | ||
65 | #define SMB349_INTR_STS_D 0x38 | ||
66 | #define SMB349_INTR_STS_E 0x39 | ||
67 | #define SMB349_INTR_STS_F 0x3A | ||
68 | |||
69 | #define SMB349_STS_REG_A 0x3B | ||
70 | #define SMB349_STS_REG_B 0x3C | ||
71 | #define SMB349_STS_REG_C 0x3D | ||
72 | #define SMB349_STS_REG_D 0x3E | ||
73 | #define SMB349_STS_REG_E 0x3F | ||
74 | |||
75 | #define SMB349_ENABLE_WRITE 1 | ||
76 | #define SMB349_DISABLE_WRITE 0 | ||
77 | #define ENABLE_WRT_ACCESS 0x80 | ||
78 | #define THERM_CTRL 0x10 | ||
79 | #define BATTERY_MISSING 0x10 | ||
80 | #define CHARGING 0x06 | ||
81 | #define DEDICATED_CHARGER 0x04 | ||
82 | #define CHRG_DOWNSTRM_PORT 0x08 | ||
83 | #define ENABLE_CHARGE 0x02 | ||
84 | |||
85 | static struct smb349_charger *charger; | ||
86 | static int smb349_configure_charger(struct i2c_client *client, int value); | ||
87 | static int smb349_configure_interrupts(struct i2c_client *client); | ||
88 | |||
89 | static int smb349_read(struct i2c_client *client, int reg) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | ret = i2c_smbus_read_byte_data(client, reg); | ||
94 | |||
95 | if (ret < 0) | ||
96 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static int smb349_write(struct i2c_client *client, int reg, u8 value) | ||
102 | { | ||
103 | int ret; | ||
104 | |||
105 | ret = i2c_smbus_write_byte_data(client, reg, value); | ||
106 | |||
107 | if (ret < 0) | ||
108 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
109 | |||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static int smb349_update_reg(struct i2c_client *client, int reg, u8 value) | ||
114 | { | ||
115 | int ret, retval; | ||
116 | |||
117 | retval = smb349_read(client, reg); | ||
118 | if (retval < 0) { | ||
119 | dev_err(&client->dev, "%s: err %d\n", __func__, retval); | ||
120 | return retval; | ||
121 | } | ||
122 | |||
123 | ret = smb349_write(client, reg, retval | value); | ||
124 | if (ret < 0) { | ||
125 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | int smb349_volatile_writes(struct i2c_client *client, uint8_t value) | ||
133 | { | ||
134 | int ret = 0; | ||
135 | |||
136 | if (value == SMB349_ENABLE_WRITE) { | ||
137 | /* Enable volatile write to config registers */ | ||
138 | ret = smb349_update_reg(client, SMB349_CMD_REG, | ||
139 | ENABLE_WRT_ACCESS); | ||
140 | if (ret < 0) { | ||
141 | dev_err(&client->dev, "%s(): Failed in writing" | ||
142 | "register 0x%02x\n", __func__, SMB349_CMD_REG); | ||
143 | return ret; | ||
144 | } | ||
145 | } else { | ||
146 | ret = smb349_read(client, SMB349_CMD_REG); | ||
147 | if (ret < 0) { | ||
148 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | ret = smb349_write(client, SMB349_CMD_REG, ret & (~(1<<7))); | ||
153 | if (ret < 0) { | ||
154 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
155 | return ret; | ||
156 | } | ||
157 | } | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | static void smb349_clear_interrupts(struct i2c_client *client) | ||
162 | { | ||
163 | uint8_t val, buf[6]; | ||
164 | |||
165 | val = i2c_smbus_read_i2c_block_data(client, SMB349_INTR_STS_A, 6, buf); | ||
166 | if (val < 0) | ||
167 | dev_err(&client->dev, "%s(): Failed in clearing interrupts\n", | ||
168 | __func__); | ||
169 | } | ||
170 | |||
171 | static int smb349_configure_otg(struct i2c_client *client, int enable) | ||
172 | { | ||
173 | int ret = 0; | ||
174 | |||
175 | /*Enable volatile writes to registers*/ | ||
176 | ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE); | ||
177 | if (ret < 0) { | ||
178 | dev_err(&client->dev, "%s error in configuring otg..\n", | ||
179 | __func__); | ||
180 | goto error; | ||
181 | } | ||
182 | |||
183 | if (enable) { | ||
184 | /* Configure PGOOD to be active low */ | ||
185 | ret = smb349_read(client, SMB349_SYSOK_USB3); | ||
186 | if (ret < 0) { | ||
187 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
188 | goto error; | ||
189 | } | ||
190 | |||
191 | ret = smb349_write(client, SMB349_SYSOK_USB3, (ret & (~(1)))); | ||
192 | if (ret < 0) { | ||
193 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
194 | goto error; | ||
195 | } | ||
196 | |||
197 | /* Enable OTG */ | ||
198 | ret = smb349_update_reg(client, SMB349_CMD_REG, 0x10); | ||
199 | if (ret < 0) { | ||
200 | dev_err(&client->dev, "%s: Failed in writing register" | ||
201 | "0x%02x\n", __func__, SMB349_CMD_REG); | ||
202 | goto error; | ||
203 | } | ||
204 | } else { | ||
205 | /* Disable OTG */ | ||
206 | ret = smb349_read(client, SMB349_CMD_REG); | ||
207 | if (ret < 0) { | ||
208 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
209 | goto error; | ||
210 | } | ||
211 | |||
212 | ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<4)))); | ||
213 | if (ret < 0) { | ||
214 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
215 | goto error; | ||
216 | } | ||
217 | |||
218 | /* Configure PGOOD to be active high */ | ||
219 | ret = smb349_update_reg(client, SMB349_SYSOK_USB3, 0x01); | ||
220 | if (ret < 0) { | ||
221 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
222 | goto error; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /* Disable volatile writes to registers */ | ||
227 | ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE); | ||
228 | if (ret < 0) | ||
229 | dev_err(&client->dev, "%s error in configuring OTG..\n", | ||
230 | __func__); | ||
231 | error: | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int smb349_configure_charger(struct i2c_client *client, int value) | ||
236 | { | ||
237 | int ret = 0; | ||
238 | |||
239 | /* Enable volatile writes to registers */ | ||
240 | ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE); | ||
241 | if (ret < 0) { | ||
242 | dev_err(&client->dev, "%s() error in configuring charger..\n", | ||
243 | __func__); | ||
244 | goto error; | ||
245 | } | ||
246 | |||
247 | if (value) { | ||
248 | /* Enable charging */ | ||
249 | ret = smb349_update_reg(client, SMB349_CMD_REG, ENABLE_CHARGE); | ||
250 | if (ret < 0) { | ||
251 | dev_err(&client->dev, "%s(): Failed in writing register" | ||
252 | "0x%02x\n", __func__, SMB349_CMD_REG); | ||
253 | goto error; | ||
254 | } | ||
255 | |||
256 | /* Configure THERM ctrl */ | ||
257 | ret = smb349_update_reg(client, SMB349_THERM_CTRL, THERM_CTRL); | ||
258 | if (ret < 0) { | ||
259 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
260 | goto error; | ||
261 | } | ||
262 | } else { | ||
263 | ret = smb349_read(client, SMB349_CMD_REG); | ||
264 | if (ret < 0) { | ||
265 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
266 | goto error; | ||
267 | } | ||
268 | |||
269 | ret = smb349_write(client, SMB349_CMD_REG, (ret & (~(1<<1)))); | ||
270 | if (ret < 0) { | ||
271 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
272 | goto error; | ||
273 | } | ||
274 | } | ||
275 | /* Disable volatile writes to registers */ | ||
276 | ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE); | ||
277 | if (ret < 0) { | ||
278 | dev_err(&client->dev, "%s() error in configuring charger..\n", | ||
279 | __func__); | ||
280 | goto error; | ||
281 | } | ||
282 | error: | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static irqreturn_t smb349_status_isr(int irq, void *dev_id) | ||
287 | { | ||
288 | struct i2c_client *client = charger->client; | ||
289 | int ret, val; | ||
290 | |||
291 | val = smb349_read(client, SMB349_STS_REG_D); | ||
292 | if (val < 0) { | ||
293 | dev_err(&client->dev, "%s(): Failed in reading register" | ||
294 | "0x%02x\n", __func__, SMB349_STS_REG_D); | ||
295 | goto irq_error; | ||
296 | } else if (val != 0) { | ||
297 | if (val & DEDICATED_CHARGER) | ||
298 | charger->chrg_type = AC; | ||
299 | else if (val & CHRG_DOWNSTRM_PORT) | ||
300 | charger->chrg_type = USB; | ||
301 | |||
302 | /* configure charger */ | ||
303 | ret = smb349_configure_charger(client, 1); | ||
304 | if (ret < 0) { | ||
305 | dev_err(&client->dev, "%s() error in configuring" | ||
306 | "charger..\n", __func__); | ||
307 | goto irq_error; | ||
308 | } | ||
309 | |||
310 | charger->state = progress; | ||
311 | } else { | ||
312 | charger->state = stopped; | ||
313 | |||
314 | /* Disable charger */ | ||
315 | ret = smb349_configure_charger(client, 0); | ||
316 | if (ret < 0) { | ||
317 | dev_err(&client->dev, "%s() error in configuring" | ||
318 | "charger..\n", __func__); | ||
319 | goto irq_error; | ||
320 | } | ||
321 | |||
322 | ret = smb349_configure_interrupts(client); | ||
323 | if (ret < 0) { | ||
324 | dev_err(&client->dev, "%s() error in configuring" | ||
325 | "charger..\n", __func__); | ||
326 | goto irq_error; | ||
327 | } | ||
328 | |||
329 | } | ||
330 | |||
331 | if (charger->charger_cb) | ||
332 | charger->charger_cb(charger->state, charger->chrg_type, | ||
333 | charger->charger_cb_data); | ||
334 | irq_error: | ||
335 | smb349_clear_interrupts(client); | ||
336 | return IRQ_HANDLED; | ||
337 | } | ||
338 | |||
339 | int update_charger_status(void) | ||
340 | { | ||
341 | struct i2c_client *client = charger->client; | ||
342 | int ret, val; | ||
343 | |||
344 | val = smb349_read(client, SMB349_STS_REG_D); | ||
345 | if (val < 0) { | ||
346 | dev_err(&client->dev, "%s(): Failed in reading register" | ||
347 | "0x%02x\n", __func__, SMB349_STS_REG_D); | ||
348 | goto val_error; | ||
349 | } else if (val != 0) { | ||
350 | if (val & DEDICATED_CHARGER) | ||
351 | charger->chrg_type = AC; | ||
352 | else if (val & CHRG_DOWNSTRM_PORT) | ||
353 | charger->chrg_type = USB; | ||
354 | |||
355 | /* configure charger */ | ||
356 | ret = smb349_configure_charger(client, 1); | ||
357 | if (ret < 0) { | ||
358 | dev_err(&client->dev, "%s() error in configuring" | ||
359 | "charger..\n", __func__); | ||
360 | goto ret_error; | ||
361 | } | ||
362 | |||
363 | charger->state = progress; | ||
364 | } else { | ||
365 | charger->state = stopped; | ||
366 | |||
367 | /* Disable charger */ | ||
368 | ret = smb349_configure_charger(client, 0); | ||
369 | if (ret < 0) { | ||
370 | dev_err(&client->dev, "%s() error in configuring" | ||
371 | "charger..\n", __func__); | ||
372 | goto ret_error; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | if (charger->charger_cb) | ||
377 | charger->charger_cb(charger->state, charger->chrg_type, | ||
378 | charger->charger_cb_data); | ||
379 | return 0; | ||
380 | val_error: | ||
381 | return val; | ||
382 | ret_error: | ||
383 | return ret; | ||
384 | } | ||
385 | EXPORT_SYMBOL_GPL(update_charger_status); | ||
386 | |||
387 | int register_callback(charging_callback_t cb, void *args) | ||
388 | { | ||
389 | struct smb349_charger *charger_data = charger; | ||
390 | if (!charger_data) | ||
391 | return -ENODEV; | ||
392 | |||
393 | charger_data->charger_cb = cb; | ||
394 | charger_data->charger_cb_data = args; | ||
395 | return 0; | ||
396 | } | ||
397 | EXPORT_SYMBOL_GPL(register_callback); | ||
398 | |||
399 | int smb349_battery_online(void) | ||
400 | { | ||
401 | int val; | ||
402 | struct i2c_client *client = charger->client; | ||
403 | |||
404 | val = smb349_read(charger->client, SMB349_INTR_STS_B); | ||
405 | if (val < 0) { | ||
406 | dev_err(&client->dev, "%s(): Failed in reading register" | ||
407 | "0x%02x\n", __func__, SMB349_INTR_STS_B); | ||
408 | return val; | ||
409 | } | ||
410 | if (val & BATTERY_MISSING) | ||
411 | return 0; | ||
412 | else | ||
413 | return 1; | ||
414 | } | ||
415 | |||
416 | static int smb349_configure_interrupts(struct i2c_client *client) | ||
417 | { | ||
418 | int ret = 0; | ||
419 | |||
420 | /* Enable volatile writes to registers */ | ||
421 | ret = smb349_volatile_writes(client, SMB349_ENABLE_WRITE); | ||
422 | if (ret < 0) { | ||
423 | dev_err(&client->dev, "%s() error in configuring charger..\n", | ||
424 | __func__); | ||
425 | goto error; | ||
426 | } | ||
427 | |||
428 | ret = smb349_update_reg(client, SMB349_FAULT_INTR, 0xff); | ||
429 | if (ret < 0) { | ||
430 | dev_err(&client->dev, "%s(): Failed in writing register" | ||
431 | "0x%02x\n", __func__, SMB349_CMD_REG); | ||
432 | goto error; | ||
433 | } | ||
434 | |||
435 | ret = smb349_update_reg(client, SMB349_STS_INTR_1, 0xff); | ||
436 | if (ret < 0) { | ||
437 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | ||
438 | goto error; | ||
439 | } | ||
440 | |||
441 | /* Disable volatile writes to registers */ | ||
442 | ret = smb349_volatile_writes(client, SMB349_DISABLE_WRITE); | ||
443 | if (ret < 0) { | ||
444 | dev_err(&client->dev, "%s() error in configuring charger..\n", | ||
445 | __func__); | ||
446 | goto error; | ||
447 | } | ||
448 | |||
449 | error: | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | static void smb349_otg_status(enum usb_otg_state to, enum usb_otg_state from, void *data) | ||
454 | { | ||
455 | struct i2c_client *client = charger->client; | ||
456 | int ret; | ||
457 | |||
458 | if ((from == OTG_STATE_A_SUSPEND) && (to == OTG_STATE_A_HOST)) { | ||
459 | |||
460 | /* configure charger */ | ||
461 | ret = smb349_configure_charger(client, 0); | ||
462 | if (ret < 0) | ||
463 | dev_err(&client->dev, "%s() error in configuring" | ||
464 | "otg..\n", __func__); | ||
465 | |||
466 | /* ENABLE OTG */ | ||
467 | ret = smb349_configure_otg(client, 1); | ||
468 | if (ret < 0) | ||
469 | dev_err(&client->dev, "%s() error in configuring" | ||
470 | "otg..\n", __func__); | ||
471 | |||
472 | } else if ((from == OTG_STATE_A_HOST) && (to == OTG_STATE_A_SUSPEND)) { | ||
473 | |||
474 | /* Disable OTG */ | ||
475 | ret = smb349_configure_otg(client, 0); | ||
476 | if (ret < 0) | ||
477 | dev_err(&client->dev, "%s() error in configuring" | ||
478 | "otg..\n", __func__); | ||
479 | |||
480 | /* configure charger */ | ||
481 | ret = smb349_configure_charger(client, 1); | ||
482 | if (ret < 0) | ||
483 | dev_err(&client->dev, "%s() error in configuring" | ||
484 | "otg..\n", __func__); | ||
485 | |||
486 | ret = smb349_configure_interrupts(client); | ||
487 | if (ret < 0) | ||
488 | dev_err(&client->dev, "%s() error in configuring" | ||
489 | "otg..\n", __func__); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | static int __devinit smb349_probe(struct i2c_client *client, | ||
494 | const struct i2c_device_id *id) | ||
495 | { | ||
496 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
497 | int ret, irq_num; | ||
498 | |||
499 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | ||
500 | return -EIO; | ||
501 | |||
502 | charger = kzalloc(sizeof(*charger), GFP_KERNEL); | ||
503 | if (!charger) | ||
504 | return -ENOMEM; | ||
505 | |||
506 | charger->client = client; | ||
507 | charger->dev = &client->dev; | ||
508 | i2c_set_clientdata(client, charger); | ||
509 | |||
510 | /* Check battery presence */ | ||
511 | if (!smb349_battery_online()) { | ||
512 | dev_err(&client->dev, "%s() No Battery present, exiting..\n", | ||
513 | __func__); | ||
514 | ret = -ENODEV; | ||
515 | goto error; | ||
516 | } | ||
517 | |||
518 | ret = register_otg_callback(smb349_otg_status, charger); | ||
519 | if (ret < 0) | ||
520 | goto error; | ||
521 | |||
522 | ret = smb349_configure_charger(client, 1); | ||
523 | if (ret < 0) | ||
524 | return ret; | ||
525 | |||
526 | ret = smb349_configure_interrupts(client); | ||
527 | if (ret < 0) { | ||
528 | dev_err(&client->dev, "%s() error in configuring charger..\n", | ||
529 | __func__); | ||
530 | goto error; | ||
531 | } | ||
532 | |||
533 | irq_num = gpio_to_irq(client->irq); | ||
534 | ret = request_threaded_irq(irq_num, | ||
535 | NULL, smb349_status_isr, IRQ_TYPE_EDGE_FALLING, | ||
536 | "smb349", charger); | ||
537 | if (ret) { | ||
538 | dev_err(&client->dev, "%s(): Failed in requesting isr\n", | ||
539 | __func__); | ||
540 | goto error; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | error: | ||
545 | kfree(charger); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | static int __devexit smb349_remove(struct i2c_client *client) | ||
550 | { | ||
551 | struct smb349_charger *charger = i2c_get_clientdata(client); | ||
552 | |||
553 | free_irq(gpio_to_irq(client->irq), charger); | ||
554 | kfree(charger); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static const struct i2c_device_id smb349_id[] = { | ||
560 | { "smb349", 0 }, | ||
561 | { } | ||
562 | }; | ||
563 | MODULE_DEVICE_TABLE(i2c, smb349_id); | ||
564 | |||
565 | static struct i2c_driver smb349_i2c_driver = { | ||
566 | .driver = { | ||
567 | .name = "smb349", | ||
568 | }, | ||
569 | .probe = smb349_probe, | ||
570 | .remove = __devexit_p(smb349_remove), | ||
571 | .id_table = smb349_id, | ||
572 | }; | ||
573 | |||
574 | static int __init smb349_init(void) | ||
575 | { | ||
576 | return i2c_add_driver(&smb349_i2c_driver); | ||
577 | } | ||
578 | module_init(smb349_init); | ||
579 | |||
580 | static void __exit smb349_exit(void) | ||
581 | { | ||
582 | i2c_del_driver(&smb349_i2c_driver); | ||
583 | } | ||
584 | module_exit(smb349_exit); | ||
585 | |||
586 | MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>"); | ||
587 | MODULE_DESCRIPTION("SMB349 Battery-Charger"); | ||
588 | MODULE_LICENSE("GPL"); | ||