leds-aw200xx.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Awinic AW20036/AW20054/AW20072/AW20108 LED driver
  4. *
  5. * Copyright (c) 2023, SberDevices. All Rights Reserved.
  6. *
  7. * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru>
  8. */
  9. #include <linux/bitfield.h>
  10. #include <linux/bits.h>
  11. #include <linux/container_of.h>
  12. #include <linux/gpio/consumer.h>
  13. #include <linux/i2c.h>
  14. #include <linux/leds.h>
  15. #include <linux/mod_devicetable.h>
  16. #include <linux/module.h>
  17. #include <linux/mutex.h>
  18. #include <linux/regmap.h>
  19. #include <linux/time.h>
  20. #include <linux/units.h>
  21. #define AW200XX_DIM_MAX (BIT(6) - 1)
  22. #define AW200XX_FADE_MAX (BIT(8) - 1)
  23. #define AW200XX_IMAX_DEFAULT_uA 60000
  24. #define AW200XX_IMAX_MAX_uA 160000
  25. #define AW200XX_IMAX_MIN_uA 3300
  26. /* Page 0 */
  27. #define AW200XX_REG_PAGE0_BASE 0xc000
  28. /* Select page register */
  29. #define AW200XX_REG_PAGE 0xF0
  30. #define AW200XX_PAGE_MASK (GENMASK(7, 6) | GENMASK(2, 0))
  31. #define AW200XX_PAGE_SHIFT 0
  32. #define AW200XX_NUM_PAGES 6
  33. #define AW200XX_PAGE_SIZE 256
  34. #define AW200XX_REG(page, reg) \
  35. (AW200XX_REG_PAGE0_BASE + (page) * AW200XX_PAGE_SIZE + (reg))
  36. #define AW200XX_REG_MAX \
  37. AW200XX_REG(AW200XX_NUM_PAGES - 1, AW200XX_PAGE_SIZE - 1)
  38. #define AW200XX_PAGE0 0
  39. #define AW200XX_PAGE1 1
  40. #define AW200XX_PAGE2 2
  41. #define AW200XX_PAGE3 3
  42. #define AW200XX_PAGE4 4
  43. #define AW200XX_PAGE5 5
  44. /* Chip ID register */
  45. #define AW200XX_REG_IDR AW200XX_REG(AW200XX_PAGE0, 0x00)
  46. #define AW200XX_IDR_CHIPID 0x18
  47. /* Sleep mode register */
  48. #define AW200XX_REG_SLPCR AW200XX_REG(AW200XX_PAGE0, 0x01)
  49. #define AW200XX_SLPCR_ACTIVE 0x00
  50. /* Reset register */
  51. #define AW200XX_REG_RSTR AW200XX_REG(AW200XX_PAGE0, 0x02)
  52. #define AW200XX_RSTR_RESET 0x01
  53. /* Global current configuration register */
  54. #define AW200XX_REG_GCCR AW200XX_REG(AW200XX_PAGE0, 0x03)
  55. #define AW200XX_GCCR_IMAX_MASK GENMASK(7, 4)
  56. #define AW200XX_GCCR_IMAX(x) ((x) << 4)
  57. #define AW200XX_GCCR_ALLON BIT(3)
  58. /* Fast clear display control register */
  59. #define AW200XX_REG_FCD AW200XX_REG(AW200XX_PAGE0, 0x04)
  60. #define AW200XX_FCD_CLEAR 0x01
  61. /* Display size configuration */
  62. #define AW200XX_REG_DSIZE AW200XX_REG(AW200XX_PAGE0, 0x80)
  63. #define AW200XX_DSIZE_COLUMNS_MAX 12
  64. #define AW200XX_LED2REG(x, columns) \
  65. ((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns))))
  66. /* DIM current configuration register on page 1 */
  67. #define AW200XX_REG_DIM_PAGE1(x, columns) \
  68. AW200XX_REG(AW200XX_PAGE1, AW200XX_LED2REG(x, columns))
  69. /*
  70. * DIM current configuration register (page 4).
  71. * The even address for current DIM configuration.
  72. * The odd address for current FADE configuration
  73. */
  74. #define AW200XX_REG_DIM(x, columns) \
  75. AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2)
  76. #define AW200XX_REG_DIM2FADE(x) ((x) + 1)
  77. #define AW200XX_REG_FADE2DIM(fade) \
  78. DIV_ROUND_UP((fade) * AW200XX_DIM_MAX, AW200XX_FADE_MAX)
  79. /*
  80. * Duty ratio of display scan (see p.15 of datasheet for formula):
  81. * duty = (592us / 600.5us) * (1 / (display_rows + 1))
  82. *
  83. * Multiply to 1000 (MILLI) to improve the accuracy of calculations.
  84. */
  85. #define AW200XX_DUTY_RATIO(rows) \
  86. (((592UL * USEC_PER_SEC) / 600500UL) * (MILLI / (rows)) / MILLI)
  87. struct aw200xx_chipdef {
  88. u32 channels;
  89. u32 display_size_rows_max;
  90. u32 display_size_columns;
  91. };
  92. struct aw200xx_led {
  93. struct led_classdev cdev;
  94. struct aw200xx *chip;
  95. int dim;
  96. u32 num;
  97. };
  98. struct aw200xx {
  99. const struct aw200xx_chipdef *cdef;
  100. struct i2c_client *client;
  101. struct regmap *regmap;
  102. struct mutex mutex;
  103. u32 num_leds;
  104. u32 display_rows;
  105. struct gpio_desc *hwen;
  106. struct aw200xx_led leds[] __counted_by(num_leds);
  107. };
  108. static ssize_t dim_show(struct device *dev, struct device_attribute *devattr,
  109. char *buf)
  110. {
  111. struct led_classdev *cdev = dev_get_drvdata(dev);
  112. struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
  113. int dim = led->dim;
  114. if (dim < 0)
  115. return sysfs_emit(buf, "auto\n");
  116. return sysfs_emit(buf, "%d\n", dim);
  117. }
  118. static ssize_t dim_store(struct device *dev, struct device_attribute *devattr,
  119. const char *buf, size_t count)
  120. {
  121. struct led_classdev *cdev = dev_get_drvdata(dev);
  122. struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
  123. struct aw200xx *chip = led->chip;
  124. u32 columns = chip->cdef->display_size_columns;
  125. int dim;
  126. ssize_t ret;
  127. if (sysfs_streq(buf, "auto")) {
  128. dim = -1;
  129. } else {
  130. ret = kstrtoint(buf, 0, &dim);
  131. if (ret)
  132. return ret;
  133. if (dim > AW200XX_DIM_MAX)
  134. return -EINVAL;
  135. }
  136. mutex_lock(&chip->mutex);
  137. if (dim >= 0) {
  138. ret = regmap_write(chip->regmap,
  139. AW200XX_REG_DIM_PAGE1(led->num, columns),
  140. dim);
  141. if (ret)
  142. goto out_unlock;
  143. }
  144. led->dim = dim;
  145. ret = count;
  146. out_unlock:
  147. mutex_unlock(&chip->mutex);
  148. return ret;
  149. }
  150. static DEVICE_ATTR_RW(dim);
  151. static struct attribute *dim_attrs[] = {
  152. &dev_attr_dim.attr,
  153. NULL
  154. };
  155. ATTRIBUTE_GROUPS(dim);
  156. static int aw200xx_brightness_set(struct led_classdev *cdev,
  157. enum led_brightness brightness)
  158. {
  159. struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev);
  160. struct aw200xx *chip = led->chip;
  161. int dim;
  162. u32 reg;
  163. int ret;
  164. mutex_lock(&chip->mutex);
  165. reg = AW200XX_REG_DIM(led->num, chip->cdef->display_size_columns);
  166. dim = led->dim;
  167. if (dim < 0)
  168. dim = AW200XX_REG_FADE2DIM(brightness);
  169. ret = regmap_write(chip->regmap, reg, dim);
  170. if (ret)
  171. goto out_unlock;
  172. ret = regmap_write(chip->regmap,
  173. AW200XX_REG_DIM2FADE(reg), brightness);
  174. out_unlock:
  175. mutex_unlock(&chip->mutex);
  176. return ret;
  177. }
  178. static u32 aw200xx_imax_from_global(const struct aw200xx *const chip,
  179. u32 global_imax_uA)
  180. {
  181. u64 led_imax_uA;
  182. /*
  183. * The output current of each LED (see p.14 of datasheet for formula):
  184. * Iled = Imax * (dim / 63) * ((fade + 1) / 256) * duty
  185. *
  186. * The value of duty is determined by the following formula:
  187. * duty = (592us / 600.5us) * (1 / (display_rows + 1))
  188. *
  189. * Calculated for the maximum values of fade and dim.
  190. * We divide by 1000 because we earlier multiplied by 1000 to improve
  191. * accuracy when calculating the duty.
  192. */
  193. led_imax_uA = global_imax_uA * AW200XX_DUTY_RATIO(chip->display_rows);
  194. do_div(led_imax_uA, MILLI);
  195. return led_imax_uA;
  196. }
  197. static u32 aw200xx_imax_to_global(const struct aw200xx *const chip,
  198. u32 led_imax_uA)
  199. {
  200. u32 duty = AW200XX_DUTY_RATIO(chip->display_rows);
  201. /* The output current of each LED (see p.14 of datasheet for formula) */
  202. return (led_imax_uA * 1000U) / duty;
  203. }
  204. #define AW200XX_IMAX_MULTIPLIER1 10000
  205. #define AW200XX_IMAX_MULTIPLIER2 3333
  206. #define AW200XX_IMAX_BASE_VAL1 0
  207. #define AW200XX_IMAX_BASE_VAL2 8
  208. /*
  209. * The AW200XX has a 4-bit register (GCCR) to configure the global current,
  210. * which ranges from 3.3mA to 160mA. The following table indicates the values
  211. * of the global current, divided into two parts:
  212. *
  213. * +-----------+-----------------+-----------+-----------------+
  214. * | reg value | global max (mA) | reg value | global max (mA) |
  215. * +-----------+-----------------+-----------+-----------------+
  216. * | 0 | 10 | 8 | 3.3 |
  217. * | 1 | 20 | 9 | 6.7 |
  218. * | 2 | 30 | 10 | 10 |
  219. * | 3 | 40 | 11 | 13.3 |
  220. * | 4 | 60 | 12 | 20 |
  221. * | 5 | 80 | 13 | 26.7 |
  222. * | 6 | 120 | 14 | 40 |
  223. * | 7 | 160 | 15 | 53.3 |
  224. * +-----------+-----------------+-----------+-----------------+
  225. *
  226. * The left part with a multiplier of 10, and the right part with a multiplier
  227. * of 3.3.
  228. * So we have two formulas to calculate the global current:
  229. * for the left part of the table:
  230. * imax = coefficient * 10
  231. *
  232. * for the right part of the table:
  233. * imax = coefficient * 3.3
  234. *
  235. * The coefficient table consists of the following values:
  236. * 1, 2, 3, 4, 6, 8, 12, 16.
  237. */
  238. static int aw200xx_set_imax(const struct aw200xx *const chip,
  239. u32 led_imax_uA)
  240. {
  241. u32 g_imax_uA = aw200xx_imax_to_global(chip, led_imax_uA);
  242. static const u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16};
  243. u32 gccr_imax = UINT_MAX;
  244. u32 cur_imax = 0;
  245. int i;
  246. for (i = 0; i < ARRAY_SIZE(coeff_table); i++) {
  247. u32 imax;
  248. /* select closest ones */
  249. imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER1;
  250. if (g_imax_uA >= imax && imax > cur_imax) {
  251. cur_imax = imax;
  252. gccr_imax = i + AW200XX_IMAX_BASE_VAL1;
  253. }
  254. imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER2;
  255. imax = DIV_ROUND_CLOSEST(imax, 100) * 100;
  256. if (g_imax_uA >= imax && imax > cur_imax) {
  257. cur_imax = imax;
  258. gccr_imax = i + AW200XX_IMAX_BASE_VAL2;
  259. }
  260. }
  261. if (gccr_imax == UINT_MAX)
  262. return -EINVAL;
  263. return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR,
  264. AW200XX_GCCR_IMAX_MASK,
  265. AW200XX_GCCR_IMAX(gccr_imax));
  266. }
  267. static int aw200xx_chip_reset(const struct aw200xx *const chip)
  268. {
  269. int ret;
  270. ret = regmap_write(chip->regmap, AW200XX_REG_RSTR, AW200XX_RSTR_RESET);
  271. if (ret)
  272. return ret;
  273. /* According to the datasheet software reset takes at least 1ms */
  274. fsleep(1000);
  275. regcache_mark_dirty(chip->regmap);
  276. return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR);
  277. }
  278. static int aw200xx_chip_init(const struct aw200xx *const chip)
  279. {
  280. int ret;
  281. ret = regmap_write(chip->regmap, AW200XX_REG_DSIZE,
  282. chip->display_rows - 1);
  283. if (ret)
  284. return ret;
  285. ret = regmap_write(chip->regmap, AW200XX_REG_SLPCR,
  286. AW200XX_SLPCR_ACTIVE);
  287. if (ret)
  288. return ret;
  289. return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR,
  290. AW200XX_GCCR_ALLON, AW200XX_GCCR_ALLON);
  291. }
  292. static int aw200xx_chip_check(const struct aw200xx *const chip)
  293. {
  294. struct device *dev = &chip->client->dev;
  295. u32 chipid;
  296. int ret;
  297. ret = regmap_read(chip->regmap, AW200XX_REG_IDR, &chipid);
  298. if (ret)
  299. return dev_err_probe(dev, ret, "Failed to read chip ID\n");
  300. if (chipid != AW200XX_IDR_CHIPID)
  301. return dev_err_probe(dev, -ENODEV,
  302. "Chip reported wrong ID: %x\n", chipid);
  303. return 0;
  304. }
  305. static void aw200xx_enable(const struct aw200xx *const chip)
  306. {
  307. gpiod_set_value_cansleep(chip->hwen, 1);
  308. /*
  309. * After HWEN pin set high the chip begins to load the OTP information,
  310. * which takes 200us to complete. About 200us wait time is needed for
  311. * internal oscillator startup and display SRAM initialization. After
  312. * display SRAM initialization, the registers in page1 to page5 can be
  313. * configured via i2c interface.
  314. */
  315. fsleep(400);
  316. }
  317. static void aw200xx_disable(const struct aw200xx *const chip)
  318. {
  319. return gpiod_set_value_cansleep(chip->hwen, 0);
  320. }
  321. static int aw200xx_probe_get_display_rows(struct device *dev,
  322. struct aw200xx *chip)
  323. {
  324. struct fwnode_handle *child;
  325. u32 max_source = 0;
  326. device_for_each_child_node(dev, child) {
  327. u32 source;
  328. int ret;
  329. ret = fwnode_property_read_u32(child, "reg", &source);
  330. if (ret || source >= chip->cdef->channels)
  331. continue;
  332. max_source = max(max_source, source);
  333. }
  334. if (max_source == 0)
  335. return -EINVAL;
  336. chip->display_rows = max_source / chip->cdef->display_size_columns + 1;
  337. return 0;
  338. }
  339. static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
  340. {
  341. struct fwnode_handle *child;
  342. u32 current_min, current_max, min_uA;
  343. int ret;
  344. int i;
  345. ret = aw200xx_probe_get_display_rows(dev, chip);
  346. if (ret)
  347. return dev_err_probe(dev, ret,
  348. "No valid led definitions found\n");
  349. current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA);
  350. current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA);
  351. min_uA = UINT_MAX;
  352. i = 0;
  353. device_for_each_child_node(dev, child) {
  354. struct led_init_data init_data = {};
  355. struct aw200xx_led *led;
  356. u32 source, imax;
  357. ret = fwnode_property_read_u32(child, "reg", &source);
  358. if (ret) {
  359. dev_err(dev, "Missing reg property\n");
  360. chip->num_leds--;
  361. continue;
  362. }
  363. if (source >= chip->cdef->channels) {
  364. dev_err(dev, "LED reg %u out of range (max %u)\n",
  365. source, chip->cdef->channels);
  366. chip->num_leds--;
  367. continue;
  368. }
  369. ret = fwnode_property_read_u32(child, "led-max-microamp",
  370. &imax);
  371. if (ret) {
  372. dev_info(&chip->client->dev,
  373. "DT property led-max-microamp is missing\n");
  374. } else if (imax < current_min || imax > current_max) {
  375. dev_err(dev, "Invalid value %u for led-max-microamp\n",
  376. imax);
  377. chip->num_leds--;
  378. continue;
  379. } else {
  380. min_uA = min(min_uA, imax);
  381. }
  382. led = &chip->leds[i];
  383. led->dim = -1;
  384. led->num = source;
  385. led->chip = chip;
  386. led->cdev.brightness_set_blocking = aw200xx_brightness_set;
  387. led->cdev.max_brightness = AW200XX_FADE_MAX;
  388. led->cdev.groups = dim_groups;
  389. init_data.fwnode = child;
  390. ret = devm_led_classdev_register_ext(dev, &led->cdev,
  391. &init_data);
  392. if (ret) {
  393. fwnode_handle_put(child);
  394. break;
  395. }
  396. i++;
  397. }
  398. if (!chip->num_leds)
  399. return -EINVAL;
  400. if (min_uA == UINT_MAX) {
  401. min_uA = aw200xx_imax_from_global(chip,
  402. AW200XX_IMAX_DEFAULT_uA);
  403. }
  404. return aw200xx_set_imax(chip, min_uA);
  405. }
  406. static const struct regmap_range_cfg aw200xx_ranges[] = {
  407. {
  408. .name = "aw200xx",
  409. .range_min = 0,
  410. .range_max = AW200XX_REG_MAX,
  411. .selector_reg = AW200XX_REG_PAGE,
  412. .selector_mask = AW200XX_PAGE_MASK,
  413. .selector_shift = AW200XX_PAGE_SHIFT,
  414. .window_start = 0,
  415. .window_len = AW200XX_PAGE_SIZE,
  416. },
  417. };
  418. static const struct regmap_range aw200xx_writeonly_ranges[] = {
  419. regmap_reg_range(AW200XX_REG(AW200XX_PAGE1, 0x00), AW200XX_REG_MAX),
  420. };
  421. static const struct regmap_access_table aw200xx_readable_table = {
  422. .no_ranges = aw200xx_writeonly_ranges,
  423. .n_no_ranges = ARRAY_SIZE(aw200xx_writeonly_ranges),
  424. };
  425. static const struct regmap_range aw200xx_readonly_ranges[] = {
  426. regmap_reg_range(AW200XX_REG_IDR, AW200XX_REG_IDR),
  427. };
  428. static const struct regmap_access_table aw200xx_writeable_table = {
  429. .no_ranges = aw200xx_readonly_ranges,
  430. .n_no_ranges = ARRAY_SIZE(aw200xx_readonly_ranges),
  431. };
  432. static const struct regmap_config aw200xx_regmap_config = {
  433. .reg_bits = 8,
  434. .val_bits = 8,
  435. .max_register = AW200XX_REG_MAX,
  436. .ranges = aw200xx_ranges,
  437. .num_ranges = ARRAY_SIZE(aw200xx_ranges),
  438. .rd_table = &aw200xx_readable_table,
  439. .wr_table = &aw200xx_writeable_table,
  440. .cache_type = REGCACHE_MAPLE,
  441. .disable_locking = true,
  442. };
  443. static void aw200xx_chip_reset_action(void *data)
  444. {
  445. aw200xx_chip_reset(data);
  446. }
  447. static void aw200xx_disable_action(void *data)
  448. {
  449. aw200xx_disable(data);
  450. }
  451. static int aw200xx_probe(struct i2c_client *client)
  452. {
  453. const struct aw200xx_chipdef *cdef;
  454. struct aw200xx *chip;
  455. int count;
  456. int ret;
  457. cdef = device_get_match_data(&client->dev);
  458. if (!cdef)
  459. return -ENODEV;
  460. count = device_get_child_node_count(&client->dev);
  461. if (!count || count > cdef->channels)
  462. return dev_err_probe(&client->dev, -EINVAL,
  463. "Incorrect number of leds (%d)", count);
  464. chip = devm_kzalloc(&client->dev, struct_size(chip, leds, count),
  465. GFP_KERNEL);
  466. if (!chip)
  467. return -ENOMEM;
  468. chip->cdef = cdef;
  469. chip->num_leds = count;
  470. chip->client = client;
  471. i2c_set_clientdata(client, chip);
  472. chip->regmap = devm_regmap_init_i2c(client, &aw200xx_regmap_config);
  473. if (IS_ERR(chip->regmap))
  474. return PTR_ERR(chip->regmap);
  475. chip->hwen = devm_gpiod_get_optional(&client->dev, "enable",
  476. GPIOD_OUT_HIGH);
  477. if (IS_ERR(chip->hwen))
  478. return dev_err_probe(&client->dev, PTR_ERR(chip->hwen),
  479. "Cannot get enable GPIO");
  480. aw200xx_enable(chip);
  481. ret = devm_add_action(&client->dev, aw200xx_disable_action, chip);
  482. if (ret)
  483. return ret;
  484. ret = aw200xx_chip_check(chip);
  485. if (ret)
  486. return ret;
  487. ret = devm_mutex_init(&client->dev, &chip->mutex);
  488. if (ret)
  489. return ret;
  490. /* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */
  491. mutex_lock(&chip->mutex);
  492. ret = aw200xx_chip_reset(chip);
  493. if (ret)
  494. goto out_unlock;
  495. ret = devm_add_action(&client->dev, aw200xx_chip_reset_action, chip);
  496. if (ret)
  497. goto out_unlock;
  498. ret = aw200xx_probe_fw(&client->dev, chip);
  499. if (ret)
  500. goto out_unlock;
  501. ret = aw200xx_chip_init(chip);
  502. out_unlock:
  503. if (ret)
  504. aw200xx_disable(chip);
  505. mutex_unlock(&chip->mutex);
  506. return ret;
  507. }
  508. static const struct aw200xx_chipdef aw20036_cdef = {
  509. .channels = 36,
  510. .display_size_rows_max = 3,
  511. .display_size_columns = 12,
  512. };
  513. static const struct aw200xx_chipdef aw20054_cdef = {
  514. .channels = 54,
  515. .display_size_rows_max = 6,
  516. .display_size_columns = 9,
  517. };
  518. static const struct aw200xx_chipdef aw20072_cdef = {
  519. .channels = 72,
  520. .display_size_rows_max = 6,
  521. .display_size_columns = 12,
  522. };
  523. static const struct aw200xx_chipdef aw20108_cdef = {
  524. .channels = 108,
  525. .display_size_rows_max = 9,
  526. .display_size_columns = 12,
  527. };
  528. static const struct i2c_device_id aw200xx_id[] = {
  529. { "aw20036" },
  530. { "aw20054" },
  531. { "aw20072" },
  532. { "aw20108" },
  533. {}
  534. };
  535. MODULE_DEVICE_TABLE(i2c, aw200xx_id);
  536. static const struct of_device_id aw200xx_match_table[] = {
  537. { .compatible = "awinic,aw20036", .data = &aw20036_cdef, },
  538. { .compatible = "awinic,aw20054", .data = &aw20054_cdef, },
  539. { .compatible = "awinic,aw20072", .data = &aw20072_cdef, },
  540. { .compatible = "awinic,aw20108", .data = &aw20108_cdef, },
  541. {}
  542. };
  543. MODULE_DEVICE_TABLE(of, aw200xx_match_table);
  544. static struct i2c_driver aw200xx_driver = {
  545. .driver = {
  546. .name = "aw200xx",
  547. .of_match_table = aw200xx_match_table,
  548. },
  549. .probe = aw200xx_probe,
  550. .id_table = aw200xx_id,
  551. };
  552. module_i2c_driver(aw200xx_driver);
  553. MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>");
  554. MODULE_DESCRIPTION("AW200XX LED driver");
  555. MODULE_LICENSE("GPL");