leds-bd2802.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. /*
  2. * leds-bd2802.c - RGB LED Driver
  3. *
  4. * Copyright (C) 2009 Samsung Electronics
  5. * Kim Kyuwon <q1.kim@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
  12. *
  13. */
  14. #include <linux/module.h>
  15. #include <linux/i2c.h>
  16. #include <linux/gpio.h>
  17. #include <linux/delay.h>
  18. #include <linux/leds.h>
  19. #include <linux/leds-bd2802.h>
  20. #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
  21. #define BD2802_LED_OFFSET 0xa
  22. #define BD2802_COLOR_OFFSET 0x3
  23. #define BD2802_REG_CLKSETUP 0x00
  24. #define BD2802_REG_CONTROL 0x01
  25. #define BD2802_REG_HOURSETUP 0x02
  26. #define BD2802_REG_CURRENT1SETUP 0x03
  27. #define BD2802_REG_CURRENT2SETUP 0x04
  28. #define BD2802_REG_WAVEPATTERN 0x05
  29. #define BD2802_CURRENT_032 0x10 /* 3.2mA */
  30. #define BD2802_CURRENT_000 0x00 /* 0.0mA */
  31. #define BD2802_PATTERN_FULL 0x07
  32. #define BD2802_PATTERN_HALF 0x03
  33. enum led_ids {
  34. LED1,
  35. LED2,
  36. LED_NUM,
  37. };
  38. enum led_colors {
  39. RED,
  40. GREEN,
  41. BLUE,
  42. };
  43. enum led_bits {
  44. BD2802_OFF,
  45. BD2802_BLINK,
  46. BD2802_ON,
  47. };
  48. /*
  49. * State '0' : 'off'
  50. * State '1' : 'blink'
  51. * State '2' : 'on'.
  52. */
  53. struct led_state {
  54. unsigned r:2;
  55. unsigned g:2;
  56. unsigned b:2;
  57. };
  58. struct bd2802_led {
  59. struct bd2802_led_platform_data *pdata;
  60. struct i2c_client *client;
  61. struct rw_semaphore rwsem;
  62. struct work_struct work;
  63. struct led_state led[2];
  64. /*
  65. * Making led_classdev as array is not recommended, because array
  66. * members prevent using 'container_of' macro. So repetitive works
  67. * are needed.
  68. */
  69. struct led_classdev cdev_led1r;
  70. struct led_classdev cdev_led1g;
  71. struct led_classdev cdev_led1b;
  72. struct led_classdev cdev_led2r;
  73. struct led_classdev cdev_led2g;
  74. struct led_classdev cdev_led2b;
  75. /*
  76. * Advanced Configuration Function(ADF) mode:
  77. * In ADF mode, user can set registers of BD2802GU directly,
  78. * therefore BD2802GU doesn't enter reset state.
  79. */
  80. int adf_on;
  81. enum led_ids led_id;
  82. enum led_colors color;
  83. enum led_bits state;
  84. };
  85. /*--------------------------------------------------------------*/
  86. /* BD2802GU helper functions */
  87. /*--------------------------------------------------------------*/
  88. static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
  89. enum led_colors color)
  90. {
  91. switch (color) {
  92. case RED:
  93. return !led->led[id].r;
  94. case GREEN:
  95. return !led->led[id].g;
  96. case BLUE:
  97. return !led->led[id].b;
  98. default:
  99. dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
  100. return -EINVAL;
  101. }
  102. }
  103. static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
  104. {
  105. if (led->led[id].r || led->led[id].g || led->led[id].b)
  106. return 0;
  107. return 1;
  108. }
  109. static inline int bd2802_is_all_off(struct bd2802_led *led)
  110. {
  111. int i;
  112. for (i = 0; i < LED_NUM; i++)
  113. if (!bd2802_is_led_off(led, i))
  114. return 0;
  115. return 1;
  116. }
  117. static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
  118. {
  119. return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
  120. }
  121. static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
  122. u8 reg_offset)
  123. {
  124. return reg_offset + bd2802_get_base_offset(id, color);
  125. }
  126. /*--------------------------------------------------------------*/
  127. /* BD2802GU core functions */
  128. /*--------------------------------------------------------------*/
  129. static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
  130. {
  131. int ret = i2c_smbus_write_byte_data(client, reg, val);
  132. if (ret >= 0)
  133. return 0;
  134. dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
  135. __func__, reg, val, ret);
  136. return ret;
  137. }
  138. static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
  139. enum led_colors color, enum led_bits led_bit)
  140. {
  141. int i;
  142. u8 value;
  143. for (i = 0; i < LED_NUM; i++) {
  144. if (i == id) {
  145. switch (color) {
  146. case RED:
  147. led->led[i].r = led_bit;
  148. break;
  149. case GREEN:
  150. led->led[i].g = led_bit;
  151. break;
  152. case BLUE:
  153. led->led[i].b = led_bit;
  154. break;
  155. default:
  156. dev_err(&led->client->dev,
  157. "%s: Invalid color\n", __func__);
  158. return;
  159. }
  160. }
  161. }
  162. if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
  163. return;
  164. if (!bd2802_is_led_off(led, id))
  165. return;
  166. if (bd2802_is_all_off(led) && !led->adf_on) {
  167. gpio_set_value(led->pdata->reset_gpio, 0);
  168. return;
  169. }
  170. /*
  171. * In this case, other led is turned on, and current led is turned
  172. * off. So set RGB LED Control register to stop the current RGB LED
  173. */
  174. value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
  175. bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
  176. }
  177. static void bd2802_configure(struct bd2802_led *led)
  178. {
  179. struct bd2802_led_platform_data *pdata = led->pdata;
  180. u8 reg;
  181. reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
  182. bd2802_write_byte(led->client, reg, pdata->rgb_time);
  183. reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
  184. bd2802_write_byte(led->client, reg, pdata->rgb_time);
  185. }
  186. static void bd2802_reset_cancel(struct bd2802_led *led)
  187. {
  188. gpio_set_value(led->pdata->reset_gpio, 1);
  189. udelay(100);
  190. bd2802_configure(led);
  191. }
  192. static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
  193. {
  194. enum led_ids other_led = (id == LED1) ? LED2 : LED1;
  195. u8 value, other_led_on;
  196. other_led_on = !bd2802_is_led_off(led, other_led);
  197. if (id == LED1)
  198. value = LED_CTL(other_led_on, 1);
  199. else
  200. value = LED_CTL(1 , other_led_on);
  201. bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
  202. }
  203. static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
  204. enum led_colors color)
  205. {
  206. u8 reg;
  207. if (bd2802_is_all_off(led) && !led->adf_on)
  208. bd2802_reset_cancel(led);
  209. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
  210. bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
  211. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
  212. bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
  213. reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
  214. bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
  215. bd2802_enable(led, id);
  216. bd2802_update_state(led, id, color, BD2802_ON);
  217. }
  218. static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
  219. enum led_colors color)
  220. {
  221. u8 reg;
  222. if (bd2802_is_all_off(led) && !led->adf_on)
  223. bd2802_reset_cancel(led);
  224. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
  225. bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
  226. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
  227. bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
  228. reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
  229. bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
  230. bd2802_enable(led, id);
  231. bd2802_update_state(led, id, color, BD2802_BLINK);
  232. }
  233. static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
  234. enum led_colors color, enum led_bits led_bit)
  235. {
  236. if (led_bit == BD2802_OFF) {
  237. dev_err(&led->client->dev,
  238. "Only 'blink' and 'on' are allowed\n");
  239. return;
  240. }
  241. if (led_bit == BD2802_BLINK)
  242. bd2802_set_blink(led, id, color);
  243. else
  244. bd2802_set_on(led, id, color);
  245. }
  246. static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
  247. enum led_colors color)
  248. {
  249. u8 reg;
  250. if (bd2802_is_rgb_off(led, id, color))
  251. return;
  252. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
  253. bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
  254. reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
  255. bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
  256. bd2802_update_state(led, id, color, BD2802_OFF);
  257. }
  258. static void bd2802_restore_state(struct bd2802_led *led)
  259. {
  260. int i;
  261. for (i = 0; i < LED_NUM; i++) {
  262. if (led->led[i].r)
  263. bd2802_turn_on(led, i, RED, led->led[i].r);
  264. if (led->led[i].g)
  265. bd2802_turn_on(led, i, GREEN, led->led[i].g);
  266. if (led->led[i].b)
  267. bd2802_turn_on(led, i, BLUE, led->led[i].b);
  268. }
  269. }
  270. #define BD2802_SET_REGISTER(reg_addr, reg_name) \
  271. static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
  272. struct device_attribute *attr, const char *buf, size_t count) \
  273. { \
  274. struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
  275. unsigned long val; \
  276. int ret; \
  277. if (!count) \
  278. return -EINVAL; \
  279. ret = strict_strtoul(buf, 16, &val); \
  280. if (ret) \
  281. return ret; \
  282. down_write(&led->rwsem); \
  283. bd2802_write_byte(led->client, reg_addr, (u8) val); \
  284. up_write(&led->rwsem); \
  285. return count; \
  286. } \
  287. static struct device_attribute bd2802_reg##reg_addr##_attr = { \
  288. .attr = {.name = reg_name, .mode = 0644, .owner = THIS_MODULE}, \
  289. .store = bd2802_store_reg##reg_addr, \
  290. };
  291. BD2802_SET_REGISTER(0x00, "0x00");
  292. BD2802_SET_REGISTER(0x01, "0x01");
  293. BD2802_SET_REGISTER(0x02, "0x02");
  294. BD2802_SET_REGISTER(0x03, "0x03");
  295. BD2802_SET_REGISTER(0x04, "0x04");
  296. BD2802_SET_REGISTER(0x05, "0x05");
  297. BD2802_SET_REGISTER(0x06, "0x06");
  298. BD2802_SET_REGISTER(0x07, "0x07");
  299. BD2802_SET_REGISTER(0x08, "0x08");
  300. BD2802_SET_REGISTER(0x09, "0x09");
  301. BD2802_SET_REGISTER(0x0a, "0x0a");
  302. BD2802_SET_REGISTER(0x0b, "0x0b");
  303. BD2802_SET_REGISTER(0x0c, "0x0c");
  304. BD2802_SET_REGISTER(0x0d, "0x0d");
  305. BD2802_SET_REGISTER(0x0e, "0x0e");
  306. BD2802_SET_REGISTER(0x0f, "0x0f");
  307. BD2802_SET_REGISTER(0x10, "0x10");
  308. BD2802_SET_REGISTER(0x11, "0x11");
  309. BD2802_SET_REGISTER(0x12, "0x12");
  310. BD2802_SET_REGISTER(0x13, "0x13");
  311. BD2802_SET_REGISTER(0x14, "0x14");
  312. BD2802_SET_REGISTER(0x15, "0x15");
  313. static struct device_attribute *bd2802_addr_attributes[] = {
  314. &bd2802_reg0x00_attr,
  315. &bd2802_reg0x01_attr,
  316. &bd2802_reg0x02_attr,
  317. &bd2802_reg0x03_attr,
  318. &bd2802_reg0x04_attr,
  319. &bd2802_reg0x05_attr,
  320. &bd2802_reg0x06_attr,
  321. &bd2802_reg0x07_attr,
  322. &bd2802_reg0x08_attr,
  323. &bd2802_reg0x09_attr,
  324. &bd2802_reg0x0a_attr,
  325. &bd2802_reg0x0b_attr,
  326. &bd2802_reg0x0c_attr,
  327. &bd2802_reg0x0d_attr,
  328. &bd2802_reg0x0e_attr,
  329. &bd2802_reg0x0f_attr,
  330. &bd2802_reg0x10_attr,
  331. &bd2802_reg0x11_attr,
  332. &bd2802_reg0x12_attr,
  333. &bd2802_reg0x13_attr,
  334. &bd2802_reg0x14_attr,
  335. &bd2802_reg0x15_attr,
  336. };
  337. static void bd2802_enable_adv_conf(struct bd2802_led *led)
  338. {
  339. int i, ret;
  340. for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
  341. ret = device_create_file(&led->client->dev,
  342. bd2802_addr_attributes[i]);
  343. if (ret) {
  344. dev_err(&led->client->dev, "failed to sysfs file %s\n",
  345. bd2802_addr_attributes[i]->attr.name);
  346. goto failed_remove_files;
  347. }
  348. }
  349. if (bd2802_is_all_off(led))
  350. bd2802_reset_cancel(led);
  351. led->adf_on = 1;
  352. return;
  353. failed_remove_files:
  354. for (i--; i >= 0; i--)
  355. device_remove_file(&led->client->dev,
  356. bd2802_addr_attributes[i]);
  357. }
  358. static void bd2802_disable_adv_conf(struct bd2802_led *led)
  359. {
  360. int i;
  361. for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
  362. device_remove_file(&led->client->dev,
  363. bd2802_addr_attributes[i]);
  364. if (bd2802_is_all_off(led))
  365. gpio_set_value(led->pdata->reset_gpio, 0);
  366. led->adf_on = 0;
  367. }
  368. static ssize_t bd2802_show_adv_conf(struct device *dev,
  369. struct device_attribute *attr, char *buf)
  370. {
  371. struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
  372. ssize_t ret;
  373. down_read(&led->rwsem);
  374. if (led->adf_on)
  375. ret = sprintf(buf, "on\n");
  376. else
  377. ret = sprintf(buf, "off\n");
  378. up_read(&led->rwsem);
  379. return ret;
  380. }
  381. static ssize_t bd2802_store_adv_conf(struct device *dev,
  382. struct device_attribute *attr, const char *buf, size_t count)
  383. {
  384. struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
  385. if (!count)
  386. return -EINVAL;
  387. down_write(&led->rwsem);
  388. if (!led->adf_on && !strncmp(buf, "on", 2))
  389. bd2802_enable_adv_conf(led);
  390. else if (led->adf_on && !strncmp(buf, "off", 3))
  391. bd2802_disable_adv_conf(led);
  392. up_write(&led->rwsem);
  393. return count;
  394. }
  395. static struct device_attribute bd2802_adv_conf_attr = {
  396. .attr = {
  397. .name = "advanced_configuration",
  398. .mode = 0644,
  399. .owner = THIS_MODULE
  400. },
  401. .show = bd2802_show_adv_conf,
  402. .store = bd2802_store_adv_conf,
  403. };
  404. static void bd2802_led_work(struct work_struct *work)
  405. {
  406. struct bd2802_led *led = container_of(work, struct bd2802_led, work);
  407. if (led->state)
  408. bd2802_turn_on(led, led->led_id, led->color, led->state);
  409. else
  410. bd2802_turn_off(led, led->led_id, led->color);
  411. }
  412. #define BD2802_CONTROL_RGBS(name, id, clr) \
  413. static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
  414. enum led_brightness value) \
  415. { \
  416. struct bd2802_led *led = \
  417. container_of(led_cdev, struct bd2802_led, cdev_##name); \
  418. led->led_id = id; \
  419. led->color = clr; \
  420. if (value == LED_OFF) \
  421. led->state = BD2802_OFF; \
  422. else \
  423. led->state = BD2802_ON; \
  424. schedule_work(&led->work); \
  425. } \
  426. static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
  427. unsigned long *delay_on, unsigned long *delay_off) \
  428. { \
  429. struct bd2802_led *led = \
  430. container_of(led_cdev, struct bd2802_led, cdev_##name); \
  431. if (*delay_on == 0 || *delay_off == 0) \
  432. return -EINVAL; \
  433. led->led_id = id; \
  434. led->color = clr; \
  435. led->state = BD2802_BLINK; \
  436. schedule_work(&led->work); \
  437. return 0; \
  438. }
  439. BD2802_CONTROL_RGBS(led1r, LED1, RED);
  440. BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
  441. BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
  442. BD2802_CONTROL_RGBS(led2r, LED2, RED);
  443. BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
  444. BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
  445. static int bd2802_register_led_classdev(struct bd2802_led *led)
  446. {
  447. int ret;
  448. INIT_WORK(&led->work, bd2802_led_work);
  449. led->cdev_led1r.name = "led1_R";
  450. led->cdev_led1r.brightness = LED_OFF;
  451. led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
  452. led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
  453. led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
  454. ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
  455. if (ret < 0) {
  456. dev_err(&led->client->dev, "couldn't register LED %s\n",
  457. led->cdev_led1r.name);
  458. goto failed_unregister_led1_R;
  459. }
  460. led->cdev_led1g.name = "led1_G";
  461. led->cdev_led1g.brightness = LED_OFF;
  462. led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
  463. led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
  464. led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
  465. ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
  466. if (ret < 0) {
  467. dev_err(&led->client->dev, "couldn't register LED %s\n",
  468. led->cdev_led1g.name);
  469. goto failed_unregister_led1_G;
  470. }
  471. led->cdev_led1b.name = "led1_B";
  472. led->cdev_led1b.brightness = LED_OFF;
  473. led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
  474. led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
  475. led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
  476. ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
  477. if (ret < 0) {
  478. dev_err(&led->client->dev, "couldn't register LED %s\n",
  479. led->cdev_led1b.name);
  480. goto failed_unregister_led1_B;
  481. }
  482. led->cdev_led2r.name = "led2_R";
  483. led->cdev_led2r.brightness = LED_OFF;
  484. led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
  485. led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
  486. led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
  487. ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
  488. if (ret < 0) {
  489. dev_err(&led->client->dev, "couldn't register LED %s\n",
  490. led->cdev_led2r.name);
  491. goto failed_unregister_led2_R;
  492. }
  493. led->cdev_led2g.name = "led2_G";
  494. led->cdev_led2g.brightness = LED_OFF;
  495. led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
  496. led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
  497. led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
  498. ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
  499. if (ret < 0) {
  500. dev_err(&led->client->dev, "couldn't register LED %s\n",
  501. led->cdev_led2g.name);
  502. goto failed_unregister_led2_G;
  503. }
  504. led->cdev_led2b.name = "led2_B";
  505. led->cdev_led2b.brightness = LED_OFF;
  506. led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
  507. led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
  508. led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
  509. ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
  510. if (ret < 0) {
  511. dev_err(&led->client->dev, "couldn't register LED %s\n",
  512. led->cdev_led2b.name);
  513. goto failed_unregister_led2_B;
  514. }
  515. return 0;
  516. failed_unregister_led2_B:
  517. led_classdev_unregister(&led->cdev_led2g);
  518. failed_unregister_led2_G:
  519. led_classdev_unregister(&led->cdev_led2r);
  520. failed_unregister_led2_R:
  521. led_classdev_unregister(&led->cdev_led1b);
  522. failed_unregister_led1_B:
  523. led_classdev_unregister(&led->cdev_led1g);
  524. failed_unregister_led1_G:
  525. led_classdev_unregister(&led->cdev_led1r);
  526. failed_unregister_led1_R:
  527. return ret;
  528. }
  529. static void bd2802_unregister_led_classdev(struct bd2802_led *led)
  530. {
  531. cancel_work_sync(&led->work);
  532. led_classdev_unregister(&led->cdev_led1r);
  533. }
  534. static int __devinit bd2802_probe(struct i2c_client *client,
  535. const struct i2c_device_id *id)
  536. {
  537. struct bd2802_led *led;
  538. struct bd2802_led_platform_data *pdata;
  539. int ret;
  540. led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
  541. if (!led) {
  542. dev_err(&client->dev, "failed to allocate driver data\n");
  543. return -ENOMEM;
  544. }
  545. led->client = client;
  546. pdata = led->pdata = client->dev.platform_data;
  547. i2c_set_clientdata(client, led);
  548. /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
  549. gpio_request(pdata->reset_gpio, "RGB_RESETB");
  550. gpio_direction_output(pdata->reset_gpio, 1);
  551. /* Tacss = min 0.1ms */
  552. udelay(100);
  553. /* Detect BD2802GU */
  554. ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
  555. if (ret < 0) {
  556. dev_err(&client->dev, "failed to detect device\n");
  557. goto failed_free;
  558. } else
  559. dev_info(&client->dev, "return 0x%02x\n", ret);
  560. /* To save the power, reset BD2802 after detecting */
  561. gpio_set_value(led->pdata->reset_gpio, 0);
  562. init_rwsem(&led->rwsem);
  563. ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
  564. if (ret) {
  565. dev_err(&client->dev, "failed to create sysfs file %s\n",
  566. bd2802_adv_conf_attr.attr.name);
  567. goto failed_free;
  568. }
  569. ret = bd2802_register_led_classdev(led);
  570. if (ret < 0)
  571. goto failed_unregister_dev_file;
  572. return 0;
  573. failed_unregister_dev_file:
  574. device_remove_file(&client->dev, &bd2802_adv_conf_attr);
  575. failed_free:
  576. i2c_set_clientdata(client, NULL);
  577. kfree(led);
  578. return ret;
  579. }
  580. static int __exit bd2802_remove(struct i2c_client *client)
  581. {
  582. struct bd2802_led *led = i2c_get_clientdata(client);
  583. bd2802_unregister_led_classdev(led);
  584. gpio_set_value(led->pdata->reset_gpio, 0);
  585. if (led->adf_on)
  586. bd2802_disable_adv_conf(led);
  587. device_remove_file(&client->dev, &bd2802_adv_conf_attr);
  588. i2c_set_clientdata(client, NULL);
  589. kfree(led);
  590. return 0;
  591. }
  592. static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg)
  593. {
  594. struct bd2802_led *led = i2c_get_clientdata(client);
  595. gpio_set_value(led->pdata->reset_gpio, 0);
  596. return 0;
  597. }
  598. static int bd2802_resume(struct i2c_client *client)
  599. {
  600. struct bd2802_led *led = i2c_get_clientdata(client);
  601. if (!bd2802_is_all_off(led) || led->adf_on) {
  602. gpio_set_value(led->pdata->reset_gpio, 1);
  603. udelay(100);
  604. bd2802_restore_state(led);
  605. }
  606. return 0;
  607. }
  608. static const struct i2c_device_id bd2802_id[] = {
  609. { "BD2802", 0 },
  610. { }
  611. };
  612. MODULE_DEVICE_TABLE(i2c, bd2802_id);
  613. static struct i2c_driver bd2802_i2c_driver = {
  614. .driver = {
  615. .name = "BD2802",
  616. },
  617. .probe = bd2802_probe,
  618. .remove = __exit_p(bd2802_remove),
  619. .suspend = bd2802_suspend,
  620. .resume = bd2802_resume,
  621. .id_table = bd2802_id,
  622. };
  623. static int __init bd2802_init(void)
  624. {
  625. return i2c_add_driver(&bd2802_i2c_driver);
  626. }
  627. module_init(bd2802_init);
  628. static void __exit bd2802_exit(void)
  629. {
  630. i2c_del_driver(&bd2802_i2c_driver);
  631. }
  632. module_exit(bd2802_exit);
  633. MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
  634. MODULE_DESCRIPTION("BD2802 LED driver");
  635. MODULE_LICENSE("GPL");