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/leds-lp8550.h>
24 #include <linux/slab.h>
25 #include <linux/types.h>
29 #define LD_LP8550_ON_OFF_MASK 0xFE
31 #define LD_LP8550_ALLOWED_R_BYTES 1
32 #define LD_LP8550_ALLOWED_W_BYTES 2
33 #define LD_LP8550_MAX_RW_RETRIES 5
34 #define LD_LP8550_I2C_RETRY_DELAY 10
36 #define LP8550_BRIGHTNESS_CTRL 0x00
37 #define LP8550_DEVICE_CTRL 0x01
38 #define LP8550_FAULT 0x02
39 #define LP8550_CHIP_ID 0x03
40 #define LP8550_DIRECT_CTRL 0x04
41 #define LP8550_TEMP_MSB 0x05
42 #define LP8550_TEMP_LSB 0x06
44 /* EEPROM Register address */
45 #define LP8550_EEPROM_CTRL 0x72
46 #define LP8550_EEPROM_A0 0xa0
47 #define LP8550_EEPROM_A1 0xa1
48 #define LP8550_EEPROM_A2 0xa2
49 #define LP8550_EEPROM_A3 0xa3
50 #define LP8550_EEPROM_A4 0xa4
51 #define LP8550_EEPROM_A5 0xa5
52 #define LP8550_EEPROM_A6 0xa6
53 #define LP8550_EEPROM_A7 0xa7
57 struct led_classdev led_dev;
58 struct i2c_client *client;
59 struct work_struct wq;
60 struct lp8550_platform_data *led_pdata;
61 uint8_t last_requested_brightness;
70 { "BRIGHTNESS_CTRL", LP8550_BRIGHTNESS_CTRL },
71 { "DEV_CTRL", LP8550_DEVICE_CTRL },
72 { "FAULT", LP8550_FAULT },
73 { "CHIP_ID", LP8550_CHIP_ID },
74 { "DIRECT_CTRL", LP8550_DIRECT_CTRL },
75 { "EEPROM_CTRL", LP8550_EEPROM_CTRL },
76 { "EEPROM_A0", LP8550_EEPROM_A0 },
77 { "EEPROM_A1", LP8550_EEPROM_A1 },
78 { "EEPROM_A2", LP8550_EEPROM_A2 },
79 { "EEPROM_A3", LP8550_EEPROM_A3 },
80 { "EEPROM_A4", LP8550_EEPROM_A4 },
81 { "EEPROM_A5", LP8550_EEPROM_A5 },
82 { "EEPROM_A6", LP8550_EEPROM_A6 },
83 { "EEPROM_A7", LP8550_EEPROM_A7 },
87 static uint32_t lp8550_debug;
88 module_param_named(als_debug, lp8550_debug, uint, 0664);
89 static void lp8550_brightness_write(struct lp8550_data *led_data);
91 static int lp8550_read_reg(struct lp8550_data *led_data, uint8_t reg,
99 pr_err("%s: invalid value pointer\n", __func__);
104 error = i2c_master_send(led_data->client, &dest_buffer, 1);
106 error = i2c_master_recv(led_data->client,
107 &dest_buffer, LD_LP8550_ALLOWED_R_BYTES);
109 if (error != LD_LP8550_ALLOWED_R_BYTES) {
110 pr_err("%s: read[%i] failed: %d\n", __func__, i, error);
111 msleep(LD_LP8550_I2C_RETRY_DELAY);
113 } while ((error != LD_LP8550_ALLOWED_R_BYTES) &&
114 ((++i) < LD_LP8550_MAX_RW_RETRIES));
116 if (error == LD_LP8550_ALLOWED_R_BYTES) {
118 *value = dest_buffer;
124 static int lp8550_write_reg(struct lp8550_data *led_data, uint8_t reg,
127 uint8_t buf[LD_LP8550_ALLOWED_W_BYTES] = { reg, value };
132 bytes = i2c_master_send(led_data->client, buf,
133 LD_LP8550_ALLOWED_W_BYTES);
135 if (bytes != LD_LP8550_ALLOWED_W_BYTES) {
136 pr_err("%s: write %d failed: %d\n", __func__, i, bytes);
137 msleep(LD_LP8550_I2C_RETRY_DELAY);
139 } while ((bytes != (LD_LP8550_ALLOWED_W_BYTES))
140 && ((++i) < LD_LP8550_MAX_RW_RETRIES));
142 if (bytes != LD_LP8550_ALLOWED_W_BYTES) {
143 pr_err("%s: i2c_master_send error\n", __func__);
149 static int ld_lp8550_init_registers(struct lp8550_data *led_data)
151 unsigned i, n, reg_count, reg_addr;
154 /* Check the EEPROM values and update if neccessary */
156 reg_addr = LP8550_EEPROM_A0;
157 for (i = 0, n = 0; i < reg_count; i++) {
158 lp8550_read_reg(led_data, reg_addr, &value);
160 pr_info("%s:Register 0x%x value 0x%X\n", __func__,
162 if (value != led_data->led_pdata->eeprom_table[n].eeprom_data) {
164 pr_info("%s:Writing 0x%x to 0x%X\n", __func__,
165 led_data->led_pdata->eeprom_table[n].eeprom_data,
167 if (lp8550_write_reg(led_data, LP8550_DEVICE_CTRL,
169 pr_err("%s:Register initialization failed\n",
171 if (lp8550_write_reg(led_data, reg_addr,
172 led_data->led_pdata->eeprom_table[n].eeprom_data))
173 pr_err("%s:Register initialization failed\n",
175 if (lp8550_write_reg(led_data, LP8550_EEPROM_CTRL,
177 pr_err("%s:Register initialization failed\n",
179 if (lp8550_write_reg(led_data, LP8550_EEPROM_CTRL,
181 pr_err("%s:Register initialization failed\n",
184 if (lp8550_write_reg(led_data, LP8550_EEPROM_CTRL,
186 pr_err("%s:Register initialization failed\n",
193 if (lp8550_write_reg(led_data, LP8550_DEVICE_CTRL,
194 led_data->led_pdata->dev_ctrl_config)) {
195 pr_err("%s:Register initialization failed\n", __func__);
201 static void ld_lp8550_brightness_set(struct led_classdev *led_cdev,
202 enum led_brightness brightness)
204 struct lp8550_data *led_data =
205 container_of(led_cdev, struct lp8550_data, led_dev);
207 if (brightness > 255)
210 led_data->brightness = brightness;
211 schedule_work(&led_data->wq);
213 EXPORT_SYMBOL(ld_lp8550_brightness_set);
215 static void lp8550_brightness_work(struct work_struct *work)
217 struct lp8550_data *led_data =
218 container_of(work, struct lp8550_data, wq);
220 lp8550_brightness_write(led_data);
223 static void lp8550_brightness_write(struct lp8550_data *led_data)
226 int brightness = led_data->brightness;
229 pr_info("%s: setting brightness to %i\n",
230 __func__, brightness);
232 if (brightness == LED_OFF) {
233 if (lp8550_write_reg(led_data, LP8550_DEVICE_CTRL,
234 (led_data->led_pdata->dev_ctrl_config &
235 LD_LP8550_ON_OFF_MASK))) {
236 pr_err("%s:writing failed while setting brightness:%d\n",
240 if (lp8550_write_reg(led_data, LP8550_DEVICE_CTRL,
241 led_data->led_pdata->dev_ctrl_config | 0x01)) {
242 pr_err("%s:writing failed while setting brightness:%d\n",
245 if (lp8550_write_reg(led_data, LP8550_BRIGHTNESS_CTRL, brightness)) {
246 pr_err("%s:Failed to set brightness:%d\n",
249 led_data->last_requested_brightness = brightness;
254 static ssize_t ld_lp8550_registers_show(struct device *dev,
255 struct device_attribute *attr, char *buf)
257 struct i2c_client *client = container_of(dev->parent, struct i2c_client,
259 struct lp8550_data *led_data = i2c_get_clientdata(client);
260 unsigned i, n, reg_count;
263 reg_count = sizeof(lp8550_regs) / sizeof(lp8550_regs[0]);
264 for (i = 0, n = 0; i < reg_count; i++) {
265 lp8550_read_reg(led_data, lp8550_regs[i].reg, &value);
266 n += scnprintf(buf + n, PAGE_SIZE - n,
275 static ssize_t ld_lp8550_registers_store(struct device *dev,
276 struct device_attribute *attr,
277 const char *buf, size_t count)
279 struct i2c_client *client = container_of(dev->parent, struct i2c_client,
281 struct lp8550_data *led_data = i2c_get_clientdata(client);
282 unsigned i, reg_count, value;
287 pr_err("%s:input too long\n", __func__);
291 if (sscanf(buf, "%s %x", name, &value) != 2) {
292 pr_err("%s:unable to parse input\n", __func__);
296 reg_count = sizeof(lp8550_regs) / sizeof(lp8550_regs[0]);
297 for (i = 0; i < reg_count; i++) {
298 if (!strcmp(name, lp8550_regs[i].name)) {
299 error = lp8550_write_reg(led_data,
303 pr_err("%s:Failed to write register %s\n",
311 pr_err("%s:no such register %s\n", __func__, name);
314 static DEVICE_ATTR(registers, 0644, ld_lp8550_registers_show,
315 ld_lp8550_registers_store);
318 static int ld_lp8550_probe(struct i2c_client *client,
319 const struct i2c_device_id *id)
321 struct lp8550_platform_data *pdata = client->dev.platform_data;
322 struct lp8550_data *led_data;
326 pr_err("%s: platform data required\n", __func__);
328 } else if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
329 pr_err("%s:I2C_FUNC_I2C not supported\n", __func__);
333 led_data = kzalloc(sizeof(struct lp8550_data), GFP_KERNEL);
334 if (led_data == NULL) {
336 goto err_alloc_data_failed;
339 led_data->client = client;
341 led_data->led_dev.name = LD_LP8550_LED_DEV;
342 led_data->led_dev.brightness_set = ld_lp8550_brightness_set;
343 led_data->led_pdata = client->dev.platform_data;
345 i2c_set_clientdata(client, led_data);
347 error = ld_lp8550_init_registers(led_data);
349 pr_err("%s: Register Initialization failed: %d\n",
352 goto err_reg_init_failed;
355 error = lp8550_write_reg(led_data, LP8550_BRIGHTNESS_CTRL,
356 pdata->power_up_brightness);
358 pr_err("%s:Setting power up brightness failed %d\n",
361 goto err_reg_init_failed;
364 INIT_WORK(&led_data->wq, lp8550_brightness_work);
366 error = led_classdev_register((struct device *) &client->dev,
369 pr_err("%s: Register led class failed: %d\n", __func__, error);
371 goto err_class_reg_failed;
375 error = device_create_file(led_data->led_dev.dev, &dev_attr_registers);
377 pr_err("%s:File device creation failed: %d\n", __func__, error);
383 err_class_reg_failed:
386 err_alloc_data_failed:
390 static int ld_lp8550_remove(struct i2c_client *client)
392 struct lp8550_data *led_data = i2c_get_clientdata(client);
395 device_remove_file(led_data->led_dev.dev, &dev_attr_registers);
397 led_classdev_unregister(&led_data->led_dev);
402 static int lp8550_suspend(struct i2c_client *client, pm_message_t mesg)
404 struct lp8550_data *led_data = i2c_get_clientdata(client);
407 pr_info("%s: Suspending\n", __func__);
409 lp8550_write_reg(led_data, LP8550_DEVICE_CTRL,
410 led_data->led_pdata->dev_ctrl_config & LD_LP8550_ON_OFF_MASK);
415 static int lp8550_resume(struct i2c_client *client)
417 struct lp8550_data *led_data = i2c_get_clientdata(client);
420 pr_info("%s: Resuming with brightness %i\n",
421 __func__, led_data->brightness);
423 lp8550_brightness_write(led_data);
428 static const struct i2c_device_id lp8550_id[] = {
433 static struct i2c_driver ld_lp8550_i2c_driver = {
434 .probe = ld_lp8550_probe,
435 .remove = ld_lp8550_remove,
436 .suspend = lp8550_suspend,
437 .resume = lp8550_resume,
438 .id_table = lp8550_id,
440 .name = LD_LP8550_NAME,
441 .owner = THIS_MODULE,
445 static int __init ld_lp8550_init(void)
447 return i2c_add_driver(&ld_lp8550_i2c_driver);
450 static void __exit ld_lp8550_exit(void)
452 i2c_del_driver(&ld_lp8550_i2c_driver);
456 module_init(ld_lp8550_init);
457 module_exit(ld_lp8550_exit);
459 MODULE_DESCRIPTION("Lighting driver for LP8550");
460 MODULE_AUTHOR("Dan Murphy D.Murphy@Motorola.com");
461 MODULE_LICENSE("GPL");