leds_drv.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. /*
  2. * drivers/leds/leds-mt65xx.c
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file COPYING in the main directory of this archive for
  6. * more details.
  7. *
  8. * mt65xx leds driver
  9. *
  10. */
  11. #include <linux/i2c.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/delay.h>
  15. #include <linux/string.h>
  16. #include <linux/ctype.h>
  17. #include <linux/leds.h>
  18. /* #include <linux/leds-mt65xx.h> */
  19. #include <linux/workqueue.h>
  20. #include <linux/wakelock.h>
  21. #include <linux/slab.h>
  22. #include <linux/spinlock.h>
  23. /* #include <mach/mt_pwm.h> */
  24. /* #include <mach/mt_pwm_hal.h> */
  25. /* #include <mach/mt_gpio.h> */
  26. /*
  27. #include <mach/upmu_common_sw.h>
  28. #include <mach/upmu_hw.h> */
  29. /* #include <mach/mt_pmic_feature_api.h> */
  30. /* #include <mach/mt_boot.h> */
  31. #include <leds_hal.h>
  32. #include "leds_drv.h"
  33. #include <mt-plat/mt_pwm.h>
  34. #include <mt-plat/upmu_common.h>
  35. #ifdef BACKLIGHT_SUPPORT_LP8557
  36. #include <linux/of_gpio.h>
  37. #include <linux/gpio.h>
  38. #include <asm-generic/gpio.h>
  39. #endif
  40. /****************************************************************************
  41. * variables
  42. ***************************************************************************/
  43. struct cust_mt65xx_led *bl_setting = NULL;
  44. /* static unsigned int bl_brightness = 102;
  45. static unsigned int bl_duty = 21;
  46. static unsigned int bl_div = CLK_DIV1;
  47. static unsigned int bl_frequency = 32000; */
  48. static unsigned int bl_div = CLK_DIV1;
  49. #define PWM_DIV_NUM 8
  50. static unsigned int div_array[PWM_DIV_NUM];
  51. struct mt65xx_led_data *g_leds_data[MT65XX_LED_TYPE_TOTAL];
  52. #ifdef BACKLIGHT_SUPPORT_LP8557
  53. static unsigned int last_level1 = 102;
  54. static struct i2c_client *g_client;
  55. static int I2C_SET_FOR_BACKLIGHT = 350;
  56. #endif
  57. /****************************************************************************
  58. * DEBUG MACROS
  59. ***************************************************************************/
  60. static int debug_enable_led = 1;
  61. /* #define pr_fmt(fmt) "[LED_DRV]"fmt */
  62. #define LEDS_DRV_DEBUG(format, args...) do { \
  63. if (debug_enable_led) { \
  64. pr_debug(format, ##args);\
  65. } \
  66. } while (0)
  67. /****************************************************************************
  68. * function prototypes
  69. ***************************************************************************/
  70. #ifndef CONTROL_BL_TEMPERATURE
  71. #define CONTROL_BL_TEMPERATURE
  72. #endif
  73. #define MT_LED_INTERNAL_LEVEL_BIT_CNT 10
  74. /******************************************************************************
  75. for DISP backlight High resolution
  76. ******************************************************************************/
  77. #ifdef LED_INCREASE_LED_LEVEL_MTKPATCH
  78. #define LED_INTERNAL_LEVEL_BIT_CNT 10
  79. #endif
  80. static int mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level);
  81. /****************************************************************************
  82. * add API for temperature control
  83. ***************************************************************************/
  84. #ifdef CONTROL_BL_TEMPERATURE
  85. /* define int limit for brightness limitation */
  86. static unsigned int limit = 255;
  87. static unsigned int limit_flag;
  88. static unsigned int last_level;
  89. static unsigned int current_level;
  90. static DEFINE_MUTEX(bl_level_limit_mutex);
  91. /****************************************************************************
  92. * external functions for display
  93. * this API add for control the power and temperature,
  94. * if enabe=1, the value of brightness will smaller than max_level,
  95. * whatever lightservice transfers to driver.
  96. ***************************************************************************/
  97. int setMaxbrightness(int max_level, int enable)
  98. {
  99. #if !defined(CONFIG_MTK_AAL_SUPPORT)
  100. struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();
  101. mutex_lock(&bl_level_limit_mutex);
  102. if (1 == enable) {
  103. limit_flag = 1;
  104. limit = max_level;
  105. mutex_unlock(&bl_level_limit_mutex);
  106. /* if (limit < last_level){ */
  107. if (0 != current_level) {
  108. if (limit < last_level) {
  109. LEDS_DRV_DEBUG
  110. ("mt65xx_leds_set_cust in setMaxbrightness:value control start! limit=%d\n",
  111. limit);
  112. mt65xx_led_set_cust(&cust_led_list
  113. [MT65XX_LED_TYPE_LCD],
  114. limit);
  115. } else {
  116. mt65xx_led_set_cust(&cust_led_list
  117. [MT65XX_LED_TYPE_LCD],
  118. last_level);
  119. }
  120. }
  121. } else {
  122. limit_flag = 0;
  123. limit = 255;
  124. mutex_unlock(&bl_level_limit_mutex);
  125. if (0 != current_level) {
  126. LEDS_DRV_DEBUG("control temperature close:limit=%d\n",
  127. limit);
  128. mt65xx_led_set_cust(&cust_led_list[MT65XX_LED_TYPE_LCD],
  129. last_level);
  130. }
  131. }
  132. #else
  133. LEDS_DRV_DEBUG("setMaxbrightness go through AAL\n");
  134. disp_bls_set_max_backlight(((((1 << LED_INTERNAL_LEVEL_BIT_CNT) -
  135. 1) * max_level + 127) / 255));
  136. #endif /* endif CONFIG_MTK_AAL_SUPPORT */
  137. return 0;
  138. }
  139. EXPORT_SYMBOL(setMaxbrightness);
  140. #endif
  141. /****************************************************************************
  142. * internal functions
  143. ***************************************************************************/
  144. static void get_div_array(void)
  145. {
  146. int i = 0;
  147. unsigned int *temp = mt_get_div_array();
  148. while (i < PWM_DIV_NUM) {
  149. div_array[i] = *temp++;
  150. LEDS_DRV_DEBUG("get_div_array: div_array=%d\n", div_array[i]);
  151. i++;
  152. }
  153. }
  154. static int led_set_pwm(int pwm_num, struct nled_setting *led)
  155. {
  156. mt_led_set_pwm(pwm_num, led);
  157. return 0;
  158. }
  159. static int brightness_set_pmic(enum mt65xx_led_pmic pmic_type, u32 level,
  160. u32 div)
  161. {
  162. mt_brightness_set_pmic(pmic_type, level, div);
  163. return -1;
  164. }
  165. static int mt65xx_led_set_cust(struct cust_mt65xx_led *cust, int level)
  166. {
  167. #ifdef CONTROL_BL_TEMPERATURE
  168. mutex_lock(&bl_level_limit_mutex);
  169. current_level = level;
  170. /* LEDS_DRV_DEBUG("brightness_set_cust:current_level=%d\n", current_level); */
  171. if (0 == limit_flag) {
  172. last_level = level;
  173. /* LEDS_DRV_DEBUG("brightness_set_cust:last_level=%d\n", last_level); */
  174. } else {
  175. if (limit < current_level) {
  176. level = limit;
  177. /* LEDS_DRV_DEBUG("backlight_set_cust: control level=%d\n", level); */
  178. }
  179. }
  180. mutex_unlock(&bl_level_limit_mutex);
  181. #endif
  182. #ifdef LED_INCREASE_LED_LEVEL_MTKPATCH
  183. if (MT65XX_LED_MODE_CUST_BLS_PWM == cust->mode) {
  184. mt_mt65xx_led_set_cust(cust,
  185. ((((1 << LED_INTERNAL_LEVEL_BIT_CNT) -
  186. 1) * level + 127) / 255));
  187. } else {
  188. mt_mt65xx_led_set_cust(cust, level);
  189. }
  190. #else
  191. mt_mt65xx_led_set_cust(cust, level);
  192. #endif
  193. return -1;
  194. }
  195. static void mt65xx_led_set(struct led_classdev *led_cdev,
  196. enum led_brightness level)
  197. {
  198. struct mt65xx_led_data *led_data =
  199. container_of(led_cdev, struct mt65xx_led_data, cdev);
  200. #ifdef BACKLIGHT_SUPPORT_LP8557
  201. bool flag = FALSE;
  202. int value = 0;
  203. int retval;
  204. struct device_node *node = NULL;
  205. struct i2c_client *client = g_client;
  206. value = i2c_smbus_read_byte_data(g_client, 0x10);
  207. LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:0x10 = %d\n", value);
  208. node = of_find_compatible_node(NULL, NULL,
  209. "mediatek,lcd-backlight");
  210. if (node) {
  211. I2C_SET_FOR_BACKLIGHT = of_get_named_gpio(node, "gpios", 0);
  212. LEDS_DRV_DEBUG("Led_i2c gpio num for power:%d\n", I2C_SET_FOR_BACKLIGHT);
  213. }
  214. #endif
  215. if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
  216. #ifdef CONTROL_BL_TEMPERATURE
  217. mutex_lock(&bl_level_limit_mutex);
  218. current_level = level;
  219. /* LEDS_DRV_DEBUG("brightness_set_cust:current_level=%d\n", current_level); */
  220. if (0 == limit_flag) {
  221. last_level = level;
  222. /* LEDS_DRV_DEBUG("brightness_set_cust:last_level=%d\n", last_level); */
  223. } else {
  224. if (limit < current_level) {
  225. level = limit;
  226. LEDS_DRV_DEBUG
  227. ("backlight_set_cust: control level=%d\n",
  228. level);
  229. }
  230. }
  231. mutex_unlock(&bl_level_limit_mutex);
  232. #endif
  233. }
  234. #ifdef BACKLIGHT_SUPPORT_LP8557
  235. retval = gpio_request(I2C_SET_FOR_BACKLIGHT, "i2c_set_for_backlight");
  236. if (retval)
  237. LEDS_DRV_DEBUG("LEDS: request I2C gpio149 failed\n");
  238. if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
  239. if (level == 0) {
  240. LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:close the power\n");
  241. i2c_smbus_write_byte_data(client, 0x00, 0);
  242. gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 0);
  243. }
  244. if (!last_level1 && level) {
  245. LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:open the power\n");
  246. gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 1);
  247. mdelay(100);
  248. i2c_smbus_write_byte_data(client, 0x10, 4);
  249. flag = TRUE;
  250. }
  251. last_level1 = level;
  252. }
  253. gpio_free(I2C_SET_FOR_BACKLIGHT);
  254. #endif
  255. mt_mt65xx_led_set(led_cdev, level);
  256. #ifdef BACKLIGHT_SUPPORT_LP8557
  257. if (strcmp(led_data->cust.name, "lcd-backlight") == 0) {
  258. if (flag) {
  259. i2c_smbus_write_byte_data(client, 0x14, 0xdf);
  260. i2c_smbus_write_byte_data(client, 0x04, 0xff);
  261. i2c_smbus_write_byte_data(client, 0x00, 1);
  262. }
  263. }
  264. #endif
  265. }
  266. static int mt65xx_blink_set(struct led_classdev *led_cdev,
  267. unsigned long *delay_on, unsigned long *delay_off)
  268. {
  269. if (mt_mt65xx_blink_set(led_cdev, delay_on, delay_off))
  270. return -1;
  271. else
  272. return 0;
  273. }
  274. /****************************************************************************
  275. * external functions for display
  276. ***************************************************************************/
  277. int mt65xx_leds_brightness_set(enum mt65xx_led_type type,
  278. enum led_brightness level)
  279. {
  280. int val;
  281. struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();
  282. #ifdef BACKLIGHT_SUPPORT_LP8557
  283. bool flag = FALSE;
  284. int value = 0;
  285. int retval;
  286. struct device_node *node = NULL;
  287. struct i2c_client *client = g_client;
  288. value = i2c_smbus_read_byte_data(g_client, 0x10);
  289. LEDS_DRV_DEBUG("LEDS:mt65xx_led_set:0x10 = %d\n", value);
  290. node = of_find_compatible_node(NULL, NULL,
  291. "mediatek,lcd-backlight");
  292. if (node) {
  293. I2C_SET_FOR_BACKLIGHT = of_get_named_gpio(node, "gpios", 0);
  294. LEDS_DRV_DEBUG("Led_i2c gpio num for power:%d\n", I2C_SET_FOR_BACKLIGHT);
  295. }
  296. #endif
  297. LEDS_DRV_DEBUG("#%d:%d\n", type, level);
  298. if (type < 0 || type >= MT65XX_LED_TYPE_TOTAL)
  299. return -1;
  300. if (level > LED_FULL)
  301. level = LED_FULL;
  302. else if (level < 0)
  303. level = 0;
  304. #ifdef BACKLIGHT_SUPPORT_LP8557
  305. retval = gpio_request(I2C_SET_FOR_BACKLIGHT, "i2c_set_for_backlight");
  306. if (retval)
  307. LEDS_DRV_DEBUG("LEDS: request I2C gpio149 failed\n");
  308. if (strcmp(cust_led_list[type].name, "lcd-backlight") == 0) {
  309. if (level == 0) {
  310. i2c_smbus_write_byte_data(client, 0x00, 0);
  311. gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 0);
  312. }
  313. if (!last_level1 && level) {
  314. gpio_direction_output(I2C_SET_FOR_BACKLIGHT, 1);
  315. mdelay(100);
  316. i2c_smbus_write_byte_data(client, 0x10, 4);
  317. flag = TRUE;
  318. }
  319. last_level1 = level;
  320. }
  321. gpio_free(I2C_SET_FOR_BACKLIGHT);
  322. #endif
  323. val = mt65xx_led_set_cust(&cust_led_list[type], level);
  324. #ifdef BACKLIGHT_SUPPORT_LP8557
  325. if (strcmp(cust_led_list[type].name, "lcd-backlight") == 0) {
  326. if (flag) {
  327. i2c_smbus_write_byte_data(client, 0x14, 0xdf);
  328. i2c_smbus_write_byte_data(client, 0x04, 0xff);
  329. i2c_smbus_write_byte_data(client, 0x00, 1);
  330. }
  331. }
  332. #endif
  333. return val;
  334. }
  335. EXPORT_SYMBOL(mt65xx_leds_brightness_set);
  336. /****************************************************************************
  337. * external functions for AAL
  338. ***************************************************************************/
  339. int backlight_brightness_set(int level)
  340. {
  341. struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();
  342. if (level > ((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1))
  343. level = ((1 << MT_LED_INTERNAL_LEVEL_BIT_CNT) - 1);
  344. else if (level < 0)
  345. level = 0;
  346. if (MT65XX_LED_MODE_CUST_BLS_PWM ==
  347. cust_led_list[MT65XX_LED_TYPE_LCD].mode) {
  348. #ifdef CONTROL_BL_TEMPERATURE
  349. mutex_lock(&bl_level_limit_mutex);
  350. current_level = (level >> (MT_LED_INTERNAL_LEVEL_BIT_CNT - 8)); /* 8 bits */
  351. if (0 == limit_flag) {
  352. last_level = current_level;
  353. } else {
  354. if (limit < current_level) {
  355. /* extend 8-bit limit to 10 bits */
  356. level =
  357. (limit <<
  358. (MT_LED_INTERNAL_LEVEL_BIT_CNT -
  359. 8)) | (limit >> (16 -
  360. MT_LED_INTERNAL_LEVEL_BIT_CNT));
  361. }
  362. }
  363. mutex_unlock(&bl_level_limit_mutex);
  364. #endif
  365. return
  366. mt_mt65xx_led_set_cust(&cust_led_list[MT65XX_LED_TYPE_LCD],
  367. level);
  368. } else {
  369. return mt65xx_led_set_cust(&cust_led_list[MT65XX_LED_TYPE_LCD],
  370. (level >>
  371. (MT_LED_INTERNAL_LEVEL_BIT_CNT -
  372. 8)));
  373. }
  374. }
  375. EXPORT_SYMBOL(backlight_brightness_set);
  376. #if 0
  377. static ssize_t show_duty(struct device *dev, struct device_attribute *attr,
  378. char *buf)
  379. {
  380. LEDS_DRV_DEBUG("get backlight duty value is:%d\n", bl_duty);
  381. return sprintf(buf, "%u\n", bl_duty);
  382. }
  383. static ssize_t store_duty(struct device *dev, struct device_attribute *attr,
  384. const char *buf, size_t size)
  385. {
  386. char *pvalue = NULL;
  387. unsigned int level = 0;
  388. size_t count = 0;
  389. bl_div = mt_get_bl_div();
  390. LEDS_DRV_DEBUG("set backlight duty start\n");
  391. level = (unsigned int) kstrtoul(buf, &pvalue, 10);
  392. count = pvalue - buf;
  393. if (*pvalue && isspace(*pvalue))
  394. count++;
  395. if (count == size) {
  396. if (bl_setting->mode == MT65XX_LED_MODE_PMIC) {
  397. /* duty:0-16 */
  398. if ((level >= 0) && (level <= 15)) {
  399. mt_brightness_set_pmic_duty_store((level * 17),
  400. bl_div);
  401. } else {
  402. LEDS_DRV_DEBUG
  403. ("duty value is error, please select value from [0-15]!\n");
  404. }
  405. }
  406. else if (bl_setting->mode == MT65XX_LED_MODE_PWM) {
  407. if (level == 0) {
  408. mt_led_pwm_disable(bl_setting->data);
  409. } else if (level <= 64) {
  410. mt_backlight_set_pwm_duty(bl_setting->data,
  411. level, bl_div,
  412. &bl_setting->
  413. config_data);
  414. }
  415. }
  416. mt_set_bl_duty(level);
  417. }
  418. return size;
  419. }
  420. static DEVICE_ATTR(duty, 0664, show_duty, store_duty);
  421. static ssize_t show_div(struct device *dev, struct device_attribute *attr,
  422. char *buf)
  423. {
  424. bl_div = mt_get_bl_div();
  425. LEDS_DRV_DEBUG("get backlight div value is:%d\n", bl_div);
  426. return sprintf(buf, "%u\n", bl_div);
  427. }
  428. static ssize_t store_div(struct device *dev, struct device_attribute *attr,
  429. const char *buf, size_t size)
  430. {
  431. char *pvalue = NULL;
  432. unsigned int div = 0;
  433. size_t count = 0;
  434. bl_duty = mt_get_bl_duty();
  435. LEDS_DRV_DEBUG("set backlight div start\n");
  436. div = kstrtoul(buf, &pvalue, 10);
  437. count = pvalue - buf;
  438. if (*pvalue && isspace(*pvalue))
  439. count++;
  440. if (count == size) {
  441. if (div < 0 || (div > 7)) {
  442. LEDS_DRV_DEBUG
  443. ("set backlight div parameter error: %d[div:0~7]\n",
  444. div);
  445. return 0;
  446. }
  447. if (bl_setting->mode == MT65XX_LED_MODE_PWM) {
  448. LEDS_DRV_DEBUG
  449. ("set PWM backlight div OK: div=%d, duty=%d\n", div,
  450. bl_duty);
  451. mt_backlight_set_pwm_div(bl_setting->data, bl_duty, div,
  452. &bl_setting->config_data);
  453. }
  454. else if (bl_setting->mode == MT65XX_LED_MODE_CUST_LCM) {
  455. bl_brightness = mt_get_bl_brightness();
  456. LEDS_DRV_DEBUG
  457. ("set cust backlight div OK: div=%d, brightness=%d\n",
  458. div, bl_brightness);
  459. ((cust_brightness_set) (bl_setting->data))
  460. (bl_brightness, div);
  461. }
  462. mt_set_bl_div(div);
  463. }
  464. return size;
  465. }
  466. static DEVICE_ATTR(div, 0664, show_div, store_div);
  467. static ssize_t show_frequency(struct device *dev, struct device_attribute *attr,
  468. char *buf)
  469. {
  470. bl_div = mt_get_bl_div();
  471. bl_frequency = mt_get_bl_frequency();
  472. if (bl_setting->mode == MT65XX_LED_MODE_PWM) {
  473. mt_set_bl_frequency(32000 / div_array[bl_div]);
  474. } else if (bl_setting->mode == MT65XX_LED_MODE_CUST_LCM) {
  475. /* mtkfb_get_backlight_pwm(bl_div, &bl_frequency); */
  476. mt_backlight_get_pwm_fsel(bl_div, &bl_frequency);
  477. }
  478. LEDS_DRV_DEBUG("get backlight PWM frequency value is:%d\n",
  479. bl_frequency);
  480. return sprintf(buf, "%u\n", bl_frequency);
  481. }
  482. static DEVICE_ATTR(frequency, 0444, show_frequency, NULL);
  483. static ssize_t store_pwm_register(struct device *dev,
  484. struct device_attribute *attr,
  485. const char *buf, size_t size)
  486. {
  487. char *pvalue = NULL;
  488. unsigned int reg_value = 0;
  489. unsigned int reg_address = 0;
  490. if (buf != NULL && size != 0) {
  491. /* LEDS_DRV_DEBUG("store_pwm_register: size:%d,address:0x%s\n", size, buf); */
  492. reg_address = kstrtoul(buf, &pvalue, 16);
  493. if (*pvalue && (*pvalue == '#')) {
  494. reg_value = kstrtoul((pvalue + 1), NULL, 16);
  495. LEDS_DRV_DEBUG("set pwm register:[0x%x]= 0x%x\n",
  496. reg_address, reg_value);
  497. /* OUTREG32(reg_address,reg_value); */
  498. mt_store_pwm_register(reg_address, reg_value);
  499. } else if (*pvalue && (*pvalue == '@')) {
  500. LEDS_DRV_DEBUG("get pwm register:[0x%x]=0x%x\n",
  501. reg_address,
  502. mt_show_pwm_register(reg_address));
  503. }
  504. }
  505. return size;
  506. }
  507. static ssize_t show_pwm_register(struct device *dev,
  508. struct device_attribute *attr, char *buf)
  509. {
  510. return 0;
  511. }
  512. static DEVICE_ATTR(pwm_register, 0664, show_pwm_register, store_pwm_register);
  513. #endif
  514. #ifdef BACKLIGHT_SUPPORT_LP8557
  515. static int led_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id);
  516. static int led_i2c_remove(struct i2c_client *client);
  517. /*
  518. static struct i2c_board_info leds_board_info __initdata = {
  519. I2C_BOARD_INFO("lp8557_led", 0x2c),
  520. };*/
  521. static const struct of_device_id lp855x_id[] = {
  522. {.compatible = "mediatek,8173led_i2c"},
  523. {},
  524. };
  525. MODULE_DEVICE_TABLE(OF, lp855x_id);
  526. static const struct i2c_device_id lp855x_i2c_id[] = {{"lp8557_led", 0}, {} };
  527. struct i2c_driver led_i2c_driver = {
  528. .probe = led_i2c_probe,
  529. .remove = led_i2c_remove,
  530. .driver = {
  531. .name = "lp8557_led",
  532. .owner = THIS_MODULE,
  533. .of_match_table = of_match_ptr(lp855x_id),
  534. },
  535. .id_table = lp855x_i2c_id,
  536. };
  537. static int led_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
  538. {
  539. g_client = client;
  540. return 0;
  541. }
  542. static int led_i2c_remove(struct i2c_client *client)
  543. {
  544. return 0;
  545. }
  546. #endif
  547. /****************************************************************************
  548. * driver functions
  549. ***************************************************************************/
  550. static int mt65xx_leds_probe(struct platform_device *pdev)
  551. {
  552. int i;
  553. int ret;/* rc; */
  554. struct cust_mt65xx_led *cust_led_list = mt_get_cust_led_list();
  555. #ifdef BACKLIGHT_SUPPORT_LP8557
  556. /*i2c_register_board_info(4, &leds_board_info, 1);*/
  557. if (i2c_add_driver(&led_i2c_driver)) {
  558. LEDS_DRV_DEBUG("unable to add led-i2c driver.\n");
  559. return -1;
  560. }
  561. #endif
  562. LEDS_DRV_DEBUG("%s\n", __func__);
  563. get_div_array();
  564. for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {
  565. if (cust_led_list[i].mode == MT65XX_LED_MODE_NONE) {
  566. g_leds_data[i] = NULL;
  567. continue;
  568. }
  569. g_leds_data[i] =
  570. kzalloc(sizeof(struct mt65xx_led_data), GFP_KERNEL);
  571. if (!g_leds_data[i]) {
  572. ret = -ENOMEM;
  573. goto err;
  574. }
  575. g_leds_data[i]->cust.mode = cust_led_list[i].mode;
  576. g_leds_data[i]->cust.data = cust_led_list[i].data;
  577. g_leds_data[i]->cust.name = cust_led_list[i].name;
  578. g_leds_data[i]->cdev.name = cust_led_list[i].name;
  579. g_leds_data[i]->cust.config_data = cust_led_list[i].config_data; /* bei add */
  580. g_leds_data[i]->cdev.brightness_set = mt65xx_led_set;
  581. g_leds_data[i]->cdev.blink_set = mt65xx_blink_set;
  582. INIT_WORK(&g_leds_data[i]->work, mt_mt65xx_led_work);
  583. ret = led_classdev_register(&pdev->dev, &g_leds_data[i]->cdev);
  584. #if 0
  585. if (strcmp(g_leds_data[i]->cdev.name, "lcd-backlight") == 0) {
  586. rc = device_create_file(g_leds_data[i]->cdev.dev,
  587. &dev_attr_duty);
  588. if (rc) {
  589. LEDS_DRV_DEBUG
  590. ("device_create_file duty fail!\n");
  591. }
  592. rc = device_create_file(g_leds_data[i]->cdev.dev,
  593. &dev_attr_div);
  594. if (rc) {
  595. LEDS_DRV_DEBUG
  596. ("device_create_file duty fail!\n");
  597. }
  598. rc = device_create_file(g_leds_data[i]->cdev.dev,
  599. &dev_attr_frequency);
  600. if (rc) {
  601. LEDS_DRV_DEBUG
  602. ("device_create_file duty fail!\n");
  603. }
  604. rc = device_create_file(g_leds_data[i]->cdev.dev,
  605. &dev_attr_pwm_register);
  606. if (rc) {
  607. LEDS_DRV_DEBUG
  608. ("device_create_file duty fail!\n");
  609. }
  610. bl_setting = &g_leds_data[i]->cust;
  611. }
  612. #endif
  613. if (ret)
  614. goto err;
  615. }
  616. #ifdef CONTROL_BL_TEMPERATURE
  617. last_level = 0;
  618. limit = 255;
  619. limit_flag = 0;
  620. current_level = 0;
  621. LEDS_DRV_DEBUG
  622. ("led probe last_level = %d, limit = %d, limit_flag = %d, current_level = %d\n",
  623. last_level, limit, limit_flag, current_level);
  624. #endif
  625. return 0;
  626. err:
  627. if (i) {
  628. for (i = i - 1; i >= 0; i--) {
  629. if (!g_leds_data[i])
  630. continue;
  631. led_classdev_unregister(&g_leds_data[i]->cdev);
  632. cancel_work_sync(&g_leds_data[i]->work);
  633. kfree(g_leds_data[i]);
  634. g_leds_data[i] = NULL;
  635. }
  636. }
  637. return ret;
  638. }
  639. static int mt65xx_leds_remove(struct platform_device *pdev)
  640. {
  641. int i;
  642. for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {
  643. if (!g_leds_data[i])
  644. continue;
  645. led_classdev_unregister(&g_leds_data[i]->cdev);
  646. cancel_work_sync(&g_leds_data[i]->work);
  647. kfree(g_leds_data[i]);
  648. g_leds_data[i] = NULL;
  649. }
  650. return 0;
  651. }
  652. /*
  653. static int mt65xx_leds_suspend(struct platform_device *pdev, pm_message_t state)
  654. {
  655. return 0;
  656. }
  657. */
  658. static void mt65xx_leds_shutdown(struct platform_device *pdev)
  659. {
  660. int i;
  661. struct nled_setting led_tmp_setting = { NLED_OFF, 0, 0 };
  662. LEDS_DRV_DEBUG("%s\n", __func__);
  663. LEDS_DRV_DEBUG("mt65xx_leds_shutdown: turn off backlight\n");
  664. for (i = 0; i < MT65XX_LED_TYPE_TOTAL; i++) {
  665. if (!g_leds_data[i])
  666. continue;
  667. switch (g_leds_data[i]->cust.mode) {
  668. case MT65XX_LED_MODE_PWM:
  669. if (strcmp(g_leds_data[i]->cust.name, "lcd-backlight")
  670. == 0) {
  671. /* mt_set_pwm_disable(g_leds_data[i]->cust.data); */
  672. /* mt_pwm_power_off (g_leds_data[i]->cust.data); */
  673. mt_led_pwm_disable(g_leds_data[i]->cust.data);
  674. } else {
  675. led_set_pwm(g_leds_data[i]->cust.data,
  676. &led_tmp_setting);
  677. }
  678. break;
  679. /* case MT65XX_LED_MODE_GPIO: */
  680. /* brightness_set_gpio(g_leds_data[i]->cust.data, 0); */
  681. /* break; */
  682. case MT65XX_LED_MODE_PMIC:
  683. brightness_set_pmic(g_leds_data[i]->cust.data, 0, 0);
  684. break;
  685. case MT65XX_LED_MODE_CUST_LCM:
  686. LEDS_DRV_DEBUG("backlight control through LCM!!1\n");
  687. ((cust_brightness_set) (g_leds_data[i]->cust.data)) (0,
  688. bl_div);
  689. break;
  690. case MT65XX_LED_MODE_CUST_BLS_PWM:
  691. LEDS_DRV_DEBUG("backlight control through BLS!!1\n");
  692. ((cust_set_brightness) (g_leds_data[i]->cust.data)) (0);
  693. break;
  694. case MT65XX_LED_MODE_NONE:
  695. default:
  696. break;
  697. }
  698. }
  699. }
  700. static struct platform_driver mt65xx_leds_driver = {
  701. .driver = {
  702. .name = "leds-mt65xx",
  703. .owner = THIS_MODULE,
  704. },
  705. .probe = mt65xx_leds_probe,
  706. .remove = mt65xx_leds_remove,
  707. /* .suspend = mt65xx_leds_suspend, */
  708. .shutdown = mt65xx_leds_shutdown,
  709. };
  710. #ifdef CONFIG_OF
  711. static struct platform_device mt65xx_leds_device = {
  712. .name = "leds-mt65xx",
  713. .id = -1
  714. };
  715. #endif
  716. static int __init mt65xx_leds_init(void)
  717. {
  718. int ret;
  719. LEDS_DRV_DEBUG("%s\n", __func__);
  720. #ifdef CONFIG_OF
  721. ret = platform_device_register(&mt65xx_leds_device);
  722. if (ret)
  723. LEDS_DRV_DEBUG("mt65xx_leds_init:dev:E%d\n", ret);
  724. #endif
  725. ret = platform_driver_register(&mt65xx_leds_driver);
  726. if (ret) {
  727. LEDS_DRV_DEBUG("mt65xx_leds_init:drv:E%d\n", ret);
  728. /* platform_device_unregister(&mt65xx_leds_device); */
  729. return ret;
  730. }
  731. mt_leds_wake_lock_init();
  732. return ret;
  733. }
  734. static void __exit mt65xx_leds_exit(void)
  735. {
  736. platform_driver_unregister(&mt65xx_leds_driver);
  737. /* platform_device_unregister(&mt65xx_leds_device); */
  738. }
  739. module_param(debug_enable_led, int, 0644);
  740. module_init(mt65xx_leds_init);
  741. module_exit(mt65xx_leds_exit);
  742. MODULE_AUTHOR("MediaTek Inc.");
  743. MODULE_DESCRIPTION("LED driver for MediaTek MT65xx chip");
  744. MODULE_LICENSE("GPL");
  745. MODULE_ALIAS("leds-mt65xx");