]>
Commit | Line | Data |
---|---|---|
a1bb73d7 DK |
1 | /* |
2 | * fsa9480.c - FSA9480 micro USB switch device driver | |
3 | * | |
4 | * Copyright (C) 2010 Samsung Electronics | |
5 | * Minkyu Kang <[email protected]> | |
6 | * Wonguk Jeong <[email protected]> | |
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 version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/err.h> | |
16 | #include <linux/i2c.h> | |
17 | #include <linux/platform_data/fsa9480.h> | |
18 | #include <linux/irq.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/workqueue.h> | |
21 | #include <linux/platform_device.h> | |
22 | #include <linux/slab.h> | |
23 | #include <linux/pm_runtime.h> | |
24 | ||
25 | /* FSA9480 I2C registers */ | |
26 | #define FSA9480_REG_DEVID 0x01 | |
27 | #define FSA9480_REG_CTRL 0x02 | |
28 | #define FSA9480_REG_INT1 0x03 | |
29 | #define FSA9480_REG_INT2 0x04 | |
30 | #define FSA9480_REG_INT1_MASK 0x05 | |
31 | #define FSA9480_REG_INT2_MASK 0x06 | |
32 | #define FSA9480_REG_ADC 0x07 | |
33 | #define FSA9480_REG_TIMING1 0x08 | |
34 | #define FSA9480_REG_TIMING2 0x09 | |
35 | #define FSA9480_REG_DEV_T1 0x0a | |
36 | #define FSA9480_REG_DEV_T2 0x0b | |
37 | #define FSA9480_REG_BTN1 0x0c | |
38 | #define FSA9480_REG_BTN2 0x0d | |
39 | #define FSA9480_REG_CK 0x0e | |
40 | #define FSA9480_REG_CK_INT1 0x0f | |
41 | #define FSA9480_REG_CK_INT2 0x10 | |
42 | #define FSA9480_REG_CK_INTMASK1 0x11 | |
43 | #define FSA9480_REG_CK_INTMASK2 0x12 | |
44 | #define FSA9480_REG_MANSW1 0x13 | |
45 | #define FSA9480_REG_MANSW2 0x14 | |
46 | ||
47 | /* Control */ | |
48 | #define CON_SWITCH_OPEN (1 << 4) | |
49 | #define CON_RAW_DATA (1 << 3) | |
50 | #define CON_MANUAL_SW (1 << 2) | |
51 | #define CON_WAIT (1 << 1) | |
52 | #define CON_INT_MASK (1 << 0) | |
53 | #define CON_MASK (CON_SWITCH_OPEN | CON_RAW_DATA | \ | |
54 | CON_MANUAL_SW | CON_WAIT) | |
55 | ||
56 | /* Device Type 1 */ | |
57 | #define DEV_USB_OTG (1 << 7) | |
58 | #define DEV_DEDICATED_CHG (1 << 6) | |
59 | #define DEV_USB_CHG (1 << 5) | |
60 | #define DEV_CAR_KIT (1 << 4) | |
61 | #define DEV_UART (1 << 3) | |
62 | #define DEV_USB (1 << 2) | |
63 | #define DEV_AUDIO_2 (1 << 1) | |
64 | #define DEV_AUDIO_1 (1 << 0) | |
65 | ||
66 | #define DEV_T1_USB_MASK (DEV_USB_OTG | DEV_USB) | |
67 | #define DEV_T1_UART_MASK (DEV_UART) | |
68 | #define DEV_T1_CHARGER_MASK (DEV_DEDICATED_CHG | DEV_USB_CHG) | |
69 | ||
70 | /* Device Type 2 */ | |
71 | #define DEV_AV (1 << 6) | |
72 | #define DEV_TTY (1 << 5) | |
73 | #define DEV_PPD (1 << 4) | |
74 | #define DEV_JIG_UART_OFF (1 << 3) | |
75 | #define DEV_JIG_UART_ON (1 << 2) | |
76 | #define DEV_JIG_USB_OFF (1 << 1) | |
77 | #define DEV_JIG_USB_ON (1 << 0) | |
78 | ||
79 | #define DEV_T2_USB_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON) | |
80 | #define DEV_T2_UART_MASK (DEV_JIG_UART_OFF | DEV_JIG_UART_ON) | |
81 | #define DEV_T2_JIG_MASK (DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \ | |
82 | DEV_JIG_UART_OFF | DEV_JIG_UART_ON) | |
83 | ||
84 | /* | |
85 | * Manual Switch | |
86 | * D- [7:5] / D+ [4:2] | |
87 | * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO | |
88 | */ | |
89 | #define SW_VAUDIO ((4 << 5) | (4 << 2)) | |
90 | #define SW_UART ((3 << 5) | (3 << 2)) | |
91 | #define SW_AUDIO ((2 << 5) | (2 << 2)) | |
92 | #define SW_DHOST ((1 << 5) | (1 << 2)) | |
93 | #define SW_AUTO ((0 << 5) | (0 << 2)) | |
94 | ||
95 | /* Interrupt 1 */ | |
96 | #define INT_DETACH (1 << 1) | |
97 | #define INT_ATTACH (1 << 0) | |
98 | ||
99 | struct fsa9480_usbsw { | |
100 | struct i2c_client *client; | |
101 | struct fsa9480_platform_data *pdata; | |
102 | int dev1; | |
103 | int dev2; | |
104 | int mansw; | |
105 | }; | |
106 | ||
107 | static struct fsa9480_usbsw *chip; | |
108 | ||
109 | static int fsa9480_write_reg(struct i2c_client *client, | |
110 | int reg, int value) | |
111 | { | |
112 | int ret; | |
113 | ||
114 | ret = i2c_smbus_write_byte_data(client, reg, value); | |
115 | ||
116 | if (ret < 0) | |
117 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | |
118 | ||
119 | return ret; | |
120 | } | |
121 | ||
122 | static int fsa9480_read_reg(struct i2c_client *client, int reg) | |
123 | { | |
124 | int ret; | |
125 | ||
126 | ret = i2c_smbus_read_byte_data(client, reg); | |
127 | ||
128 | if (ret < 0) | |
129 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | |
130 | ||
131 | return ret; | |
132 | } | |
133 | ||
134 | static int fsa9480_read_irq(struct i2c_client *client, int *value) | |
135 | { | |
136 | int ret; | |
137 | ||
138 | ret = i2c_smbus_read_i2c_block_data(client, | |
139 | FSA9480_REG_INT1, 2, (u8 *)value); | |
140 | *value &= 0xffff; | |
141 | ||
142 | if (ret < 0) | |
143 | dev_err(&client->dev, "%s: err %d\n", __func__, ret); | |
144 | ||
145 | return ret; | |
146 | } | |
147 | ||
148 | static void fsa9480_set_switch(const char *buf) | |
149 | { | |
150 | struct fsa9480_usbsw *usbsw = chip; | |
151 | struct i2c_client *client = usbsw->client; | |
152 | unsigned int value; | |
153 | unsigned int path = 0; | |
154 | ||
155 | value = fsa9480_read_reg(client, FSA9480_REG_CTRL); | |
156 | ||
157 | if (!strncmp(buf, "VAUDIO", 6)) { | |
158 | path = SW_VAUDIO; | |
159 | value &= ~CON_MANUAL_SW; | |
160 | } else if (!strncmp(buf, "UART", 4)) { | |
161 | path = SW_UART; | |
162 | value &= ~CON_MANUAL_SW; | |
163 | } else if (!strncmp(buf, "AUDIO", 5)) { | |
164 | path = SW_AUDIO; | |
165 | value &= ~CON_MANUAL_SW; | |
166 | } else if (!strncmp(buf, "DHOST", 5)) { | |
167 | path = SW_DHOST; | |
168 | value &= ~CON_MANUAL_SW; | |
169 | } else if (!strncmp(buf, "AUTO", 4)) { | |
170 | path = SW_AUTO; | |
171 | value |= CON_MANUAL_SW; | |
172 | } else { | |
173 | printk(KERN_ERR "Wrong command\n"); | |
174 | return; | |
175 | } | |
176 | ||
177 | usbsw->mansw = path; | |
178 | fsa9480_write_reg(client, FSA9480_REG_MANSW1, path); | |
179 | fsa9480_write_reg(client, FSA9480_REG_CTRL, value); | |
180 | } | |
181 | ||
182 | static ssize_t fsa9480_get_switch(char *buf) | |
183 | { | |
184 | struct fsa9480_usbsw *usbsw = chip; | |
185 | struct i2c_client *client = usbsw->client; | |
186 | unsigned int value; | |
187 | ||
188 | value = fsa9480_read_reg(client, FSA9480_REG_MANSW1); | |
189 | ||
190 | if (value == SW_VAUDIO) | |
191 | return sprintf(buf, "VAUDIO\n"); | |
192 | else if (value == SW_UART) | |
193 | return sprintf(buf, "UART\n"); | |
194 | else if (value == SW_AUDIO) | |
195 | return sprintf(buf, "AUDIO\n"); | |
196 | else if (value == SW_DHOST) | |
197 | return sprintf(buf, "DHOST\n"); | |
198 | else if (value == SW_AUTO) | |
199 | return sprintf(buf, "AUTO\n"); | |
200 | else | |
201 | return sprintf(buf, "%x", value); | |
202 | } | |
203 | ||
204 | static ssize_t fsa9480_show_device(struct device *dev, | |
205 | struct device_attribute *attr, | |
206 | char *buf) | |
207 | { | |
208 | struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev); | |
209 | struct i2c_client *client = usbsw->client; | |
210 | int dev1, dev2; | |
211 | ||
212 | dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | |
213 | dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | |
214 | ||
215 | if (!dev1 && !dev2) | |
216 | return sprintf(buf, "NONE\n"); | |
217 | ||
218 | /* USB */ | |
219 | if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK) | |
220 | return sprintf(buf, "USB\n"); | |
221 | ||
222 | /* UART */ | |
223 | if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK) | |
224 | return sprintf(buf, "UART\n"); | |
225 | ||
226 | /* CHARGER */ | |
227 | if (dev1 & DEV_T1_CHARGER_MASK) | |
228 | return sprintf(buf, "CHARGER\n"); | |
229 | ||
230 | /* JIG */ | |
231 | if (dev2 & DEV_T2_JIG_MASK) | |
232 | return sprintf(buf, "JIG\n"); | |
233 | ||
234 | return sprintf(buf, "UNKNOWN\n"); | |
235 | } | |
236 | ||
237 | static ssize_t fsa9480_show_manualsw(struct device *dev, | |
238 | struct device_attribute *attr, char *buf) | |
239 | { | |
240 | return fsa9480_get_switch(buf); | |
241 | ||
242 | } | |
243 | ||
244 | static ssize_t fsa9480_set_manualsw(struct device *dev, | |
245 | struct device_attribute *attr, | |
246 | const char *buf, size_t count) | |
247 | { | |
248 | fsa9480_set_switch(buf); | |
249 | ||
250 | return count; | |
251 | } | |
252 | ||
253 | static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL); | |
254 | static DEVICE_ATTR(switch, S_IRUGO | S_IWUSR, | |
255 | fsa9480_show_manualsw, fsa9480_set_manualsw); | |
256 | ||
257 | static struct attribute *fsa9480_attributes[] = { | |
258 | &dev_attr_device.attr, | |
259 | &dev_attr_switch.attr, | |
260 | NULL | |
261 | }; | |
262 | ||
263 | static const struct attribute_group fsa9480_group = { | |
264 | .attrs = fsa9480_attributes, | |
265 | }; | |
266 | ||
267 | static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr) | |
268 | { | |
269 | int val1, val2, ctrl; | |
270 | struct fsa9480_platform_data *pdata = usbsw->pdata; | |
271 | struct i2c_client *client = usbsw->client; | |
272 | ||
273 | val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | |
274 | val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | |
275 | ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL); | |
276 | ||
277 | dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n", | |
278 | intr, val1, val2); | |
279 | ||
280 | if (!intr) | |
281 | goto out; | |
282 | ||
283 | if (intr & INT_ATTACH) { /* Attached */ | |
284 | /* USB */ | |
285 | if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) { | |
286 | if (pdata->usb_cb) | |
287 | pdata->usb_cb(FSA9480_ATTACHED); | |
288 | ||
289 | if (usbsw->mansw) { | |
290 | fsa9480_write_reg(client, | |
291 | FSA9480_REG_MANSW1, usbsw->mansw); | |
292 | } | |
293 | } | |
294 | ||
295 | /* UART */ | |
296 | if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) { | |
297 | if (pdata->uart_cb) | |
298 | pdata->uart_cb(FSA9480_ATTACHED); | |
299 | ||
300 | if (!(ctrl & CON_MANUAL_SW)) { | |
301 | fsa9480_write_reg(client, | |
302 | FSA9480_REG_MANSW1, SW_UART); | |
303 | } | |
304 | } | |
305 | ||
306 | /* CHARGER */ | |
307 | if (val1 & DEV_T1_CHARGER_MASK) { | |
308 | if (pdata->charger_cb) | |
309 | pdata->charger_cb(FSA9480_ATTACHED); | |
310 | } | |
311 | ||
312 | /* JIG */ | |
313 | if (val2 & DEV_T2_JIG_MASK) { | |
314 | if (pdata->jig_cb) | |
315 | pdata->jig_cb(FSA9480_ATTACHED); | |
316 | } | |
317 | } else if (intr & INT_DETACH) { /* Detached */ | |
318 | /* USB */ | |
319 | if (usbsw->dev1 & DEV_T1_USB_MASK || | |
320 | usbsw->dev2 & DEV_T2_USB_MASK) { | |
321 | if (pdata->usb_cb) | |
322 | pdata->usb_cb(FSA9480_DETACHED); | |
323 | } | |
324 | ||
325 | /* UART */ | |
326 | if (usbsw->dev1 & DEV_T1_UART_MASK || | |
327 | usbsw->dev2 & DEV_T2_UART_MASK) { | |
328 | if (pdata->uart_cb) | |
329 | pdata->uart_cb(FSA9480_DETACHED); | |
330 | } | |
331 | ||
332 | /* CHARGER */ | |
333 | if (usbsw->dev1 & DEV_T1_CHARGER_MASK) { | |
334 | if (pdata->charger_cb) | |
335 | pdata->charger_cb(FSA9480_DETACHED); | |
336 | } | |
337 | ||
338 | /* JIG */ | |
339 | if (usbsw->dev2 & DEV_T2_JIG_MASK) { | |
340 | if (pdata->jig_cb) | |
341 | pdata->jig_cb(FSA9480_DETACHED); | |
342 | } | |
343 | } | |
344 | ||
345 | usbsw->dev1 = val1; | |
346 | usbsw->dev2 = val2; | |
347 | ||
348 | out: | |
349 | ctrl &= ~CON_INT_MASK; | |
350 | fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); | |
351 | } | |
352 | ||
353 | static irqreturn_t fsa9480_irq_handler(int irq, void *data) | |
354 | { | |
355 | struct fsa9480_usbsw *usbsw = data; | |
356 | struct i2c_client *client = usbsw->client; | |
357 | int intr; | |
358 | ||
359 | /* clear interrupt */ | |
360 | fsa9480_read_irq(client, &intr); | |
361 | ||
362 | /* device detection */ | |
363 | fsa9480_detect_dev(usbsw, intr); | |
364 | ||
365 | return IRQ_HANDLED; | |
366 | } | |
367 | ||
368 | static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) | |
369 | { | |
370 | struct fsa9480_platform_data *pdata = usbsw->pdata; | |
371 | struct i2c_client *client = usbsw->client; | |
372 | int ret; | |
373 | int intr; | |
374 | unsigned int ctrl = CON_MASK; | |
375 | ||
376 | /* clear interrupt */ | |
377 | fsa9480_read_irq(client, &intr); | |
378 | ||
379 | /* unmask interrupt (attach/detach only) */ | |
380 | fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc); | |
381 | fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f); | |
382 | ||
383 | usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1); | |
384 | ||
385 | if (usbsw->mansw) | |
386 | ctrl &= ~CON_MANUAL_SW; /* Manual Switching Mode */ | |
387 | ||
388 | fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl); | |
389 | ||
390 | if (pdata && pdata->cfg_gpio) | |
391 | pdata->cfg_gpio(); | |
392 | ||
393 | if (client->irq) { | |
394 | ret = request_threaded_irq(client->irq, NULL, | |
395 | fsa9480_irq_handler, | |
396 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | |
397 | "fsa9480 micro USB", usbsw); | |
398 | if (ret) { | |
8faaaead | 399 | dev_err(&client->dev, "failed to request IRQ\n"); |
a1bb73d7 DK |
400 | return ret; |
401 | } | |
402 | ||
e58a0f89 JC |
403 | if (pdata) |
404 | device_init_wakeup(&client->dev, pdata->wakeup); | |
a1bb73d7 DK |
405 | } |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
80c8ae28 | 410 | static int fsa9480_probe(struct i2c_client *client, |
a1bb73d7 DK |
411 | const struct i2c_device_id *id) |
412 | { | |
413 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | |
414 | struct fsa9480_usbsw *usbsw; | |
415 | int ret = 0; | |
416 | ||
417 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
418 | return -EIO; | |
419 | ||
420 | usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL); | |
421 | if (!usbsw) { | |
422 | dev_err(&client->dev, "failed to allocate driver data\n"); | |
423 | return -ENOMEM; | |
424 | } | |
425 | ||
426 | usbsw->client = client; | |
427 | usbsw->pdata = client->dev.platform_data; | |
428 | ||
429 | chip = usbsw; | |
430 | ||
431 | i2c_set_clientdata(client, usbsw); | |
432 | ||
433 | ret = fsa9480_irq_init(usbsw); | |
434 | if (ret) | |
435 | goto fail1; | |
436 | ||
437 | ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group); | |
438 | if (ret) { | |
439 | dev_err(&client->dev, | |
440 | "failed to create fsa9480 attribute group\n"); | |
441 | goto fail2; | |
442 | } | |
443 | ||
444 | /* ADC Detect Time: 500ms */ | |
445 | fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6); | |
446 | ||
447 | if (chip->pdata->reset_cb) | |
448 | chip->pdata->reset_cb(); | |
449 | ||
450 | /* device detection */ | |
451 | fsa9480_detect_dev(usbsw, INT_ATTACH); | |
452 | ||
453 | pm_runtime_set_active(&client->dev); | |
454 | ||
455 | return 0; | |
456 | ||
457 | fail2: | |
458 | if (client->irq) | |
b89d5f17 | 459 | free_irq(client->irq, usbsw); |
a1bb73d7 | 460 | fail1: |
a1bb73d7 DK |
461 | kfree(usbsw); |
462 | return ret; | |
463 | } | |
464 | ||
486a5c28 | 465 | static int fsa9480_remove(struct i2c_client *client) |
a1bb73d7 DK |
466 | { |
467 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); | |
1a3771d5 | 468 | |
a1bb73d7 | 469 | if (client->irq) |
b89d5f17 | 470 | free_irq(client->irq, usbsw); |
a1bb73d7 DK |
471 | |
472 | sysfs_remove_group(&client->dev.kobj, &fsa9480_group); | |
473 | device_init_wakeup(&client->dev, 0); | |
474 | kfree(usbsw); | |
475 | return 0; | |
476 | } | |
477 | ||
5d4717d7 | 478 | #ifdef CONFIG_PM_SLEEP |
a1bb73d7 | 479 | |
5d4717d7 | 480 | static int fsa9480_suspend(struct device *dev) |
a1bb73d7 | 481 | { |
5d4717d7 | 482 | struct i2c_client *client = to_i2c_client(dev); |
a1bb73d7 DK |
483 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); |
484 | struct fsa9480_platform_data *pdata = usbsw->pdata; | |
485 | ||
486 | if (device_may_wakeup(&client->dev) && client->irq) | |
487 | enable_irq_wake(client->irq); | |
488 | ||
489 | if (pdata->usb_power) | |
490 | pdata->usb_power(0); | |
491 | ||
492 | return 0; | |
493 | } | |
494 | ||
5d4717d7 | 495 | static int fsa9480_resume(struct device *dev) |
a1bb73d7 | 496 | { |
5d4717d7 | 497 | struct i2c_client *client = to_i2c_client(dev); |
a1bb73d7 DK |
498 | struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); |
499 | int dev1, dev2; | |
500 | ||
501 | if (device_may_wakeup(&client->dev) && client->irq) | |
502 | disable_irq_wake(client->irq); | |
503 | ||
504 | /* | |
505 | * Clear Pending interrupt. Note that detect_dev does what | |
506 | * the interrupt handler does. So, we don't miss pending and | |
507 | * we reenable interrupt if there is one. | |
508 | */ | |
509 | fsa9480_read_reg(client, FSA9480_REG_INT1); | |
510 | fsa9480_read_reg(client, FSA9480_REG_INT2); | |
511 | ||
512 | dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1); | |
513 | dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2); | |
514 | ||
515 | /* device detection */ | |
516 | fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH); | |
517 | ||
518 | return 0; | |
519 | } | |
520 | ||
5d4717d7 LPC |
521 | static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume); |
522 | #define FSA9480_PM_OPS (&fsa9480_pm_ops) | |
523 | ||
a1bb73d7 DK |
524 | #else |
525 | ||
5d4717d7 | 526 | #define FSA9480_PM_OPS NULL |
a1bb73d7 | 527 | |
5d4717d7 | 528 | #endif /* CONFIG_PM_SLEEP */ |
a1bb73d7 DK |
529 | |
530 | static const struct i2c_device_id fsa9480_id[] = { | |
531 | {"fsa9480", 0}, | |
532 | {} | |
533 | }; | |
534 | MODULE_DEVICE_TABLE(i2c, fsa9480_id); | |
535 | ||
536 | static struct i2c_driver fsa9480_i2c_driver = { | |
537 | .driver = { | |
538 | .name = "fsa9480", | |
5d4717d7 | 539 | .pm = FSA9480_PM_OPS, |
a1bb73d7 DK |
540 | }, |
541 | .probe = fsa9480_probe, | |
2d6bed9c | 542 | .remove = fsa9480_remove, |
a1bb73d7 DK |
543 | .id_table = fsa9480_id, |
544 | }; | |
545 | ||
a64fe2ed | 546 | module_i2c_driver(fsa9480_i2c_driver); |
a1bb73d7 DK |
547 | |
548 | MODULE_AUTHOR("Minkyu Kang <[email protected]>"); | |
549 | MODULE_DESCRIPTION("FSA9480 USB Switch driver"); | |
550 | MODULE_LICENSE("GPL"); |