1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * lm3533-core.c -- LM3533 Core |
4 | * |
5 | * Copyright (C) 2011-2012 Texas Instruments |
6 | * |
7 | * Author: Johan Hovold <jhovold@gmail.com> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/err.h> |
14 | #include <linux/gpio.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/mfd/core.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/seq_file.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/uaccess.h> |
21 | |
22 | #include <linux/mfd/lm3533.h> |
23 | |
24 | |
25 | #define LM3533_BOOST_OVP_MASK 0x06 |
26 | #define LM3533_BOOST_OVP_SHIFT 1 |
27 | |
28 | #define LM3533_BOOST_FREQ_MASK 0x01 |
29 | #define LM3533_BOOST_FREQ_SHIFT 0 |
30 | |
31 | #define LM3533_BL_ID_MASK 1 |
32 | #define LM3533_LED_ID_MASK 3 |
33 | #define LM3533_BL_ID_MAX 1 |
34 | #define LM3533_LED_ID_MAX 3 |
35 | |
36 | #define LM3533_HVLED_ID_MAX 2 |
37 | #define LM3533_LVLED_ID_MAX 5 |
38 | |
39 | #define LM3533_REG_OUTPUT_CONF1 0x10 |
40 | #define LM3533_REG_OUTPUT_CONF2 0x11 |
41 | #define LM3533_REG_BOOST_PWM 0x2c |
42 | |
43 | #define LM3533_REG_MAX 0xb2 |
44 | |
45 | |
46 | static struct mfd_cell lm3533_als_devs[] = { |
47 | { |
48 | .name = "lm3533-als" , |
49 | .id = -1, |
50 | }, |
51 | }; |
52 | |
53 | static struct mfd_cell lm3533_bl_devs[] = { |
54 | { |
55 | .name = "lm3533-backlight" , |
56 | .id = 0, |
57 | }, |
58 | { |
59 | .name = "lm3533-backlight" , |
60 | .id = 1, |
61 | }, |
62 | }; |
63 | |
64 | static struct mfd_cell lm3533_led_devs[] = { |
65 | { |
66 | .name = "lm3533-leds" , |
67 | .id = 0, |
68 | }, |
69 | { |
70 | .name = "lm3533-leds" , |
71 | .id = 1, |
72 | }, |
73 | { |
74 | .name = "lm3533-leds" , |
75 | .id = 2, |
76 | }, |
77 | { |
78 | .name = "lm3533-leds" , |
79 | .id = 3, |
80 | }, |
81 | }; |
82 | |
83 | int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val) |
84 | { |
85 | int tmp; |
86 | int ret; |
87 | |
88 | ret = regmap_read(map: lm3533->regmap, reg, val: &tmp); |
89 | if (ret < 0) { |
90 | dev_err(lm3533->dev, "failed to read register %02x: %d\n" , |
91 | reg, ret); |
92 | return ret; |
93 | } |
94 | |
95 | *val = tmp; |
96 | |
97 | dev_dbg(lm3533->dev, "read [%02x]: %02x\n" , reg, *val); |
98 | |
99 | return ret; |
100 | } |
101 | EXPORT_SYMBOL_GPL(lm3533_read); |
102 | |
103 | int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val) |
104 | { |
105 | int ret; |
106 | |
107 | dev_dbg(lm3533->dev, "write [%02x]: %02x\n" , reg, val); |
108 | |
109 | ret = regmap_write(map: lm3533->regmap, reg, val); |
110 | if (ret < 0) { |
111 | dev_err(lm3533->dev, "failed to write register %02x: %d\n" , |
112 | reg, ret); |
113 | } |
114 | |
115 | return ret; |
116 | } |
117 | EXPORT_SYMBOL_GPL(lm3533_write); |
118 | |
119 | int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask) |
120 | { |
121 | int ret; |
122 | |
123 | dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n" , reg, val, mask); |
124 | |
125 | ret = regmap_update_bits(map: lm3533->regmap, reg, mask, val); |
126 | if (ret < 0) { |
127 | dev_err(lm3533->dev, "failed to update register %02x: %d\n" , |
128 | reg, ret); |
129 | } |
130 | |
131 | return ret; |
132 | } |
133 | EXPORT_SYMBOL_GPL(lm3533_update); |
134 | |
135 | static int lm3533_set_boost_freq(struct lm3533 *lm3533, |
136 | enum lm3533_boost_freq freq) |
137 | { |
138 | int ret; |
139 | |
140 | ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, |
141 | freq << LM3533_BOOST_FREQ_SHIFT, |
142 | LM3533_BOOST_FREQ_MASK); |
143 | if (ret) |
144 | dev_err(lm3533->dev, "failed to set boost frequency\n" ); |
145 | |
146 | return ret; |
147 | } |
148 | |
149 | |
150 | static int lm3533_set_boost_ovp(struct lm3533 *lm3533, |
151 | enum lm3533_boost_ovp ovp) |
152 | { |
153 | int ret; |
154 | |
155 | ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, |
156 | ovp << LM3533_BOOST_OVP_SHIFT, |
157 | LM3533_BOOST_OVP_MASK); |
158 | if (ret) |
159 | dev_err(lm3533->dev, "failed to set boost ovp\n" ); |
160 | |
161 | return ret; |
162 | } |
163 | |
164 | /* |
165 | * HVLED output config -- output hvled controlled by backlight bl |
166 | */ |
167 | static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl) |
168 | { |
169 | u8 val; |
170 | u8 mask; |
171 | int shift; |
172 | int ret; |
173 | |
174 | if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX) |
175 | return -EINVAL; |
176 | |
177 | if (bl > LM3533_BL_ID_MAX) |
178 | return -EINVAL; |
179 | |
180 | shift = hvled - 1; |
181 | mask = LM3533_BL_ID_MASK << shift; |
182 | val = bl << shift; |
183 | |
184 | ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask); |
185 | if (ret) |
186 | dev_err(lm3533->dev, "failed to set hvled config\n" ); |
187 | |
188 | return ret; |
189 | } |
190 | |
191 | /* |
192 | * LVLED output config -- output lvled controlled by LED led |
193 | */ |
194 | static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led) |
195 | { |
196 | u8 reg; |
197 | u8 val; |
198 | u8 mask; |
199 | int shift; |
200 | int ret; |
201 | |
202 | if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX) |
203 | return -EINVAL; |
204 | |
205 | if (led > LM3533_LED_ID_MAX) |
206 | return -EINVAL; |
207 | |
208 | if (lvled < 4) { |
209 | reg = LM3533_REG_OUTPUT_CONF1; |
210 | shift = 2 * lvled; |
211 | } else { |
212 | reg = LM3533_REG_OUTPUT_CONF2; |
213 | shift = 2 * (lvled - 4); |
214 | } |
215 | |
216 | mask = LM3533_LED_ID_MASK << shift; |
217 | val = led << shift; |
218 | |
219 | ret = lm3533_update(lm3533, reg, val, mask); |
220 | if (ret) |
221 | dev_err(lm3533->dev, "failed to set lvled config\n" ); |
222 | |
223 | return ret; |
224 | } |
225 | |
226 | static void lm3533_enable(struct lm3533 *lm3533) |
227 | { |
228 | if (gpio_is_valid(number: lm3533->gpio_hwen)) |
229 | gpio_set_value(gpio: lm3533->gpio_hwen, value: 1); |
230 | } |
231 | |
232 | static void lm3533_disable(struct lm3533 *lm3533) |
233 | { |
234 | if (gpio_is_valid(number: lm3533->gpio_hwen)) |
235 | gpio_set_value(gpio: lm3533->gpio_hwen, value: 0); |
236 | } |
237 | |
238 | enum lm3533_attribute_type { |
239 | LM3533_ATTR_TYPE_BACKLIGHT, |
240 | LM3533_ATTR_TYPE_LED, |
241 | }; |
242 | |
243 | struct lm3533_device_attribute { |
244 | struct device_attribute dev_attr; |
245 | enum lm3533_attribute_type type; |
246 | union { |
247 | struct { |
248 | u8 id; |
249 | } output; |
250 | } u; |
251 | }; |
252 | |
253 | #define to_lm3533_dev_attr(_attr) \ |
254 | container_of(_attr, struct lm3533_device_attribute, dev_attr) |
255 | |
256 | static ssize_t show_output(struct device *dev, |
257 | struct device_attribute *attr, char *buf) |
258 | { |
259 | struct lm3533 *lm3533 = dev_get_drvdata(dev); |
260 | struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr); |
261 | int id = lattr->u.output.id; |
262 | u8 reg; |
263 | u8 val; |
264 | u8 mask; |
265 | int shift; |
266 | int ret; |
267 | |
268 | if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) { |
269 | reg = LM3533_REG_OUTPUT_CONF1; |
270 | shift = id - 1; |
271 | mask = LM3533_BL_ID_MASK << shift; |
272 | } else { |
273 | if (id < 4) { |
274 | reg = LM3533_REG_OUTPUT_CONF1; |
275 | shift = 2 * id; |
276 | } else { |
277 | reg = LM3533_REG_OUTPUT_CONF2; |
278 | shift = 2 * (id - 4); |
279 | } |
280 | mask = LM3533_LED_ID_MASK << shift; |
281 | } |
282 | |
283 | ret = lm3533_read(lm3533, reg, &val); |
284 | if (ret) |
285 | return ret; |
286 | |
287 | val = (val & mask) >> shift; |
288 | |
289 | return sysfs_emit(buf, fmt: "%u\n" , val); |
290 | } |
291 | |
292 | static ssize_t store_output(struct device *dev, |
293 | struct device_attribute *attr, |
294 | const char *buf, size_t len) |
295 | { |
296 | struct lm3533 *lm3533 = dev_get_drvdata(dev); |
297 | struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr); |
298 | int id = lattr->u.output.id; |
299 | u8 val; |
300 | int ret; |
301 | |
302 | if (kstrtou8(s: buf, base: 0, res: &val)) |
303 | return -EINVAL; |
304 | |
305 | if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) |
306 | ret = lm3533_set_hvled_config(lm3533, hvled: id, bl: val); |
307 | else |
308 | ret = lm3533_set_lvled_config(lm3533, lvled: id, led: val); |
309 | |
310 | if (ret) |
311 | return ret; |
312 | |
313 | return len; |
314 | } |
315 | |
316 | #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \ |
317 | struct lm3533_device_attribute lm3533_dev_attr_##_name = \ |
318 | { .dev_attr = __ATTR(_name, _mode, _show, _store), \ |
319 | .type = _type, \ |
320 | .u.output = { .id = _id }, } |
321 | |
322 | #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \ |
323 | LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \ |
324 | show_output, store_output, _type, _id) |
325 | |
326 | #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \ |
327 | LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr) |
328 | #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \ |
329 | LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr) |
330 | /* |
331 | * Output config: |
332 | * |
333 | * output_hvled<nr> 0-1 |
334 | * output_lvled<nr> 0-3 |
335 | */ |
336 | static LM3533_OUTPUT_HVLED_ATTR_RW(1); |
337 | static LM3533_OUTPUT_HVLED_ATTR_RW(2); |
338 | static LM3533_OUTPUT_LVLED_ATTR_RW(1); |
339 | static LM3533_OUTPUT_LVLED_ATTR_RW(2); |
340 | static LM3533_OUTPUT_LVLED_ATTR_RW(3); |
341 | static LM3533_OUTPUT_LVLED_ATTR_RW(4); |
342 | static LM3533_OUTPUT_LVLED_ATTR_RW(5); |
343 | |
344 | static struct attribute *lm3533_attributes[] = { |
345 | &lm3533_dev_attr_output_hvled1.dev_attr.attr, |
346 | &lm3533_dev_attr_output_hvled2.dev_attr.attr, |
347 | &lm3533_dev_attr_output_lvled1.dev_attr.attr, |
348 | &lm3533_dev_attr_output_lvled2.dev_attr.attr, |
349 | &lm3533_dev_attr_output_lvled3.dev_attr.attr, |
350 | &lm3533_dev_attr_output_lvled4.dev_attr.attr, |
351 | &lm3533_dev_attr_output_lvled5.dev_attr.attr, |
352 | NULL, |
353 | }; |
354 | |
355 | #define to_dev_attr(_attr) \ |
356 | container_of(_attr, struct device_attribute, attr) |
357 | |
358 | static umode_t lm3533_attr_is_visible(struct kobject *kobj, |
359 | struct attribute *attr, int n) |
360 | { |
361 | struct device *dev = kobj_to_dev(kobj); |
362 | struct lm3533 *lm3533 = dev_get_drvdata(dev); |
363 | struct device_attribute *dattr = to_dev_attr(attr); |
364 | struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr); |
365 | enum lm3533_attribute_type type = lattr->type; |
366 | umode_t mode = attr->mode; |
367 | |
368 | if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT) |
369 | mode = 0; |
370 | else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED) |
371 | mode = 0; |
372 | |
373 | return mode; |
374 | }; |
375 | |
376 | static struct attribute_group lm3533_attribute_group = { |
377 | .is_visible = lm3533_attr_is_visible, |
378 | .attrs = lm3533_attributes |
379 | }; |
380 | |
381 | static int lm3533_device_als_init(struct lm3533 *lm3533) |
382 | { |
383 | struct lm3533_platform_data *pdata = dev_get_platdata(dev: lm3533->dev); |
384 | int ret; |
385 | |
386 | if (!pdata->als) |
387 | return 0; |
388 | |
389 | lm3533_als_devs[0].platform_data = pdata->als; |
390 | lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); |
391 | |
392 | ret = mfd_add_devices(parent: lm3533->dev, id: 0, cells: lm3533_als_devs, n_devs: 1, NULL, |
393 | irq_base: 0, NULL); |
394 | if (ret) { |
395 | dev_err(lm3533->dev, "failed to add ALS device\n" ); |
396 | return ret; |
397 | } |
398 | |
399 | lm3533->have_als = 1; |
400 | |
401 | return 0; |
402 | } |
403 | |
404 | static int lm3533_device_bl_init(struct lm3533 *lm3533) |
405 | { |
406 | struct lm3533_platform_data *pdata = dev_get_platdata(dev: lm3533->dev); |
407 | int i; |
408 | int ret; |
409 | |
410 | if (!pdata->backlights || pdata->num_backlights == 0) |
411 | return 0; |
412 | |
413 | if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs)) |
414 | pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs); |
415 | |
416 | for (i = 0; i < pdata->num_backlights; ++i) { |
417 | lm3533_bl_devs[i].platform_data = &pdata->backlights[i]; |
418 | lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]); |
419 | } |
420 | |
421 | ret = mfd_add_devices(parent: lm3533->dev, id: 0, cells: lm3533_bl_devs, |
422 | n_devs: pdata->num_backlights, NULL, irq_base: 0, NULL); |
423 | if (ret) { |
424 | dev_err(lm3533->dev, "failed to add backlight devices\n" ); |
425 | return ret; |
426 | } |
427 | |
428 | lm3533->have_backlights = 1; |
429 | |
430 | return 0; |
431 | } |
432 | |
433 | static int lm3533_device_led_init(struct lm3533 *lm3533) |
434 | { |
435 | struct lm3533_platform_data *pdata = dev_get_platdata(dev: lm3533->dev); |
436 | int i; |
437 | int ret; |
438 | |
439 | if (!pdata->leds || pdata->num_leds == 0) |
440 | return 0; |
441 | |
442 | if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs)) |
443 | pdata->num_leds = ARRAY_SIZE(lm3533_led_devs); |
444 | |
445 | for (i = 0; i < pdata->num_leds; ++i) { |
446 | lm3533_led_devs[i].platform_data = &pdata->leds[i]; |
447 | lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]); |
448 | } |
449 | |
450 | ret = mfd_add_devices(parent: lm3533->dev, id: 0, cells: lm3533_led_devs, |
451 | n_devs: pdata->num_leds, NULL, irq_base: 0, NULL); |
452 | if (ret) { |
453 | dev_err(lm3533->dev, "failed to add LED devices\n" ); |
454 | return ret; |
455 | } |
456 | |
457 | lm3533->have_leds = 1; |
458 | |
459 | return 0; |
460 | } |
461 | |
462 | static int lm3533_device_setup(struct lm3533 *lm3533, |
463 | struct lm3533_platform_data *pdata) |
464 | { |
465 | int ret; |
466 | |
467 | ret = lm3533_set_boost_freq(lm3533, freq: pdata->boost_freq); |
468 | if (ret) |
469 | return ret; |
470 | |
471 | return lm3533_set_boost_ovp(lm3533, ovp: pdata->boost_ovp); |
472 | } |
473 | |
474 | static int lm3533_device_init(struct lm3533 *lm3533) |
475 | { |
476 | struct lm3533_platform_data *pdata = dev_get_platdata(dev: lm3533->dev); |
477 | int ret; |
478 | |
479 | dev_dbg(lm3533->dev, "%s\n" , __func__); |
480 | |
481 | if (!pdata) { |
482 | dev_err(lm3533->dev, "no platform data\n" ); |
483 | return -EINVAL; |
484 | } |
485 | |
486 | lm3533->gpio_hwen = pdata->gpio_hwen; |
487 | |
488 | if (gpio_is_valid(number: lm3533->gpio_hwen)) { |
489 | ret = devm_gpio_request_one(dev: lm3533->dev, gpio: lm3533->gpio_hwen, |
490 | GPIOF_OUT_INIT_LOW, label: "lm3533-hwen" ); |
491 | if (ret < 0) { |
492 | dev_err(lm3533->dev, |
493 | "failed to request HWEN GPIO %d\n" , |
494 | lm3533->gpio_hwen); |
495 | return ret; |
496 | } |
497 | } |
498 | |
499 | lm3533_enable(lm3533); |
500 | |
501 | ret = lm3533_device_setup(lm3533, pdata); |
502 | if (ret) |
503 | goto err_disable; |
504 | |
505 | lm3533_device_als_init(lm3533); |
506 | lm3533_device_bl_init(lm3533); |
507 | lm3533_device_led_init(lm3533); |
508 | |
509 | ret = sysfs_create_group(kobj: &lm3533->dev->kobj, grp: &lm3533_attribute_group); |
510 | if (ret < 0) { |
511 | dev_err(lm3533->dev, "failed to create sysfs attributes\n" ); |
512 | goto err_unregister; |
513 | } |
514 | |
515 | return 0; |
516 | |
517 | err_unregister: |
518 | mfd_remove_devices(parent: lm3533->dev); |
519 | err_disable: |
520 | lm3533_disable(lm3533); |
521 | |
522 | return ret; |
523 | } |
524 | |
525 | static void lm3533_device_exit(struct lm3533 *lm3533) |
526 | { |
527 | dev_dbg(lm3533->dev, "%s\n" , __func__); |
528 | |
529 | sysfs_remove_group(kobj: &lm3533->dev->kobj, grp: &lm3533_attribute_group); |
530 | |
531 | mfd_remove_devices(parent: lm3533->dev); |
532 | lm3533_disable(lm3533); |
533 | } |
534 | |
535 | static bool lm3533_readable_register(struct device *dev, unsigned int reg) |
536 | { |
537 | switch (reg) { |
538 | case 0x10 ... 0x2c: |
539 | case 0x30 ... 0x38: |
540 | case 0x40 ... 0x45: |
541 | case 0x50 ... 0x57: |
542 | case 0x60 ... 0x6e: |
543 | case 0x70 ... 0x75: |
544 | case 0x80 ... 0x85: |
545 | case 0x90 ... 0x95: |
546 | case 0xa0 ... 0xa5: |
547 | case 0xb0 ... 0xb2: |
548 | return true; |
549 | default: |
550 | return false; |
551 | } |
552 | } |
553 | |
554 | static bool lm3533_volatile_register(struct device *dev, unsigned int reg) |
555 | { |
556 | switch (reg) { |
557 | case 0x34 ... 0x36: /* zone */ |
558 | case 0x37 ... 0x38: /* adc */ |
559 | case 0xb0 ... 0xb1: /* fault */ |
560 | return true; |
561 | default: |
562 | return false; |
563 | } |
564 | } |
565 | |
566 | static bool lm3533_precious_register(struct device *dev, unsigned int reg) |
567 | { |
568 | switch (reg) { |
569 | case 0x34: /* zone */ |
570 | return true; |
571 | default: |
572 | return false; |
573 | } |
574 | } |
575 | |
576 | static const struct regmap_config regmap_config = { |
577 | .reg_bits = 8, |
578 | .val_bits = 8, |
579 | .max_register = LM3533_REG_MAX, |
580 | .readable_reg = lm3533_readable_register, |
581 | .volatile_reg = lm3533_volatile_register, |
582 | .precious_reg = lm3533_precious_register, |
583 | }; |
584 | |
585 | static int lm3533_i2c_probe(struct i2c_client *i2c) |
586 | { |
587 | struct lm3533 *lm3533; |
588 | |
589 | dev_dbg(&i2c->dev, "%s\n" , __func__); |
590 | |
591 | lm3533 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*lm3533), GFP_KERNEL); |
592 | if (!lm3533) |
593 | return -ENOMEM; |
594 | |
595 | i2c_set_clientdata(client: i2c, data: lm3533); |
596 | |
597 | lm3533->regmap = devm_regmap_init_i2c(i2c, ®map_config); |
598 | if (IS_ERR(ptr: lm3533->regmap)) |
599 | return PTR_ERR(ptr: lm3533->regmap); |
600 | |
601 | lm3533->dev = &i2c->dev; |
602 | lm3533->irq = i2c->irq; |
603 | |
604 | return lm3533_device_init(lm3533); |
605 | } |
606 | |
607 | static void lm3533_i2c_remove(struct i2c_client *i2c) |
608 | { |
609 | struct lm3533 *lm3533 = i2c_get_clientdata(client: i2c); |
610 | |
611 | dev_dbg(&i2c->dev, "%s\n" , __func__); |
612 | |
613 | lm3533_device_exit(lm3533); |
614 | } |
615 | |
616 | static const struct i2c_device_id lm3533_i2c_ids[] = { |
617 | { "lm3533" , 0 }, |
618 | { }, |
619 | }; |
620 | MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids); |
621 | |
622 | static struct i2c_driver lm3533_i2c_driver = { |
623 | .driver = { |
624 | .name = "lm3533" , |
625 | }, |
626 | .id_table = lm3533_i2c_ids, |
627 | .probe = lm3533_i2c_probe, |
628 | .remove = lm3533_i2c_remove, |
629 | }; |
630 | |
631 | static int __init lm3533_i2c_init(void) |
632 | { |
633 | return i2c_add_driver(&lm3533_i2c_driver); |
634 | } |
635 | subsys_initcall(lm3533_i2c_init); |
636 | |
637 | static void __exit lm3533_i2c_exit(void) |
638 | { |
639 | i2c_del_driver(driver: &lm3533_i2c_driver); |
640 | } |
641 | module_exit(lm3533_i2c_exit); |
642 | |
643 | MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>" ); |
644 | MODULE_DESCRIPTION("LM3533 Core" ); |
645 | MODULE_LICENSE("GPL" ); |
646 | |