summaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@linux.intel.com>2015-04-26 17:56:54 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-08-26 20:30:12 -0400
commita56ba8fbcb55f3c5fc06f803469e7412f9e13c18 (patch)
treef15d173468c416599d48cdca3787fc1359c7ce3f /drivers/leds
parent535a218d26bed1f565adbb6921226b213e4574d1 (diff)
media: leds: as3645a: Add LED flash class driver
Add a LED flash class driver for the as3654a flash controller. A V4L2 flash driver for it already exists (drivers/media/i2c/as3645a.c), and this driver is based on that. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Acked-by: Jacek Anaszewski <jacek.anaszewski@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-as3645a.c763
3 files changed, 772 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 594b24d410c3..bad3a4098104 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -58,6 +58,14 @@ config LEDS_AAT1290
58 help 58 help
59 This option enables support for the LEDs on the AAT1290. 59 This option enables support for the LEDs on the AAT1290.
60 60
61config LEDS_AS3645A
62 tristate "AS3645A LED flash controller support"
63 depends on I2C && LEDS_CLASS_FLASH
64 help
65 Enable LED flash class support for AS3645A LED flash
66 controller. V4L2 flash API is provided as well if
67 CONFIG_V4L2_FLASH_API is enabled.
68
61config LEDS_BCM6328 69config LEDS_BCM6328
62 tristate "LED Support for Broadcom BCM6328" 70 tristate "LED Support for Broadcom BCM6328"
63 depends on LEDS_CLASS 71 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 909dae62ba05..7d7b26552923 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
8# LED Platform Drivers 8# LED Platform Drivers
9obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o 9obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
10obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o 10obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
11obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
11obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o 12obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
12obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o 13obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
13obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o 14obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
new file mode 100644
index 000000000000..bbbbe0898233
--- /dev/null
+++ b/drivers/leds/leds-as3645a.c
@@ -0,0 +1,763 @@
1/*
2 * drivers/leds/leds-as3645a.c - AS3645A and LM3555 flash controllers driver
3 *
4 * Copyright (C) 2008-2011 Nokia Corporation
5 * Copyright (c) 2011, 2017 Intel Corporation.
6 *
7 * Based on drivers/media/i2c/as3645a.c.
8 *
9 * Contact: Sakari Ailus <sakari.ailus@iki.fi>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 */
20
21#include <linux/delay.h>
22#include <linux/gpio/consumer.h>
23#include <linux/i2c.h>
24#include <linux/led-class-flash.h>
25#include <linux/leds.h>
26#include <linux/module.h>
27#include <linux/mutex.h>
28#include <linux/of.h>
29#include <linux/slab.h>
30
31#include <media/v4l2-flash-led-class.h>
32
33#define AS_TIMER_US_TO_CODE(t) (((t) / 1000 - 100) / 50)
34#define AS_TIMER_CODE_TO_US(c) ((50 * (c) + 100) * 1000)
35
36/* Register definitions */
37
38/* Read-only Design info register: Reset state: xxxx 0001 */
39#define AS_DESIGN_INFO_REG 0x00
40#define AS_DESIGN_INFO_FACTORY(x) (((x) >> 4))
41#define AS_DESIGN_INFO_MODEL(x) ((x) & 0x0f)
42
43/* Read-only Version control register: Reset state: 0000 0000
44 * for first engineering samples
45 */
46#define AS_VERSION_CONTROL_REG 0x01
47#define AS_VERSION_CONTROL_RFU(x) (((x) >> 4))
48#define AS_VERSION_CONTROL_VERSION(x) ((x) & 0x0f)
49
50/* Read / Write (Indicator and timer register): Reset state: 0000 1111 */
51#define AS_INDICATOR_AND_TIMER_REG 0x02
52#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT 0
53#define AS_INDICATOR_AND_TIMER_VREF_SHIFT 4
54#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6
55
56/* Read / Write (Current set register): Reset state: 0110 1001 */
57#define AS_CURRENT_SET_REG 0x03
58#define AS_CURRENT_ASSIST_LIGHT_SHIFT 0
59#define AS_CURRENT_LED_DET_ON (1 << 3)
60#define AS_CURRENT_FLASH_CURRENT_SHIFT 4
61
62/* Read / Write (Control register): Reset state: 1011 0100 */
63#define AS_CONTROL_REG 0x04
64#define AS_CONTROL_MODE_SETTING_SHIFT 0
65#define AS_CONTROL_STROBE_ON (1 << 2)
66#define AS_CONTROL_OUT_ON (1 << 3)
67#define AS_CONTROL_EXT_TORCH_ON (1 << 4)
68#define AS_CONTROL_STROBE_TYPE_EDGE (0 << 5)
69#define AS_CONTROL_STROBE_TYPE_LEVEL (1 << 5)
70#define AS_CONTROL_COIL_PEAK_SHIFT 6
71
72/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */
73#define AS_FAULT_INFO_REG 0x05
74#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT (1 << 1)
75#define AS_FAULT_INFO_INDICATOR_LED (1 << 2)
76#define AS_FAULT_INFO_LED_AMOUNT (1 << 3)
77#define AS_FAULT_INFO_TIMEOUT (1 << 4)
78#define AS_FAULT_INFO_OVER_TEMPERATURE (1 << 5)
79#define AS_FAULT_INFO_SHORT_CIRCUIT (1 << 6)
80#define AS_FAULT_INFO_OVER_VOLTAGE (1 << 7)
81
82/* Boost register */
83#define AS_BOOST_REG 0x0d
84#define AS_BOOST_CURRENT_DISABLE (0 << 0)
85#define AS_BOOST_CURRENT_ENABLE (1 << 0)
86
87/* Password register is used to unlock boost register writing */
88#define AS_PASSWORD_REG 0x0f
89#define AS_PASSWORD_UNLOCK_VALUE 0x55
90
91#define AS_NAME "as3645a"
92#define AS_I2C_ADDR (0x60 >> 1) /* W:0x60, R:0x61 */
93
94#define AS_FLASH_TIMEOUT_MIN 100000 /* us */
95#define AS_FLASH_TIMEOUT_MAX 850000
96#define AS_FLASH_TIMEOUT_STEP 50000
97
98#define AS_FLASH_INTENSITY_MIN 200000 /* uA */
99#define AS_FLASH_INTENSITY_MAX_1LED 500000
100#define AS_FLASH_INTENSITY_MAX_2LEDS 400000
101#define AS_FLASH_INTENSITY_STEP 20000
102
103#define AS_TORCH_INTENSITY_MIN 20000 /* uA */
104#define AS_TORCH_INTENSITY_MAX 160000
105#define AS_TORCH_INTENSITY_STEP 20000
106
107#define AS_INDICATOR_INTENSITY_MIN 0 /* uA */
108#define AS_INDICATOR_INTENSITY_MAX 10000
109#define AS_INDICATOR_INTENSITY_STEP 2500
110
111#define AS_PEAK_mA_MAX 2000
112#define AS_PEAK_mA_TO_REG(a) \
113 ((min_t(u32, AS_PEAK_mA_MAX, a) - 1250) / 250)
114
115enum as_mode {
116 AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT,
117 AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT,
118 AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT,
119 AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT,
120};
121
122struct as3645a_config {
123 u32 flash_timeout_us;
124 u32 flash_max_ua;
125 u32 assist_max_ua;
126 u32 indicator_max_ua;
127 u32 voltage_reference;
128 u32 peak;
129};
130
131struct as3645a_names {
132 char flash[32];
133 char indicator[32];
134};
135
136struct as3645a {
137 struct i2c_client *client;
138
139 struct mutex mutex;
140
141 struct led_classdev_flash fled;
142 struct led_classdev iled_cdev;
143
144 struct v4l2_flash *vf;
145 struct v4l2_flash *vfind;
146
147 struct device_node *flash_node;
148 struct device_node *indicator_node;
149
150 struct as3645a_config cfg;
151
152 enum as_mode mode;
153 unsigned int timeout;
154 unsigned int flash_current;
155 unsigned int assist_current;
156 unsigned int indicator_current;
157 enum v4l2_flash_strobe_source strobe_source;
158};
159
160#define fled_to_as3645a(__fled) container_of(__fled, struct as3645a, fled)
161#define iled_cdev_to_as3645a(__iled_cdev) \
162 container_of(__iled_cdev, struct as3645a, iled_cdev)
163
164/* Return negative errno else zero on success */
165static int as3645a_write(struct as3645a *flash, u8 addr, u8 val)
166{
167 struct i2c_client *client = flash->client;
168 int rval;
169
170 rval = i2c_smbus_write_byte_data(client, addr, val);
171
172 dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
173 rval < 0 ? "fail" : "ok");
174
175 return rval;
176}
177
178/* Return negative errno else a data byte received from the device. */
179static int as3645a_read(struct as3645a *flash, u8 addr)
180{
181 struct i2c_client *client = flash->client;
182 int rval;
183
184 rval = i2c_smbus_read_byte_data(client, addr);
185
186 dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval,
187 rval < 0 ? "fail" : "ok");
188
189 return rval;
190}
191
192/* -----------------------------------------------------------------------------
193 * Hardware configuration and trigger
194 */
195
196/**
197 * as3645a_set_config - Set flash configuration registers
198 * @flash: The flash
199 *
200 * Configure the hardware with flash, assist and indicator currents, as well as
201 * flash timeout.
202 *
203 * Return 0 on success, or a negative error code if an I2C communication error
204 * occurred.
205 */
206static int as3645a_set_current(struct as3645a *flash)
207{
208 u8 val;
209
210 val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT)
211 | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT)
212 | AS_CURRENT_LED_DET_ON;
213
214 return as3645a_write(flash, AS_CURRENT_SET_REG, val);
215}
216
217static int as3645a_set_timeout(struct as3645a *flash)
218{
219 u8 val;
220
221 val = flash->timeout << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT;
222
223 val |= (flash->cfg.voltage_reference
224 << AS_INDICATOR_AND_TIMER_VREF_SHIFT)
225 | ((flash->indicator_current ? flash->indicator_current - 1 : 0)
226 << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT);
227
228 return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val);
229}
230
231/**
232 * as3645a_set_control - Set flash control register
233 * @flash: The flash
234 * @mode: Desired output mode
235 * @on: Desired output state
236 *
237 * Configure the hardware with output mode and state.
238 *
239 * Return 0 on success, or a negative error code if an I2C communication error
240 * occurred.
241 */
242static int
243as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on)
244{
245 u8 reg;
246
247 /* Configure output parameters and operation mode. */
248 reg = (flash->cfg.peak << AS_CONTROL_COIL_PEAK_SHIFT)
249 | (on ? AS_CONTROL_OUT_ON : 0)
250 | mode;
251
252 if (mode == AS_MODE_FLASH &&
253 flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL)
254 reg |= AS_CONTROL_STROBE_TYPE_LEVEL
255 | AS_CONTROL_STROBE_ON;
256
257 return as3645a_write(flash, AS_CONTROL_REG, reg);
258}
259
260static int as3645a_get_fault(struct led_classdev_flash *fled, u32 *fault)
261{
262 struct as3645a *flash = fled_to_as3645a(fled);
263 int rval;
264
265 /* NOTE: reading register clears fault status */
266 rval = as3645a_read(flash, AS_FAULT_INFO_REG);
267 if (rval < 0)
268 return rval;
269
270 if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT)
271 *fault |= LED_FAULT_OVER_CURRENT;
272
273 if (rval & AS_FAULT_INFO_INDICATOR_LED)
274 *fault |= LED_FAULT_INDICATOR;
275
276 dev_dbg(&flash->client->dev, "%u connected LEDs\n",
277 rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1);
278
279 if (rval & AS_FAULT_INFO_TIMEOUT)
280 *fault |= LED_FAULT_TIMEOUT;
281
282 if (rval & AS_FAULT_INFO_OVER_TEMPERATURE)
283 *fault |= LED_FAULT_OVER_TEMPERATURE;
284
285 if (rval & AS_FAULT_INFO_SHORT_CIRCUIT)
286 *fault |= LED_FAULT_OVER_CURRENT;
287
288 if (rval & AS_FAULT_INFO_OVER_VOLTAGE)
289 *fault |= LED_FAULT_INPUT_VOLTAGE;
290
291 return rval;
292}
293
294static unsigned int __as3645a_current_to_reg(unsigned int min, unsigned int max,
295 unsigned int step,
296 unsigned int val)
297{
298 if (val < min)
299 val = min;
300
301 if (val > max)
302 val = max;
303
304 return (val - min) / step;
305}
306
307static unsigned int as3645a_current_to_reg(struct as3645a *flash, bool is_flash,
308 unsigned int ua)
309{
310 if (is_flash)
311 return __as3645a_current_to_reg(AS_TORCH_INTENSITY_MIN,
312 flash->cfg.assist_max_ua,
313 AS_TORCH_INTENSITY_STEP, ua);
314 else
315 return __as3645a_current_to_reg(AS_FLASH_INTENSITY_MIN,
316 flash->cfg.flash_max_ua,
317 AS_FLASH_INTENSITY_STEP, ua);
318}
319
320static int as3645a_set_indicator_brightness(struct led_classdev *iled_cdev,
321 enum led_brightness brightness)
322{
323 struct as3645a *flash = iled_cdev_to_as3645a(iled_cdev);
324 int rval;
325
326 flash->indicator_current = brightness;
327
328 rval = as3645a_set_timeout(flash);
329 if (rval)
330 return rval;
331
332 return as3645a_set_control(flash, AS_MODE_INDICATOR, brightness);
333}
334
335static int as3645a_set_assist_brightness(struct led_classdev *fled_cdev,
336 enum led_brightness brightness)
337{
338 struct led_classdev_flash *fled = lcdev_to_flcdev(fled_cdev);
339 struct as3645a *flash = fled_to_as3645a(fled);
340 int rval;
341
342 if (brightness) {
343 /* Register value 0 is 20 mA. */
344 flash->assist_current = brightness - 1;
345
346 rval = as3645a_set_current(flash);
347 if (rval)
348 return rval;
349 }
350
351 return as3645a_set_control(flash, AS_MODE_ASSIST, brightness);
352}
353
354static int as3645a_set_flash_brightness(struct led_classdev_flash *fled,
355 u32 brightness_ua)
356{
357 struct as3645a *flash = fled_to_as3645a(fled);
358
359 flash->flash_current = as3645a_current_to_reg(flash, true, brightness_ua);
360
361 return as3645a_set_current(flash);
362}
363
364static int as3645a_set_flash_timeout(struct led_classdev_flash *fled,
365 u32 timeout_us)
366{
367 struct as3645a *flash = fled_to_as3645a(fled);
368
369 flash->timeout = AS_TIMER_US_TO_CODE(timeout_us);
370
371 return as3645a_set_timeout(flash);
372}
373
374static int as3645a_set_strobe(struct led_classdev_flash *fled, bool state)
375{
376 struct as3645a *flash = fled_to_as3645a(fled);
377
378 return as3645a_set_control(flash, AS_MODE_FLASH, state);
379}
380
381static const struct led_flash_ops as3645a_led_flash_ops = {
382 .flash_brightness_set = as3645a_set_flash_brightness,
383 .timeout_set = as3645a_set_flash_timeout,
384 .strobe_set = as3645a_set_strobe,
385 .fault_get = as3645a_get_fault,
386};
387
388static int as3645a_setup(struct as3645a *flash)
389{
390 struct device *dev = &flash->client->dev;
391 u32 fault = 0;
392 int rval;
393
394 /* clear errors */
395 rval = as3645a_read(flash, AS_FAULT_INFO_REG);
396 if (rval < 0)
397 return rval;
398
399 dev_dbg(dev, "Fault info: %02x\n", rval);
400
401 rval = as3645a_set_current(flash);
402 if (rval < 0)
403 return rval;
404
405 rval = as3645a_set_timeout(flash);
406 if (rval < 0)
407 return rval;
408
409 rval = as3645a_set_control(flash, AS_MODE_INDICATOR, false);
410 if (rval < 0)
411 return rval;
412
413 /* read status */
414 rval = as3645a_get_fault(&flash->fled, &fault);
415 if (rval < 0)
416 return rval;
417
418 dev_dbg(dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n",
419 as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG));
420 dev_dbg(dev, "AS_CURRENT_SET_REG: %02x\n",
421 as3645a_read(flash, AS_CURRENT_SET_REG));
422 dev_dbg(dev, "AS_CONTROL_REG: %02x\n",
423 as3645a_read(flash, AS_CONTROL_REG));
424
425 return rval & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0;
426}
427
428static int as3645a_detect(struct as3645a *flash)
429{
430 struct device *dev = &flash->client->dev;
431 int rval, man, model, rfu, version;
432 const char *vendor;
433
434 rval = as3645a_read(flash, AS_DESIGN_INFO_REG);
435 if (rval < 0) {
436 dev_err(dev, "can't read design info reg\n");
437 return rval;
438 }
439
440 man = AS_DESIGN_INFO_FACTORY(rval);
441 model = AS_DESIGN_INFO_MODEL(rval);
442
443 rval = as3645a_read(flash, AS_VERSION_CONTROL_REG);
444 if (rval < 0) {
445 dev_err(dev, "can't read version control reg\n");
446 return rval;
447 }
448
449 rfu = AS_VERSION_CONTROL_RFU(rval);
450 version = AS_VERSION_CONTROL_VERSION(rval);
451
452 /* Verify the chip model and version. */
453 if (model != 0x01 || rfu != 0x00) {
454 dev_err(dev, "AS3645A not detected "
455 "(model %d rfu %d)\n", model, rfu);
456 return -ENODEV;
457 }
458
459 switch (man) {
460 case 1:
461 vendor = "AMS, Austria Micro Systems";
462 break;
463 case 2:
464 vendor = "ADI, Analog Devices Inc.";
465 break;
466 case 3:
467 vendor = "NSC, National Semiconductor";
468 break;
469 case 4:
470 vendor = "NXP";
471 break;
472 case 5:
473 vendor = "TI, Texas Instrument";
474 break;
475 default:
476 vendor = "Unknown";
477 }
478
479 dev_info(dev, "Chip vendor: %s (%d) Version: %d\n", vendor,
480 man, version);
481
482 rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE);
483 if (rval < 0)
484 return rval;
485
486 return as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE);
487}
488
489static int as3645a_parse_node(struct as3645a *flash,
490 struct as3645a_names *names,
491 struct device_node *node)
492{
493 struct as3645a_config *cfg = &flash->cfg;
494 const char *name;
495 int rval;
496
497 flash->flash_node = of_get_child_by_name(node, "flash");
498 if (!flash->flash_node) {
499 dev_err(&flash->client->dev, "can't find flash node\n");
500 return -ENODEV;
501 }
502
503 rval = of_property_read_string(flash->flash_node, "label", &name);
504 if (!rval)
505 strlcpy(names->flash, name, sizeof(names->flash));
506 else
507 snprintf(names->flash, sizeof(names->flash),
508 "%s:flash", node->name);
509
510 rval = of_property_read_u32(flash->flash_node, "flash-timeout-us",
511 &cfg->flash_timeout_us);
512 if (rval < 0) {
513 dev_err(&flash->client->dev,
514 "can't read flash-timeout-us property for flash\n");
515 goto out_err;
516 }
517
518 rval = of_property_read_u32(flash->flash_node, "flash-max-microamp",
519 &cfg->flash_max_ua);
520 if (rval < 0) {
521 dev_err(&flash->client->dev,
522 "can't read flash-max-microamp property for flash\n");
523 goto out_err;
524 }
525
526 rval = of_property_read_u32(flash->flash_node, "led-max-microamp",
527 &cfg->assist_max_ua);
528 if (rval < 0) {
529 dev_err(&flash->client->dev,
530 "can't read led-max-microamp property for flash\n");
531 goto out_err;
532 }
533
534 of_property_read_u32(flash->flash_node, "voltage-reference",
535 &cfg->voltage_reference);
536
537 of_property_read_u32(flash->flash_node, "peak-current-limit",
538 &cfg->peak);
539 cfg->peak = AS_PEAK_mA_TO_REG(cfg->peak);
540
541 flash->indicator_node = of_get_child_by_name(node, "indicator");
542 if (!flash->indicator_node) {
543 dev_warn(&flash->client->dev,
544 "can't find indicator node\n");
545 goto out_err;
546 }
547
548 rval = of_property_read_string(flash->indicator_node, "label", &name);
549 if (!rval)
550 strlcpy(names->indicator, name, sizeof(names->indicator));
551 else
552 snprintf(names->indicator, sizeof(names->indicator),
553 "%s:indicator", node->name);
554
555 rval = of_property_read_u32(flash->indicator_node, "led-max-microamp",
556 &cfg->indicator_max_ua);
557 if (rval < 0) {
558 dev_err(&flash->client->dev,
559 "can't read led-max-microamp property for indicator\n");
560 goto out_err;
561 }
562
563 return 0;
564
565out_err:
566 of_node_put(flash->flash_node);
567 of_node_put(flash->indicator_node);
568
569 return rval;
570}
571
572static int as3645a_led_class_setup(struct as3645a *flash,
573 struct as3645a_names *names)
574{
575 struct led_classdev *fled_cdev = &flash->fled.led_cdev;
576 struct led_classdev *iled_cdev = &flash->iled_cdev;
577 struct led_flash_setting *cfg;
578 int rval;
579
580 iled_cdev->name = names->indicator;
581 iled_cdev->brightness_set_blocking = as3645a_set_indicator_brightness;
582 iled_cdev->max_brightness =
583 flash->cfg.indicator_max_ua / AS_INDICATOR_INTENSITY_STEP;
584 iled_cdev->flags = LED_CORE_SUSPENDRESUME;
585
586 rval = led_classdev_register(&flash->client->dev, iled_cdev);
587 if (rval < 0)
588 return rval;
589
590 cfg = &flash->fled.brightness;
591 cfg->min = AS_FLASH_INTENSITY_MIN;
592 cfg->max = flash->cfg.flash_max_ua;
593 cfg->step = AS_FLASH_INTENSITY_STEP;
594 cfg->val = flash->cfg.flash_max_ua;
595
596 cfg = &flash->fled.timeout;
597 cfg->min = AS_FLASH_TIMEOUT_MIN;
598 cfg->max = flash->cfg.flash_timeout_us;
599 cfg->step = AS_FLASH_TIMEOUT_STEP;
600 cfg->val = flash->cfg.flash_timeout_us;
601
602 flash->fled.ops = &as3645a_led_flash_ops;
603
604 fled_cdev->name = names->flash;
605 fled_cdev->brightness_set_blocking = as3645a_set_assist_brightness;
606 /* Value 0 is off in LED class. */
607 fled_cdev->max_brightness =
608 as3645a_current_to_reg(flash, false,
609 flash->cfg.assist_max_ua) + 1;
610 fled_cdev->flags = LED_DEV_CAP_FLASH | LED_CORE_SUSPENDRESUME;
611
612 rval = led_classdev_flash_register(&flash->client->dev, &flash->fled);
613 if (rval) {
614 led_classdev_unregister(iled_cdev);
615 dev_err(&flash->client->dev,
616 "led_classdev_flash_register() failed, error %d\n",
617 rval);
618 }
619
620 return rval;
621}
622
623static int as3645a_v4l2_setup(struct as3645a *flash)
624{
625 struct led_classdev_flash *fled = &flash->fled;
626 struct led_classdev *led = &fled->led_cdev;
627 struct v4l2_flash_config cfg = {
628 .intensity = {
629 .min = AS_TORCH_INTENSITY_MIN,
630 .max = flash->cfg.assist_max_ua,
631 .step = AS_TORCH_INTENSITY_STEP,
632 .val = flash->cfg.assist_max_ua,
633 },
634 };
635 struct v4l2_flash_config cfgind = {
636 .intensity = {
637 .min = AS_INDICATOR_INTENSITY_MIN,
638 .max = flash->cfg.indicator_max_ua,
639 .step = AS_INDICATOR_INTENSITY_STEP,
640 .val = flash->cfg.indicator_max_ua,
641 },
642 };
643
644 strlcpy(cfg.dev_name, led->name, sizeof(cfg.dev_name));
645 strlcpy(cfgind.dev_name, flash->iled_cdev.name, sizeof(cfg.dev_name));
646
647 flash->vf = v4l2_flash_init(
648 &flash->client->dev, of_fwnode_handle(flash->flash_node),
649 &flash->fled, NULL, &cfg);
650 if (IS_ERR(flash->vf))
651 return PTR_ERR(flash->vf);
652
653 flash->vfind = v4l2_flash_indicator_init(
654 &flash->client->dev, of_fwnode_handle(flash->indicator_node),
655 &flash->iled_cdev, &cfgind);
656 if (IS_ERR(flash->vfind)) {
657 v4l2_flash_release(flash->vf);
658 return PTR_ERR(flash->vfind);
659 }
660
661 return 0;
662}
663
664static int as3645a_probe(struct i2c_client *client)
665{
666 struct as3645a_names names;
667 struct as3645a *flash;
668 int rval;
669
670 if (client->dev.of_node == NULL)
671 return -ENODEV;
672
673 flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL);
674 if (flash == NULL)
675 return -ENOMEM;
676
677 flash->client = client;
678
679 rval = as3645a_parse_node(flash, &names, client->dev.of_node);
680 if (rval < 0)
681 return rval;
682
683 rval = as3645a_detect(flash);
684 if (rval < 0)
685 goto out_put_nodes;
686
687 mutex_init(&flash->mutex);
688 i2c_set_clientdata(client, flash);
689
690 rval = as3645a_setup(flash);
691 if (rval)
692 goto out_mutex_destroy;
693
694 rval = as3645a_led_class_setup(flash, &names);
695 if (rval)
696 goto out_mutex_destroy;
697
698 rval = as3645a_v4l2_setup(flash);
699 if (rval)
700 goto out_led_classdev_flash_unregister;
701
702 return 0;
703
704out_led_classdev_flash_unregister:
705 led_classdev_flash_unregister(&flash->fled);
706
707out_mutex_destroy:
708 mutex_destroy(&flash->mutex);
709
710out_put_nodes:
711 of_node_put(flash->flash_node);
712 of_node_put(flash->indicator_node);
713
714 return rval;
715}
716
717static int as3645a_remove(struct i2c_client *client)
718{
719 struct as3645a *flash = i2c_get_clientdata(client);
720
721 as3645a_set_control(flash, AS_MODE_EXT_TORCH, false);
722
723 v4l2_flash_release(flash->vf);
724
725 led_classdev_flash_unregister(&flash->fled);
726 led_classdev_unregister(&flash->iled_cdev);
727
728 mutex_destroy(&flash->mutex);
729
730 of_node_put(flash->flash_node);
731 of_node_put(flash->indicator_node);
732
733 return 0;
734}
735
736static const struct i2c_device_id as3645a_id_table[] = {
737 { AS_NAME, 0 },
738 { },
739};
740MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
741
742static const struct of_device_id as3645a_of_table[] = {
743 { .compatible = "ams,as3645a" },
744 { },
745};
746MODULE_DEVICE_TABLE(of, as3645a_of_table);
747
748static struct i2c_driver as3645a_i2c_driver = {
749 .driver = {
750 .of_match_table = as3645a_of_table,
751 .name = AS_NAME,
752 },
753 .probe_new = as3645a_probe,
754 .remove = as3645a_remove,
755 .id_table = as3645a_id_table,
756};
757
758module_i2c_driver(as3645a_i2c_driver);
759
760MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
761MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>");
762MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
763MODULE_LICENSE("GPL v2");