lm3533-core.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. * lm3533-core.c -- LM3533 Core
  3. *
  4. * Copyright (C) 2011-2012 Texas Instruments
  5. *
  6. * Author: Johan Hovold <jhovold@gmail.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. */
  13. #include <linux/module.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/err.h>
  17. #include <linux/gpio.h>
  18. #include <linux/i2c.h>
  19. #include <linux/mfd/core.h>
  20. #include <linux/regmap.h>
  21. #include <linux/seq_file.h>
  22. #include <linux/slab.h>
  23. #include <linux/uaccess.h>
  24. #include <linux/mfd/lm3533.h>
  25. #define LM3533_BOOST_OVP_MASK 0x06
  26. #define LM3533_BOOST_OVP_SHIFT 1
  27. #define LM3533_BOOST_FREQ_MASK 0x01
  28. #define LM3533_BOOST_FREQ_SHIFT 0
  29. #define LM3533_BL_ID_MASK 1
  30. #define LM3533_LED_ID_MASK 3
  31. #define LM3533_BL_ID_MAX 1
  32. #define LM3533_LED_ID_MAX 3
  33. #define LM3533_HVLED_ID_MAX 2
  34. #define LM3533_LVLED_ID_MAX 5
  35. #define LM3533_REG_OUTPUT_CONF1 0x10
  36. #define LM3533_REG_OUTPUT_CONF2 0x11
  37. #define LM3533_REG_BOOST_PWM 0x2c
  38. #define LM3533_REG_MAX 0xb2
  39. static struct mfd_cell lm3533_als_devs[] = {
  40. {
  41. .name = "lm3533-als",
  42. .id = -1,
  43. },
  44. };
  45. static struct mfd_cell lm3533_bl_devs[] = {
  46. {
  47. .name = "lm3533-backlight",
  48. .id = 0,
  49. },
  50. {
  51. .name = "lm3533-backlight",
  52. .id = 1,
  53. },
  54. };
  55. static struct mfd_cell lm3533_led_devs[] = {
  56. {
  57. .name = "lm3533-leds",
  58. .id = 0,
  59. },
  60. {
  61. .name = "lm3533-leds",
  62. .id = 1,
  63. },
  64. {
  65. .name = "lm3533-leds",
  66. .id = 2,
  67. },
  68. {
  69. .name = "lm3533-leds",
  70. .id = 3,
  71. },
  72. };
  73. int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
  74. {
  75. int tmp;
  76. int ret;
  77. ret = regmap_read(lm3533->regmap, reg, &tmp);
  78. if (ret < 0) {
  79. dev_err(lm3533->dev, "failed to read register %02x: %d\n",
  80. reg, ret);
  81. return ret;
  82. }
  83. *val = tmp;
  84. dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
  85. return ret;
  86. }
  87. EXPORT_SYMBOL_GPL(lm3533_read);
  88. int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
  89. {
  90. int ret;
  91. dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
  92. ret = regmap_write(lm3533->regmap, reg, val);
  93. if (ret < 0) {
  94. dev_err(lm3533->dev, "failed to write register %02x: %d\n",
  95. reg, ret);
  96. }
  97. return ret;
  98. }
  99. EXPORT_SYMBOL_GPL(lm3533_write);
  100. int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
  101. {
  102. int ret;
  103. dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
  104. ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
  105. if (ret < 0) {
  106. dev_err(lm3533->dev, "failed to update register %02x: %d\n",
  107. reg, ret);
  108. }
  109. return ret;
  110. }
  111. EXPORT_SYMBOL_GPL(lm3533_update);
  112. static int lm3533_set_boost_freq(struct lm3533 *lm3533,
  113. enum lm3533_boost_freq freq)
  114. {
  115. int ret;
  116. ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
  117. freq << LM3533_BOOST_FREQ_SHIFT,
  118. LM3533_BOOST_FREQ_MASK);
  119. if (ret)
  120. dev_err(lm3533->dev, "failed to set boost frequency\n");
  121. return ret;
  122. }
  123. static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
  124. enum lm3533_boost_ovp ovp)
  125. {
  126. int ret;
  127. ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
  128. ovp << LM3533_BOOST_OVP_SHIFT,
  129. LM3533_BOOST_OVP_MASK);
  130. if (ret)
  131. dev_err(lm3533->dev, "failed to set boost ovp\n");
  132. return ret;
  133. }
  134. /*
  135. * HVLED output config -- output hvled controlled by backlight bl
  136. */
  137. static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
  138. {
  139. u8 val;
  140. u8 mask;
  141. int shift;
  142. int ret;
  143. if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
  144. return -EINVAL;
  145. if (bl > LM3533_BL_ID_MAX)
  146. return -EINVAL;
  147. shift = hvled - 1;
  148. mask = LM3533_BL_ID_MASK << shift;
  149. val = bl << shift;
  150. ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
  151. if (ret)
  152. dev_err(lm3533->dev, "failed to set hvled config\n");
  153. return ret;
  154. }
  155. /*
  156. * LVLED output config -- output lvled controlled by LED led
  157. */
  158. static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
  159. {
  160. u8 reg;
  161. u8 val;
  162. u8 mask;
  163. int shift;
  164. int ret;
  165. if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
  166. return -EINVAL;
  167. if (led > LM3533_LED_ID_MAX)
  168. return -EINVAL;
  169. if (lvled < 4) {
  170. reg = LM3533_REG_OUTPUT_CONF1;
  171. shift = 2 * lvled;
  172. } else {
  173. reg = LM3533_REG_OUTPUT_CONF2;
  174. shift = 2 * (lvled - 4);
  175. }
  176. mask = LM3533_LED_ID_MASK << shift;
  177. val = led << shift;
  178. ret = lm3533_update(lm3533, reg, val, mask);
  179. if (ret)
  180. dev_err(lm3533->dev, "failed to set lvled config\n");
  181. return ret;
  182. }
  183. static void lm3533_enable(struct lm3533 *lm3533)
  184. {
  185. if (gpio_is_valid(lm3533->gpio_hwen))
  186. gpio_set_value(lm3533->gpio_hwen, 1);
  187. }
  188. static void lm3533_disable(struct lm3533 *lm3533)
  189. {
  190. if (gpio_is_valid(lm3533->gpio_hwen))
  191. gpio_set_value(lm3533->gpio_hwen, 0);
  192. }
  193. enum lm3533_attribute_type {
  194. LM3533_ATTR_TYPE_BACKLIGHT,
  195. LM3533_ATTR_TYPE_LED,
  196. };
  197. struct lm3533_device_attribute {
  198. struct device_attribute dev_attr;
  199. enum lm3533_attribute_type type;
  200. union {
  201. struct {
  202. u8 id;
  203. } output;
  204. } u;
  205. };
  206. #define to_lm3533_dev_attr(_attr) \
  207. container_of(_attr, struct lm3533_device_attribute, dev_attr)
  208. static ssize_t show_output(struct device *dev,
  209. struct device_attribute *attr, char *buf)
  210. {
  211. struct lm3533 *lm3533 = dev_get_drvdata(dev);
  212. struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
  213. int id = lattr->u.output.id;
  214. u8 reg;
  215. u8 val;
  216. u8 mask;
  217. int shift;
  218. int ret;
  219. if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
  220. reg = LM3533_REG_OUTPUT_CONF1;
  221. shift = id - 1;
  222. mask = LM3533_BL_ID_MASK << shift;
  223. } else {
  224. if (id < 4) {
  225. reg = LM3533_REG_OUTPUT_CONF1;
  226. shift = 2 * id;
  227. } else {
  228. reg = LM3533_REG_OUTPUT_CONF2;
  229. shift = 2 * (id - 4);
  230. }
  231. mask = LM3533_LED_ID_MASK << shift;
  232. }
  233. ret = lm3533_read(lm3533, reg, &val);
  234. if (ret)
  235. return ret;
  236. val = (val & mask) >> shift;
  237. return scnprintf(buf, PAGE_SIZE, "%u\n", val);
  238. }
  239. static ssize_t store_output(struct device *dev,
  240. struct device_attribute *attr,
  241. const char *buf, size_t len)
  242. {
  243. struct lm3533 *lm3533 = dev_get_drvdata(dev);
  244. struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
  245. int id = lattr->u.output.id;
  246. u8 val;
  247. int ret;
  248. if (kstrtou8(buf, 0, &val))
  249. return -EINVAL;
  250. if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
  251. ret = lm3533_set_hvled_config(lm3533, id, val);
  252. else
  253. ret = lm3533_set_lvled_config(lm3533, id, val);
  254. if (ret)
  255. return ret;
  256. return len;
  257. }
  258. #define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
  259. struct lm3533_device_attribute lm3533_dev_attr_##_name = \
  260. { .dev_attr = __ATTR(_name, _mode, _show, _store), \
  261. .type = _type, \
  262. .u.output = { .id = _id }, }
  263. #define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
  264. LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
  265. show_output, store_output, _type, _id)
  266. #define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
  267. LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
  268. #define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
  269. LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
  270. /*
  271. * Output config:
  272. *
  273. * output_hvled<nr> 0-1
  274. * output_lvled<nr> 0-3
  275. */
  276. static LM3533_OUTPUT_HVLED_ATTR_RW(1);
  277. static LM3533_OUTPUT_HVLED_ATTR_RW(2);
  278. static LM3533_OUTPUT_LVLED_ATTR_RW(1);
  279. static LM3533_OUTPUT_LVLED_ATTR_RW(2);
  280. static LM3533_OUTPUT_LVLED_ATTR_RW(3);
  281. static LM3533_OUTPUT_LVLED_ATTR_RW(4);
  282. static LM3533_OUTPUT_LVLED_ATTR_RW(5);
  283. static struct attribute *lm3533_attributes[] = {
  284. &lm3533_dev_attr_output_hvled1.dev_attr.attr,
  285. &lm3533_dev_attr_output_hvled2.dev_attr.attr,
  286. &lm3533_dev_attr_output_lvled1.dev_attr.attr,
  287. &lm3533_dev_attr_output_lvled2.dev_attr.attr,
  288. &lm3533_dev_attr_output_lvled3.dev_attr.attr,
  289. &lm3533_dev_attr_output_lvled4.dev_attr.attr,
  290. &lm3533_dev_attr_output_lvled5.dev_attr.attr,
  291. NULL,
  292. };
  293. #define to_dev_attr(_attr) \
  294. container_of(_attr, struct device_attribute, attr)
  295. static umode_t lm3533_attr_is_visible(struct kobject *kobj,
  296. struct attribute *attr, int n)
  297. {
  298. struct device *dev = container_of(kobj, struct device, kobj);
  299. struct lm3533 *lm3533 = dev_get_drvdata(dev);
  300. struct device_attribute *dattr = to_dev_attr(attr);
  301. struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
  302. enum lm3533_attribute_type type = lattr->type;
  303. umode_t mode = attr->mode;
  304. if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
  305. mode = 0;
  306. else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
  307. mode = 0;
  308. return mode;
  309. };
  310. static struct attribute_group lm3533_attribute_group = {
  311. .is_visible = lm3533_attr_is_visible,
  312. .attrs = lm3533_attributes
  313. };
  314. static int lm3533_device_als_init(struct lm3533 *lm3533)
  315. {
  316. struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
  317. int ret;
  318. if (!pdata->als)
  319. return 0;
  320. lm3533_als_devs[0].platform_data = pdata->als;
  321. lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
  322. ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
  323. 0, NULL);
  324. if (ret) {
  325. dev_err(lm3533->dev, "failed to add ALS device\n");
  326. return ret;
  327. }
  328. lm3533->have_als = 1;
  329. return 0;
  330. }
  331. static int lm3533_device_bl_init(struct lm3533 *lm3533)
  332. {
  333. struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
  334. int i;
  335. int ret;
  336. if (!pdata->backlights || pdata->num_backlights == 0)
  337. return 0;
  338. if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
  339. pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
  340. for (i = 0; i < pdata->num_backlights; ++i) {
  341. lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
  342. lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
  343. }
  344. ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
  345. pdata->num_backlights, NULL, 0, NULL);
  346. if (ret) {
  347. dev_err(lm3533->dev, "failed to add backlight devices\n");
  348. return ret;
  349. }
  350. lm3533->have_backlights = 1;
  351. return 0;
  352. }
  353. static int lm3533_device_led_init(struct lm3533 *lm3533)
  354. {
  355. struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
  356. int i;
  357. int ret;
  358. if (!pdata->leds || pdata->num_leds == 0)
  359. return 0;
  360. if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
  361. pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
  362. for (i = 0; i < pdata->num_leds; ++i) {
  363. lm3533_led_devs[i].platform_data = &pdata->leds[i];
  364. lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
  365. }
  366. ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
  367. pdata->num_leds, NULL, 0, NULL);
  368. if (ret) {
  369. dev_err(lm3533->dev, "failed to add LED devices\n");
  370. return ret;
  371. }
  372. lm3533->have_leds = 1;
  373. return 0;
  374. }
  375. static int lm3533_device_setup(struct lm3533 *lm3533,
  376. struct lm3533_platform_data *pdata)
  377. {
  378. int ret;
  379. ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
  380. if (ret)
  381. return ret;
  382. return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
  383. }
  384. static int lm3533_device_init(struct lm3533 *lm3533)
  385. {
  386. struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
  387. int ret;
  388. dev_dbg(lm3533->dev, "%s\n", __func__);
  389. if (!pdata) {
  390. dev_err(lm3533->dev, "no platform data\n");
  391. return -EINVAL;
  392. }
  393. lm3533->gpio_hwen = pdata->gpio_hwen;
  394. dev_set_drvdata(lm3533->dev, lm3533);
  395. if (gpio_is_valid(lm3533->gpio_hwen)) {
  396. ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen,
  397. GPIOF_OUT_INIT_LOW, "lm3533-hwen");
  398. if (ret < 0) {
  399. dev_err(lm3533->dev,
  400. "failed to request HWEN GPIO %d\n",
  401. lm3533->gpio_hwen);
  402. return ret;
  403. }
  404. }
  405. lm3533_enable(lm3533);
  406. ret = lm3533_device_setup(lm3533, pdata);
  407. if (ret)
  408. goto err_disable;
  409. lm3533_device_als_init(lm3533);
  410. lm3533_device_bl_init(lm3533);
  411. lm3533_device_led_init(lm3533);
  412. ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
  413. if (ret < 0) {
  414. dev_err(lm3533->dev, "failed to create sysfs attributes\n");
  415. goto err_unregister;
  416. }
  417. return 0;
  418. err_unregister:
  419. mfd_remove_devices(lm3533->dev);
  420. err_disable:
  421. lm3533_disable(lm3533);
  422. return ret;
  423. }
  424. static void lm3533_device_exit(struct lm3533 *lm3533)
  425. {
  426. dev_dbg(lm3533->dev, "%s\n", __func__);
  427. sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
  428. mfd_remove_devices(lm3533->dev);
  429. lm3533_disable(lm3533);
  430. }
  431. static bool lm3533_readable_register(struct device *dev, unsigned int reg)
  432. {
  433. switch (reg) {
  434. case 0x10 ... 0x2c:
  435. case 0x30 ... 0x38:
  436. case 0x40 ... 0x45:
  437. case 0x50 ... 0x57:
  438. case 0x60 ... 0x6e:
  439. case 0x70 ... 0x75:
  440. case 0x80 ... 0x85:
  441. case 0x90 ... 0x95:
  442. case 0xa0 ... 0xa5:
  443. case 0xb0 ... 0xb2:
  444. return true;
  445. default:
  446. return false;
  447. }
  448. }
  449. static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
  450. {
  451. switch (reg) {
  452. case 0x34 ... 0x36: /* zone */
  453. case 0x37 ... 0x38: /* adc */
  454. case 0xb0 ... 0xb1: /* fault */
  455. return true;
  456. default:
  457. return false;
  458. }
  459. }
  460. static bool lm3533_precious_register(struct device *dev, unsigned int reg)
  461. {
  462. switch (reg) {
  463. case 0x34: /* zone */
  464. return true;
  465. default:
  466. return false;
  467. }
  468. }
  469. static const struct regmap_config regmap_config = {
  470. .reg_bits = 8,
  471. .val_bits = 8,
  472. .max_register = LM3533_REG_MAX,
  473. .readable_reg = lm3533_readable_register,
  474. .volatile_reg = lm3533_volatile_register,
  475. .precious_reg = lm3533_precious_register,
  476. };
  477. static int lm3533_i2c_probe(struct i2c_client *i2c,
  478. const struct i2c_device_id *id)
  479. {
  480. struct lm3533 *lm3533;
  481. dev_dbg(&i2c->dev, "%s\n", __func__);
  482. lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);
  483. if (!lm3533)
  484. return -ENOMEM;
  485. i2c_set_clientdata(i2c, lm3533);
  486. lm3533->regmap = devm_regmap_init_i2c(i2c, &regmap_config);
  487. if (IS_ERR(lm3533->regmap))
  488. return PTR_ERR(lm3533->regmap);
  489. lm3533->dev = &i2c->dev;
  490. lm3533->irq = i2c->irq;
  491. return lm3533_device_init(lm3533);
  492. }
  493. static int lm3533_i2c_remove(struct i2c_client *i2c)
  494. {
  495. struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
  496. dev_dbg(&i2c->dev, "%s\n", __func__);
  497. lm3533_device_exit(lm3533);
  498. return 0;
  499. }
  500. static const struct i2c_device_id lm3533_i2c_ids[] = {
  501. { "lm3533", 0 },
  502. { },
  503. };
  504. MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
  505. static struct i2c_driver lm3533_i2c_driver = {
  506. .driver = {
  507. .name = "lm3533",
  508. },
  509. .id_table = lm3533_i2c_ids,
  510. .probe = lm3533_i2c_probe,
  511. .remove = lm3533_i2c_remove,
  512. };
  513. static int __init lm3533_i2c_init(void)
  514. {
  515. return i2c_add_driver(&lm3533_i2c_driver);
  516. }
  517. subsys_initcall(lm3533_i2c_init);
  518. static void __exit lm3533_i2c_exit(void)
  519. {
  520. i2c_del_driver(&lm3533_i2c_driver);
  521. }
  522. module_exit(lm3533_i2c_exit);
  523. MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
  524. MODULE_DESCRIPTION("LM3533 Core");
  525. MODULE_LICENSE("GPL");