]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
16c5c023 JH |
2 | /* |
3 | * lm3533-core.c -- LM3533 Core | |
4 | * | |
5 | * Copyright (C) 2011-2012 Texas Instruments | |
6 | * | |
7 | * Author: Johan Hovold <[email protected]> | |
16c5c023 JH |
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 | ||
16c5c023 JH |
25 | #define LM3533_BOOST_OVP_MASK 0x06 |
26 | #define LM3533_BOOST_OVP_SHIFT 1 | |
27 | ||
16c5c023 JH |
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(lm3533->regmap, reg, &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(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 | ||
664dd066 | 125 | ret = regmap_update_bits(lm3533->regmap, reg, mask, val); |
16c5c023 JH |
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 | ||
d9055dc5 JH |
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 | ||
16c5c023 JH |
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(lm3533->gpio_hwen)) | |
229 | gpio_set_value(lm3533->gpio_hwen, 1); | |
230 | } | |
231 | ||
232 | static void lm3533_disable(struct lm3533 *lm3533) | |
233 | { | |
234 | if (gpio_is_valid(lm3533->gpio_hwen)) | |
235 | gpio_set_value(lm3533->gpio_hwen, 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; | |
16c5c023 JH |
250 | } u; |
251 | }; | |
252 | ||
253 | #define to_lm3533_dev_attr(_attr) \ | |
254 | container_of(_attr, struct lm3533_device_attribute, dev_attr) | |
255 | ||
16c5c023 JH |
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 | ||
8cc5e62b | 289 | return sysfs_emit(buf, "%u\n", val); |
16c5c023 JH |
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(buf, 0, &val)) | |
303 | return -EINVAL; | |
304 | ||
305 | if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) | |
306 | ret = lm3533_set_hvled_config(lm3533, id, val); | |
307 | else | |
308 | ret = lm3533_set_lvled_config(lm3533, id, 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[] = { | |
16c5c023 JH |
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 | ||
168755eb | 358 | static umode_t lm3533_attr_is_visible(struct kobject *kobj, |
16c5c023 JH |
359 | struct attribute *attr, int n) |
360 | { | |
23144a32 | 361 | struct device *dev = kobj_to_dev(kobj); |
16c5c023 JH |
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; | |
60908855 | 366 | umode_t mode = attr->mode; |
16c5c023 JH |
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 | ||
f791be49 | 381 | static int lm3533_device_als_init(struct lm3533 *lm3533) |
16c5c023 | 382 | { |
334a41ce | 383 | struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); |
16c5c023 JH |
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 | ||
0848c94f MB |
392 | ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, |
393 | 0, NULL); | |
16c5c023 JH |
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 | ||
f791be49 | 404 | static int lm3533_device_bl_init(struct lm3533 *lm3533) |
16c5c023 | 405 | { |
334a41ce | 406 | struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); |
16c5c023 JH |
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(lm3533->dev, 0, lm3533_bl_devs, | |
0848c94f | 422 | pdata->num_backlights, NULL, 0, NULL); |
16c5c023 JH |
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 | ||
f791be49 | 433 | static int lm3533_device_led_init(struct lm3533 *lm3533) |
16c5c023 | 434 | { |
334a41ce | 435 | struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); |
16c5c023 JH |
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(lm3533->dev, 0, lm3533_led_devs, | |
0848c94f | 451 | pdata->num_leds, NULL, 0, NULL); |
16c5c023 JH |
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 | ||
f791be49 | 462 | static int lm3533_device_setup(struct lm3533 *lm3533, |
d9055dc5 JH |
463 | struct lm3533_platform_data *pdata) |
464 | { | |
465 | int ret; | |
466 | ||
467 | ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq); | |
468 | if (ret) | |
469 | return ret; | |
470 | ||
a1c16d71 | 471 | return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp); |
d9055dc5 JH |
472 | } |
473 | ||
f791be49 | 474 | static int lm3533_device_init(struct lm3533 *lm3533) |
16c5c023 | 475 | { |
334a41ce | 476 | struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); |
16c5c023 JH |
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 | ||
16c5c023 | 488 | if (gpio_is_valid(lm3533->gpio_hwen)) { |
bf5ea28a JH |
489 | ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, |
490 | GPIOF_OUT_INIT_LOW, "lm3533-hwen"); | |
16c5c023 JH |
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 | ||
d9055dc5 JH |
501 | ret = lm3533_device_setup(lm3533, pdata); |
502 | if (ret) | |
503 | goto err_disable; | |
504 | ||
16c5c023 JH |
505 | lm3533_device_als_init(lm3533); |
506 | lm3533_device_bl_init(lm3533); | |
507 | lm3533_device_led_init(lm3533); | |
508 | ||
509 | ret = sysfs_create_group(&lm3533->dev->kobj, &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(lm3533->dev); | |
d9055dc5 | 519 | err_disable: |
16c5c023 | 520 | lm3533_disable(lm3533); |
16c5c023 JH |
521 | |
522 | return ret; | |
523 | } | |
524 | ||
4740f73f | 525 | static void lm3533_device_exit(struct lm3533 *lm3533) |
16c5c023 JH |
526 | { |
527 | dev_dbg(lm3533->dev, "%s\n", __func__); | |
528 | ||
529 | sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group); | |
530 | ||
531 | mfd_remove_devices(lm3533->dev); | |
532 | lm3533_disable(lm3533); | |
16c5c023 JH |
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) { | |
c48bf153 | 557 | case 0x34 ... 0x36: /* zone */ |
16c5c023 JH |
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 | ||
dd635161 | 576 | static const struct regmap_config regmap_config = { |
16c5c023 JH |
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 | ||
daf811fc | 585 | static int lm3533_i2c_probe(struct i2c_client *i2c) |
16c5c023 JH |
586 | { |
587 | struct lm3533 *lm3533; | |
16c5c023 JH |
588 | |
589 | dev_dbg(&i2c->dev, "%s\n", __func__); | |
590 | ||
fa648e51 | 591 | lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL); |
16c5c023 JH |
592 | if (!lm3533) |
593 | return -ENOMEM; | |
594 | ||
595 | i2c_set_clientdata(i2c, lm3533); | |
596 | ||
fa648e51 JH |
597 | lm3533->regmap = devm_regmap_init_i2c(i2c, ®map_config); |
598 | if (IS_ERR(lm3533->regmap)) | |
599 | return PTR_ERR(lm3533->regmap); | |
16c5c023 JH |
600 | |
601 | lm3533->dev = &i2c->dev; | |
602 | lm3533->irq = i2c->irq; | |
603 | ||
a1c16d71 | 604 | return lm3533_device_init(lm3533); |
16c5c023 JH |
605 | } |
606 | ||
ed5c2f5f | 607 | static void lm3533_i2c_remove(struct i2c_client *i2c) |
16c5c023 JH |
608 | { |
609 | struct lm3533 *lm3533 = i2c_get_clientdata(i2c); | |
610 | ||
611 | dev_dbg(&i2c->dev, "%s\n", __func__); | |
612 | ||
613 | lm3533_device_exit(lm3533); | |
16c5c023 JH |
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", | |
16c5c023 JH |
625 | }, |
626 | .id_table = lm3533_i2c_ids, | |
9816d859 | 627 | .probe = lm3533_i2c_probe, |
84449216 | 628 | .remove = lm3533_i2c_remove, |
16c5c023 JH |
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(&lm3533_i2c_driver); | |
640 | } | |
641 | module_exit(lm3533_i2c_exit); | |
642 | ||
643 | MODULE_AUTHOR("Johan Hovold <[email protected]>"); | |
644 | MODULE_DESCRIPTION("LM3533 Core"); | |
645 | MODULE_LICENSE("GPL"); |