2 * Copyright (C) 2010 Motorola, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 #include <linux/delay.h>
20 #include <linux/i2c.h>
21 #include <linux/leds.h>
22 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/types.h>
25 #include <linux/err.h>
27 #include <linux/led-lm3559.h>
31 #define LM3559_ALLOWED_R_BYTES 1
32 #define LM3559_ALLOWED_W_BYTES 2
33 #define LM3559_MAX_RW_RETRIES 5
34 #define LM3559_I2C_RETRY_DELAY 10
35 #define LM3559_TORCH_STEP 64
36 #define LM3559_STROBE_STEP 16
37 #define LM3559_PRIVACY_STEP 32
38 #define LM3559_RGB_STEP 32
40 #define LM3559_ENABLE_REG 0x10
41 #define LM3559_PRIVACY_REG 0x11
42 #define LM3559_MSG_IND_REG 0x12
43 #define LM3559_MSG_BLINK_REG 0x13
44 #define LM3559_PWM_REG 0x14
45 #define LM3559_GPIO_REG 0x20
46 #define LM3559_VLED_MON_REG 0x30
47 #define LM3559_ADC_DELAY_REG 0x31
48 #define LM3559_VIN_MONITOR 0x80
49 #define LM3559_LAST_FLASH 0x81
50 #define LM3559_TORCH_BRIGHTNESS 0xA0
51 #define LM3559_FLASH_BRIGHTNESS 0xB0
52 #define LM3559_FLASH_DURATION 0xC0
53 #define LM3559_FLAG_REG 0xD0
54 #define LM3559_CONFIG_REG_1 0xE0
55 #define LM3559_CONFIG_REG_2 0xF0
58 #define LED_FAULT 0x04
59 #define THERMAL_SHUTDOWN 0x02
60 #define TX1_INTERRUPT_FAULT 0x08
61 #define THERMAL_MONITOR_FAULT 0x20
62 #define VOLTAGE_MONITOR_FAULT 0x80
65 struct i2c_client *client;
66 struct lm3559_platform_data *pdata;
67 struct led_classdev flash_dev;
68 struct led_classdev torch_dev;
76 { "ENABLE", LM3559_ENABLE_REG},
77 { "PRIVACY", LM3559_PRIVACY_REG},
78 { "MSG_IND", LM3559_MSG_IND_REG},
79 { "MSG_BLINK", LM3559_MSG_BLINK_REG},
80 { "PRIVACY_PWM", LM3559_PWM_REG},
81 { "GPIO", LM3559_GPIO_REG},
82 { "VLED_MON", LM3559_VLED_MON_REG},
83 { "ADC_DELAY", LM3559_ADC_DELAY_REG},
84 { "VIN_MONITOR", LM3559_VIN_MONITOR},
85 { "LAST_FLASH", LM3559_LAST_FLASH},
86 { "TORCH_BRIGHTNESS", LM3559_TORCH_BRIGHTNESS},
87 { "FLASH_BRIGHTNESS", LM3559_FLASH_BRIGHTNESS},
88 { "FLASH_DURATION", LM3559_FLASH_DURATION},
89 { "FLAG", LM3559_FLAG_REG},
90 { "CONFIG_REG_1", LM3559_CONFIG_REG_1},
91 { "CONFIG_REG_2", LM3559_CONFIG_REG_2},
95 static uint32_t lm3559_debug;
96 module_param_named(flash_debug, lm3559_debug, uint, 0664);
98 static int lm3559_read_reg(struct lm3559_data *torch_data,
99 uint8_t reg, uint8_t* val)
106 pr_err("%s: invalid value pointer\n", __func__);
109 /* If I2C client doesn't exist */
110 if (torch_data->client == NULL) {
111 pr_err("%s: null i2c client\n", __func__);
117 err = i2c_master_send(torch_data->client, &dest_buffer,
118 LM3559_ALLOWED_R_BYTES);
119 if (err == LM3559_ALLOWED_R_BYTES)
120 err = i2c_master_recv(torch_data->client, val,
121 LM3559_ALLOWED_R_BYTES);
122 if (err != LM3559_ALLOWED_R_BYTES)
123 msleep_interruptible(LM3559_I2C_RETRY_DELAY);
124 } while ((err != LM3559_ALLOWED_R_BYTES) &&
125 ((++i) < LM3559_MAX_RW_RETRIES));
127 if (err != LM3559_ALLOWED_R_BYTES)
133 static int lm3559_write_reg(struct lm3559_data *torch_data,
134 uint8_t reg, uint8_t val)
138 uint8_t buf[LM3559_ALLOWED_W_BYTES] = { reg, val };
140 /* If I2C client doesn't exist */
141 if (torch_data->client == NULL) {
142 pr_err("%s: null i2c client\n", __func__);
147 bytes = i2c_master_send(torch_data->client, buf,
148 LM3559_ALLOWED_W_BYTES);
150 if (bytes != LM3559_ALLOWED_W_BYTES)
151 msleep_interruptible(LM3559_I2C_RETRY_DELAY);
152 } while ((bytes != LM3559_ALLOWED_W_BYTES) &&
153 ((++i) < LM3559_MAX_RW_RETRIES));
155 if (bytes != LM3559_ALLOWED_W_BYTES) {
156 pr_err("%s: i2c_master_send error\n", __func__);
164 static ssize_t ld_lm3559_registers_show(struct device *dev,
165 struct device_attribute *attr, char *buf)
167 struct i2c_client *client = container_of(dev->parent, struct i2c_client,
169 struct lm3559_data *flash_data = i2c_get_clientdata(client);
170 unsigned i, n, reg_count;
173 reg_count = sizeof(lm3559_regs) / sizeof(lm3559_regs[0]);
174 for (i = 0, n = 0; i < reg_count; i++) {
175 lm3559_read_reg(flash_data, lm3559_regs[i].reg, &value);
176 n += scnprintf(buf + n, PAGE_SIZE - n,
185 static ssize_t ld_lm3559_registers_store(struct device *dev,
186 struct device_attribute *attr,
187 const char *buf, size_t count)
189 struct i2c_client *client = container_of(dev->parent,
190 struct i2c_client, dev);
191 struct lm3559_data *flash_data = i2c_get_clientdata(client);
192 unsigned i, reg_count, value;
197 pr_err("%s:input too long\n", __func__);
201 if (sscanf(buf, "%s %x", name, &value) != 2) {
202 pr_err("%s:unable to parse input\n", __func__);
206 reg_count = sizeof(lm3559_regs) / sizeof(lm3559_regs[0]);
207 for (i = 0; i < reg_count; i++) {
208 if (!strcmp(name, lm3559_regs[i].name)) {
209 error = lm3559_write_reg(flash_data,
213 pr_err("%s:Failed to write register %s\n",
221 pr_err("%s:no such register %s\n", __func__, name);
224 static DEVICE_ATTR(registers, 0644, ld_lm3559_registers_show,
225 ld_lm3559_registers_store);
228 int lm3559_init_registers(struct lm3559_data *torch_data)
230 if (lm3559_write_reg(torch_data, LM3559_TORCH_BRIGHTNESS, 0) ||
231 lm3559_write_reg(torch_data, LM3559_ADC_DELAY_REG, 0) ||
232 lm3559_write_reg(torch_data, LM3559_FLASH_BRIGHTNESS, 0) ||
233 lm3559_write_reg(torch_data, LM3559_FLASH_DURATION,
234 torch_data->pdata->flash_duration_def) ||
235 lm3559_write_reg(torch_data, LM3559_CONFIG_REG_1, 0x6C) ||
236 lm3559_write_reg(torch_data, LM3559_CONFIG_REG_2, 0) ||
237 lm3559_write_reg(torch_data, LM3559_VIN_MONITOR,
238 torch_data->pdata->vin_monitor_def) ||
239 lm3559_write_reg(torch_data, LM3559_GPIO_REG, 0) ||
240 lm3559_write_reg(torch_data, LM3559_FLAG_REG, 0) ||
241 lm3559_write_reg(torch_data, LM3559_PRIVACY_REG, 0x10) ||
242 lm3559_write_reg(torch_data, LM3559_MSG_IND_REG, 0) ||
243 lm3559_write_reg(torch_data, LM3559_MSG_BLINK_REG, 0) ||
244 lm3559_write_reg(torch_data, LM3559_PWM_REG, 0) ||
245 lm3559_write_reg(torch_data, LM3559_ENABLE_REG, 0)) {
246 pr_err("%s:Register initialization failed\n", __func__);
252 static int lm3559_check_led_error(struct lm3559_data *torch_data) {
255 if (torch_data->pdata->flags & LM3559_FLAG_ERROR_CHECK) {
258 err = lm3559_read_reg(torch_data, LM3559_FLAG_REG, &err_flags);
260 pr_err("%s: Reading the status failed for %i\n",
265 if (err_flags & (VOLTAGE_MONITOR_FAULT |
266 THERMAL_MONITOR_FAULT |
269 pr_err("%s: Error indicated by the chip 0x%X\n",
270 __func__, err_flags);
278 static int lm3559_flash_prepare(struct lm3559_data *torch_data)
280 int err = lm3559_check_led_error(torch_data);
284 if (torch_data->flash_dev.brightness) {
285 uint8_t strobe_brightness;
286 uint val = torch_data->flash_dev.brightness - 1;
287 strobe_brightness = val | (val << 4);
289 err = lm3559_write_reg(torch_data, LM3559_FLASH_BRIGHTNESS,
292 pr_err("%s: Writing to 0x%X failed %i\n",
293 __func__, LM3559_FLASH_BRIGHTNESS, err);
297 err = lm3559_write_reg(torch_data, LM3559_FLASH_DURATION,
298 torch_data->pdata->flash_duration_def);
300 pr_err("%s: Writing to 0x%X failed %i\n",
301 __func__, LM3559_FLASH_DURATION, err);
305 err = lm3559_write_reg(torch_data, LM3559_VIN_MONITOR,
306 torch_data->pdata->vin_monitor_def);
308 pr_err("%s: Writing to 0x%X failed %i\n",
309 __func__, LM3559_VIN_MONITOR, err);
313 /* setup flash for trigger by strobe pin:
314 enable LED1 and LED2, but do not enable current */
315 err = lm3559_write_reg(torch_data, LM3559_ENABLE_REG, 0x18);
318 /* disable LED1 and LED2 and current */
319 err = lm3559_write_reg(torch_data, LM3559_ENABLE_REG, 0);
323 pr_err("%s: Writing to 0x%X failed %i\n",
324 __func__, LM3559_ENABLE_REG, err);
329 static int lm3559_torch_enable(struct lm3559_data *torch_data)
331 int err = lm3559_check_led_error(torch_data);
335 if (torch_data->torch_dev.brightness) {
336 uint8_t torch_brightness;
337 uint val = (torch_data->torch_dev.brightness - 1) & 0x3F;
338 torch_brightness = val | (val << 3);
340 err = lm3559_write_reg(torch_data, LM3559_TORCH_BRIGHTNESS,
343 pr_err("%s: Writing to 0x%X failed %i\n",
344 __func__, LM3559_TORCH_BRIGHTNESS, err);
348 err = lm3559_write_reg(torch_data, LM3559_VIN_MONITOR,
349 torch_data->pdata->vin_monitor_def);
351 pr_err("%s: Writing to 0x%X failed %i\n",
352 __func__, LM3559_VIN_MONITOR, err);
356 /* enable LED1 and LED2, enable current */
357 err = lm3559_write_reg(torch_data, LM3559_ENABLE_REG, 0x1A);
360 /* disable LED1 and LED2 and current */
361 err = lm3559_write_reg(torch_data, LM3559_ENABLE_REG, 0);
367 static void lm3559_flash_brightness_set(struct led_classdev *led_cdev,
368 enum led_brightness value)
370 struct lm3559_data *torch_data =
371 container_of(led_cdev, struct lm3559_data, flash_dev);
372 lm3559_flash_prepare(torch_data);
375 static void lm3559_torch_brightness_set(struct led_classdev *led_cdev,
376 enum led_brightness value)
378 struct lm3559_data *torch_data =
379 container_of(led_cdev, struct lm3559_data, torch_dev);
380 lm3559_torch_enable(torch_data);
383 static int lm3559_remove(struct i2c_client *client)
385 struct lm3559_data *torch_data = i2c_get_clientdata(client);
389 if (!IS_ERR_OR_NULL(torch_data->torch_dev.dev)) {
391 device_remove_file(torch_data->torch_dev.dev,
392 &dev_attr_registers);
394 led_classdev_unregister(&torch_data->torch_dev);
397 if (!IS_ERR_OR_NULL(torch_data->flash_dev.dev)) {
399 device_remove_file(torch_data->flash_dev.dev,
400 &dev_attr_registers);
402 led_classdev_unregister(&torch_data->flash_dev);
410 static int lm3559_probe(struct i2c_client *client,
411 const struct i2c_device_id *id)
413 struct lm3559_platform_data *pdata = client->dev.platform_data;
414 struct lm3559_data *torch_data;
418 dev_err(&client->dev, "platform data is NULL. exiting.\n");
422 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
423 dev_err(&client->dev, "client not i2c capable\n");
427 torch_data = kzalloc(sizeof(struct lm3559_data), GFP_KERNEL);
428 if (torch_data == NULL) {
429 dev_err(&client->dev, "kzalloc failed\n");
433 torch_data->client = client;
434 torch_data->pdata = pdata;
436 i2c_set_clientdata(client, torch_data);
438 err = lm3559_init_registers(torch_data);
442 torch_data->flash_dev.name = "flash";
443 torch_data->flash_dev.brightness_set = lm3559_flash_brightness_set;
444 torch_data->flash_dev.brightness = LED_OFF;
445 torch_data->flash_dev.max_brightness = LED_FULL;
446 err = led_classdev_register((struct device *)
447 &client->dev, &torch_data->flash_dev);
449 pr_err("%s: Register flash led class failed: %d\n",
455 err = device_create_file(torch_data->flash_dev.dev,
456 &dev_attr_registers);
458 pr_err("%s:File device creation failed: %d\n", __func__, err);
461 torch_data->torch_dev.name = "torch";
462 torch_data->torch_dev.brightness_set = lm3559_torch_brightness_set;
463 torch_data->torch_dev.brightness = LED_OFF;
464 torch_data->torch_dev.max_brightness = LED_FULL;
465 err = led_classdev_register((struct device *)
466 &client->dev, &torch_data->torch_dev);
468 pr_err("%s: Register torch led class failed: %d\n",
474 err = device_create_file(torch_data->torch_dev.dev,
475 &dev_attr_registers);
477 pr_err("%s:File device creation failed: %d\n", __func__, err);
482 lm3559_remove(client);
486 static const struct i2c_device_id lm3559_id[] = {
491 static struct i2c_driver lm3559_i2c_driver = {
492 .probe = lm3559_probe,
493 .remove = lm3559_remove,
494 .id_table = lm3559_id,
497 .owner = THIS_MODULE,
501 static int __init lm3559_init(void)
503 return i2c_add_driver(&lm3559_i2c_driver);
506 static void lm3559_exit(void)
508 i2c_del_driver(&lm3559_i2c_driver);
511 module_init(lm3559_init);
512 module_exit(lm3559_exit);
514 /****************************************************************************/
516 MODULE_DESCRIPTION("Lighting driver for LM3559");
517 MODULE_AUTHOR("MOTOROLA");
518 MODULE_LICENSE("GPL");