aw99706.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * aw99706 - Backlight driver for the AWINIC AW99706
  4. *
  5. * Copyright (C) 2025 Junjie Cao <caojunjie650@gmail.com>
  6. * Copyright (C) 2025 Pengyu Luo <mitltlatltl@gmail.com>
  7. *
  8. * Based on vendor driver:
  9. * Copyright (c) 2023 AWINIC Technology CO., LTD
  10. */
  11. #include <linux/backlight.h>
  12. #include <linux/bitfield.h>
  13. #include <linux/delay.h>
  14. #include <linux/gpio/consumer.h>
  15. #include <linux/i2c.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/regmap.h>
  19. #define AW99706_MAX_BRT_LVL 4095
  20. #define AW99706_REG_MAX 0x1F
  21. #define AW99706_ID 0x07
  22. /* registers list */
  23. #define AW99706_CFG0_REG 0x00
  24. #define AW99706_DIM_MODE_MASK GENMASK(1, 0)
  25. #define AW99706_CFG1_REG 0x01
  26. #define AW99706_SW_FREQ_MASK GENMASK(3, 0)
  27. #define AW99706_SW_ILMT_MASK GENMASK(5, 4)
  28. #define AW99706_CFG2_REG 0x02
  29. #define AW99706_ILED_MAX_MASK GENMASK(6, 0)
  30. #define AW99706_UVLOSEL_MASK BIT(7)
  31. #define AW99706_CFG3_REG 0x03
  32. #define AW99706_CFG4_REG 0x04
  33. #define AW99706_BRT_MSB_MASK GENMASK(3, 0)
  34. #define AW99706_CFG5_REG 0x05
  35. #define AW99706_BRT_LSB_MASK GENMASK(7, 0)
  36. #define AW99706_CFG6_REG 0x06
  37. #define AW99706_RAMP_CTL_MASK GENMASK(7, 6)
  38. #define AW99706_CFG7_REG 0x07
  39. #define AW99706_CFG8_REG 0x08
  40. #define AW99706_CFG9_REG 0x09
  41. #define AW99706_CFGA_REG 0x0A
  42. #define AW99706_CFGB_REG 0x0B
  43. #define AW99706_CFGC_REG 0x0C
  44. #define AW99706_CFGD_REG 0x0D
  45. #define AW99706_FLAG_REG 0x10
  46. #define AW99706_BACKLIGHT_EN_MASK BIT(7)
  47. #define AW99706_CHIPID_REG 0x11
  48. #define AW99706_LED_OPEN_FLAG_REG 0x12
  49. #define AW99706_LED_SHORT_FLAG_REG 0x13
  50. #define AW99706_MTPLDOSEL_REG 0x1E
  51. #define AW99706_MTPRUN_REG 0x1F
  52. #define RESV 0
  53. /* Boost switching frequency table, in Hz */
  54. static const u32 aw99706_sw_freq_tbl[] = {
  55. RESV, RESV, RESV, RESV, 300000, 400000, 500000, 600000,
  56. 660000, 750000, 850000, 1000000, 1200000, 1330000, 1500000, 1700000
  57. };
  58. /* Switching current limitation table, in uA */
  59. static const u32 aw99706_sw_ilmt_tbl[] = {
  60. 1500000, 2000000, 2500000, 3000000
  61. };
  62. /* ULVO threshold table, in uV */
  63. static const u32 aw99706_ulvo_thres_tbl[] = {
  64. 2200000, 5000000
  65. };
  66. struct aw99706_dt_prop {
  67. const char * const name;
  68. int (*lookup)(const struct aw99706_dt_prop *prop, u32 dt_val, u8 *val);
  69. const u32 * const lookup_tbl;
  70. u8 tbl_size;
  71. u8 reg;
  72. u8 mask;
  73. u32 def_val;
  74. };
  75. static int aw99706_dt_property_lookup(const struct aw99706_dt_prop *prop,
  76. u32 dt_val, u8 *val)
  77. {
  78. int i;
  79. if (!prop->lookup_tbl) {
  80. *val = dt_val;
  81. return 0;
  82. }
  83. for (i = 0; i < prop->tbl_size; i++)
  84. if (prop->lookup_tbl[i] == dt_val)
  85. break;
  86. *val = i;
  87. return i == prop->tbl_size ? -1 : 0;
  88. }
  89. #define MIN_ILED_MAX 5000
  90. #define MAX_ILED_MAX 50000
  91. #define STEP_ILED_MAX 500
  92. static int
  93. aw99706_dt_property_iled_max_convert(const struct aw99706_dt_prop *prop,
  94. u32 dt_val, u8 *val)
  95. {
  96. if (dt_val > MAX_ILED_MAX || dt_val < MIN_ILED_MAX)
  97. return -1;
  98. *val = (dt_val - MIN_ILED_MAX) / STEP_ILED_MAX;
  99. return (dt_val - MIN_ILED_MAX) % STEP_ILED_MAX;
  100. }
  101. static const struct aw99706_dt_prop aw99706_dt_props[] = {
  102. {
  103. "awinic,dim-mode", aw99706_dt_property_lookup,
  104. NULL, 0,
  105. AW99706_CFG0_REG, AW99706_DIM_MODE_MASK, 1,
  106. },
  107. {
  108. "awinic,sw-freq", aw99706_dt_property_lookup,
  109. aw99706_sw_freq_tbl, ARRAY_SIZE(aw99706_sw_freq_tbl),
  110. AW99706_CFG1_REG, AW99706_SW_FREQ_MASK, 750000,
  111. },
  112. {
  113. "awinic,sw-ilmt", aw99706_dt_property_lookup,
  114. aw99706_sw_ilmt_tbl, ARRAY_SIZE(aw99706_sw_ilmt_tbl),
  115. AW99706_CFG1_REG, AW99706_SW_ILMT_MASK, 3000000,
  116. },
  117. {
  118. "awinic,iled-max", aw99706_dt_property_iled_max_convert,
  119. NULL, 0,
  120. AW99706_CFG2_REG, AW99706_ILED_MAX_MASK, 20000,
  121. },
  122. {
  123. "awinic,uvlo-thres", aw99706_dt_property_lookup,
  124. aw99706_ulvo_thres_tbl, ARRAY_SIZE(aw99706_ulvo_thres_tbl),
  125. AW99706_CFG2_REG, AW99706_UVLOSEL_MASK, 2200000,
  126. },
  127. {
  128. "awinic,ramp-ctl", aw99706_dt_property_lookup,
  129. NULL, 0,
  130. AW99706_CFG6_REG, AW99706_RAMP_CTL_MASK, 2,
  131. }
  132. };
  133. struct reg_init_data {
  134. u8 reg;
  135. u8 mask;
  136. u8 val;
  137. };
  138. struct aw99706_device {
  139. struct i2c_client *client;
  140. struct device *dev;
  141. struct regmap *regmap;
  142. struct backlight_device *bl_dev;
  143. struct gpio_desc *hwen_gpio;
  144. struct reg_init_data init_tbl[ARRAY_SIZE(aw99706_dt_props)];
  145. bool bl_enable;
  146. };
  147. enum reg_access {
  148. REG_NONE_ACCESS = 0,
  149. REG_RD_ACCESS = 1,
  150. REG_WR_ACCESS = 2,
  151. };
  152. static const u8 aw99706_regs[AW99706_REG_MAX + 1] = {
  153. [AW99706_CFG0_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  154. [AW99706_CFG1_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  155. [AW99706_CFG2_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  156. [AW99706_CFG3_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  157. [AW99706_CFG4_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  158. [AW99706_CFG5_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  159. [AW99706_CFG6_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  160. [AW99706_CFG7_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  161. [AW99706_CFG8_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  162. [AW99706_CFG9_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  163. [AW99706_CFGA_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  164. [AW99706_CFGB_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  165. [AW99706_CFGC_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  166. [AW99706_CFGD_REG] = REG_RD_ACCESS | REG_WR_ACCESS,
  167. [AW99706_FLAG_REG] = REG_RD_ACCESS,
  168. [AW99706_CHIPID_REG] = REG_RD_ACCESS,
  169. [AW99706_LED_OPEN_FLAG_REG] = REG_RD_ACCESS,
  170. [AW99706_LED_SHORT_FLAG_REG] = REG_RD_ACCESS,
  171. /*
  172. * Write bit is dropped here, writing BIT(0) to MTPLDOSEL will unlock
  173. * Multi-time Programmable (MTP).
  174. */
  175. [AW99706_MTPLDOSEL_REG] = REG_RD_ACCESS,
  176. [AW99706_MTPRUN_REG] = REG_NONE_ACCESS,
  177. };
  178. static bool aw99706_readable_reg(struct device *dev, unsigned int reg)
  179. {
  180. return aw99706_regs[reg] & REG_RD_ACCESS;
  181. }
  182. static bool aw99706_writeable_reg(struct device *dev, unsigned int reg)
  183. {
  184. return aw99706_regs[reg] & REG_WR_ACCESS;
  185. }
  186. static inline int aw99706_i2c_read(struct aw99706_device *aw, u8 reg,
  187. unsigned int *val)
  188. {
  189. return regmap_read(aw->regmap, reg, val);
  190. }
  191. static inline int aw99706_i2c_write(struct aw99706_device *aw, u8 reg, u8 val)
  192. {
  193. return regmap_write(aw->regmap, reg, val);
  194. }
  195. static inline int aw99706_i2c_update_bits(struct aw99706_device *aw, u8 reg,
  196. u8 mask, u8 val)
  197. {
  198. return regmap_update_bits(aw->regmap, reg, mask, val);
  199. }
  200. static void aw99706_dt_parse(struct aw99706_device *aw,
  201. struct backlight_properties *bl_props)
  202. {
  203. const struct aw99706_dt_prop *prop;
  204. u32 dt_val;
  205. int ret, i;
  206. u8 val;
  207. for (i = 0; i < ARRAY_SIZE(aw99706_dt_props); i++) {
  208. prop = &aw99706_dt_props[i];
  209. ret = device_property_read_u32(aw->dev, prop->name, &dt_val);
  210. if (ret < 0)
  211. dt_val = prop->def_val;
  212. if (prop->lookup(prop, dt_val, &val)) {
  213. dev_warn(aw->dev, "invalid value %d for property %s, using default value %d\n",
  214. dt_val, prop->name, prop->def_val);
  215. prop->lookup(prop, prop->def_val, &val);
  216. }
  217. aw->init_tbl[i].reg = prop->reg;
  218. aw->init_tbl[i].mask = prop->mask;
  219. aw->init_tbl[i].val = val << __ffs(prop->mask);
  220. }
  221. bl_props->brightness = AW99706_MAX_BRT_LVL >> 1;
  222. bl_props->max_brightness = AW99706_MAX_BRT_LVL;
  223. device_property_read_u32(aw->dev, "default-brightness",
  224. &bl_props->brightness);
  225. device_property_read_u32(aw->dev, "max-brightness",
  226. &bl_props->max_brightness);
  227. if (bl_props->max_brightness > AW99706_MAX_BRT_LVL)
  228. bl_props->max_brightness = AW99706_MAX_BRT_LVL;
  229. if (bl_props->brightness > bl_props->max_brightness)
  230. bl_props->brightness = bl_props->max_brightness;
  231. }
  232. static int aw99706_hw_init(struct aw99706_device *aw)
  233. {
  234. int ret, i;
  235. gpiod_set_value_cansleep(aw->hwen_gpio, 1);
  236. for (i = 0; i < ARRAY_SIZE(aw->init_tbl); i++) {
  237. ret = aw99706_i2c_update_bits(aw, aw->init_tbl[i].reg,
  238. aw->init_tbl[i].mask,
  239. aw->init_tbl[i].val);
  240. if (ret < 0) {
  241. dev_err(aw->dev, "Failed to write init data %d\n", ret);
  242. return ret;
  243. }
  244. }
  245. return 0;
  246. }
  247. static int aw99706_bl_enable(struct aw99706_device *aw, bool en)
  248. {
  249. int ret;
  250. u8 val;
  251. val = FIELD_PREP(AW99706_BACKLIGHT_EN_MASK, en);
  252. ret = aw99706_i2c_update_bits(aw, AW99706_CFGD_REG,
  253. AW99706_BACKLIGHT_EN_MASK, val);
  254. if (ret)
  255. dev_err(aw->dev, "Failed to enable backlight!\n");
  256. return ret;
  257. }
  258. static int aw99706_update_brightness(struct aw99706_device *aw, u32 brt_lvl)
  259. {
  260. bool bl_enable_now = !!brt_lvl;
  261. int ret;
  262. ret = aw99706_i2c_write(aw, AW99706_CFG4_REG,
  263. (brt_lvl >> 8) & AW99706_BRT_MSB_MASK);
  264. if (ret < 0)
  265. return ret;
  266. ret = aw99706_i2c_write(aw, AW99706_CFG5_REG,
  267. brt_lvl & AW99706_BRT_LSB_MASK);
  268. if (ret < 0)
  269. return ret;
  270. if (aw->bl_enable != bl_enable_now) {
  271. ret = aw99706_bl_enable(aw, bl_enable_now);
  272. if (!ret)
  273. aw->bl_enable = bl_enable_now;
  274. }
  275. return ret;
  276. }
  277. static int aw99706_bl_update_status(struct backlight_device *bl)
  278. {
  279. struct aw99706_device *aw = bl_get_data(bl);
  280. return aw99706_update_brightness(aw, bl->props.brightness);
  281. }
  282. static const struct backlight_ops aw99706_bl_ops = {
  283. .options = BL_CORE_SUSPENDRESUME,
  284. .update_status = aw99706_bl_update_status,
  285. };
  286. static const struct regmap_config aw99706_regmap_config = {
  287. .reg_bits = 8,
  288. .val_bits = 8,
  289. .max_register = AW99706_REG_MAX,
  290. .writeable_reg = aw99706_writeable_reg,
  291. .readable_reg = aw99706_readable_reg,
  292. };
  293. static int aw99706_chip_id_read(struct aw99706_device *aw)
  294. {
  295. int ret;
  296. unsigned int val;
  297. ret = aw99706_i2c_read(aw, AW99706_CHIPID_REG, &val);
  298. if (ret < 0)
  299. return ret;
  300. return val;
  301. }
  302. static int aw99706_probe(struct i2c_client *client)
  303. {
  304. struct device *dev = &client->dev;
  305. struct aw99706_device *aw;
  306. struct backlight_device *bl_dev;
  307. struct backlight_properties props = {};
  308. int ret = 0;
  309. aw = devm_kzalloc(dev, sizeof(*aw), GFP_KERNEL);
  310. if (!aw)
  311. return -ENOMEM;
  312. aw->client = client;
  313. aw->dev = dev;
  314. i2c_set_clientdata(client, aw);
  315. aw->regmap = devm_regmap_init_i2c(client, &aw99706_regmap_config);
  316. if (IS_ERR(aw->regmap))
  317. return dev_err_probe(dev, PTR_ERR(aw->regmap),
  318. "Failed to init regmap\n");
  319. ret = aw99706_chip_id_read(aw);
  320. if (ret != AW99706_ID)
  321. return dev_err_probe(dev, -ENODEV,
  322. "Unknown chip id 0x%02x\n", ret);
  323. aw99706_dt_parse(aw, &props);
  324. aw->hwen_gpio = devm_gpiod_get(aw->dev, "enable", GPIOD_OUT_LOW);
  325. if (IS_ERR(aw->hwen_gpio))
  326. return dev_err_probe(dev, PTR_ERR(aw->hwen_gpio),
  327. "Failed to get enable gpio\n");
  328. ret = aw99706_hw_init(aw);
  329. if (ret < 0)
  330. return dev_err_probe(dev, ret,
  331. "Failed to initialize the chip\n");
  332. props.type = BACKLIGHT_RAW;
  333. props.scale = BACKLIGHT_SCALE_LINEAR;
  334. bl_dev = devm_backlight_device_register(dev, "aw99706-backlight", dev,
  335. aw, &aw99706_bl_ops, &props);
  336. if (IS_ERR(bl_dev))
  337. return dev_err_probe(dev, PTR_ERR(bl_dev),
  338. "Failed to register backlight!\n");
  339. aw->bl_dev = bl_dev;
  340. return 0;
  341. }
  342. static void aw99706_remove(struct i2c_client *client)
  343. {
  344. struct aw99706_device *aw = i2c_get_clientdata(client);
  345. aw99706_update_brightness(aw, 0);
  346. msleep(50);
  347. gpiod_set_value_cansleep(aw->hwen_gpio, 0);
  348. }
  349. static int aw99706_suspend(struct device *dev)
  350. {
  351. struct aw99706_device *aw = dev_get_drvdata(dev);
  352. return aw99706_update_brightness(aw, 0);
  353. }
  354. static int aw99706_resume(struct device *dev)
  355. {
  356. struct aw99706_device *aw = dev_get_drvdata(dev);
  357. return aw99706_hw_init(aw);
  358. }
  359. static DEFINE_SIMPLE_DEV_PM_OPS(aw99706_pm_ops, aw99706_suspend, aw99706_resume);
  360. static const struct i2c_device_id aw99706_ids[] = {
  361. { "aw99706" },
  362. { }
  363. };
  364. MODULE_DEVICE_TABLE(i2c, aw99706_ids);
  365. static const struct of_device_id aw99706_match_table[] = {
  366. { .compatible = "awinic,aw99706", },
  367. { }
  368. };
  369. MODULE_DEVICE_TABLE(of, aw99706_match_table);
  370. static struct i2c_driver aw99706_i2c_driver = {
  371. .probe = aw99706_probe,
  372. .remove = aw99706_remove,
  373. .id_table = aw99706_ids,
  374. .driver = {
  375. .name = "aw99706",
  376. .of_match_table = aw99706_match_table,
  377. .pm = pm_ptr(&aw99706_pm_ops),
  378. },
  379. };
  380. module_i2c_driver(aw99706_i2c_driver);
  381. MODULE_LICENSE("GPL v2");
  382. MODULE_DESCRIPTION("BackLight driver for aw99706");