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