leds-bd2802.c 20 KB

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