leds-mt6370-flash.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2023 Richtek Technology Corp.
  4. *
  5. * Authors:
  6. * Alice Chen <alice_chen@richtek.com>
  7. * ChiYuan Huang <cy_huang@richtek.com>
  8. */
  9. #include <linux/bitops.h>
  10. #include <linux/delay.h>
  11. #include <linux/init.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/kernel.h>
  14. #include <linux/led-class-flash.h>
  15. #include <linux/module.h>
  16. #include <linux/mutex.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/property.h>
  19. #include <linux/regmap.h>
  20. #include <media/v4l2-flash-led-class.h>
  21. enum {
  22. MT6370_LED_FLASH1 = 0,
  23. MT6370_LED_FLASH2,
  24. MT6370_MAX_LEDS
  25. };
  26. /* Virtual definition for multicolor */
  27. #define MT6370_REG_FLEDEN 0x17E
  28. #define MT6370_REG_STRBTO 0x173
  29. #define MT6370_REG_CHGSTAT2 0x1D1
  30. #define MT6370_REG_FLEDSTAT1 0x1D9
  31. #define MT6370_REG_FLEDISTRB(_id) (0x174 + 4 * (_id))
  32. #define MT6370_REG_FLEDITOR(_id) (0x175 + 4 * (_id))
  33. #define MT6370_ITORCH_MASK GENMASK(4, 0)
  34. #define MT6370_ISTROBE_MASK GENMASK(6, 0)
  35. #define MT6370_STRBTO_MASK GENMASK(6, 0)
  36. #define MT6370_TORCHEN_MASK BIT(3)
  37. #define MT6370_STROBEN_MASK BIT(2)
  38. #define MT6370_FLCSEN_MASK(_id) BIT(MT6370_LED_FLASH2 - (_id))
  39. #define MT6370_FLCSEN_MASK_ALL GENMASK(1, 0)
  40. #define MT6370_FLEDCHGVINOVP_MASK BIT(3)
  41. #define MT6370_FLED1STRBTO_MASK BIT(11)
  42. #define MT6370_FLED2STRBTO_MASK BIT(10)
  43. #define MT6370_FLED1STRB_MASK BIT(9)
  44. #define MT6370_FLED2STRB_MASK BIT(8)
  45. #define MT6370_FLED1SHORT_MASK BIT(7)
  46. #define MT6370_FLED2SHORT_MASK BIT(6)
  47. #define MT6370_FLEDLVF_MASK BIT(3)
  48. #define MT6370_LED_JOINT 2
  49. #define MT6370_RANGE_FLED_REG 4
  50. #define MT6370_ITORCH_MIN_uA 25000
  51. #define MT6370_ITORCH_STEP_uA 12500
  52. #define MT6370_ITORCH_MAX_uA 400000
  53. #define MT6370_ITORCH_DOUBLE_MAX_uA 800000
  54. #define MT6370_ISTRB_MIN_uA 50000
  55. #define MT6370_ISTRB_STEP_uA 12500
  56. #define MT6370_ISTRB_MAX_uA 1500000
  57. #define MT6370_ISTRB_DOUBLE_MAX_uA 3000000
  58. #define MT6370_STRBTO_MIN_US 64000
  59. #define MT6370_STRBTO_STEP_US 32000
  60. #define MT6370_STRBTO_MAX_US 2432000
  61. #define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member)
  62. struct mt6370_led {
  63. struct led_classdev_flash flash;
  64. struct v4l2_flash *v4l2_flash;
  65. struct mt6370_priv *priv;
  66. u8 led_no;
  67. };
  68. struct mt6370_priv {
  69. struct regmap *regmap;
  70. struct mutex lock;
  71. unsigned int fled_strobe_used;
  72. unsigned int fled_torch_used;
  73. unsigned int leds_active;
  74. unsigned int leds_count;
  75. struct mt6370_led leds[] __counted_by(leds_count);
  76. };
  77. static int mt6370_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness level)
  78. {
  79. struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
  80. struct mt6370_priv *priv = led->priv;
  81. u32 led_enable_mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL :
  82. MT6370_FLCSEN_MASK(led->led_no);
  83. u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
  84. u32 val = level ? led_enable_mask : 0;
  85. u32 curr;
  86. int ret, i;
  87. mutex_lock(&priv->lock);
  88. /*
  89. * There is only one set of flash control logic, and this flag is used to check if 'strobe'
  90. * is currently being used.
  91. */
  92. if (priv->fled_strobe_used) {
  93. dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", priv->fled_strobe_used);
  94. ret = -EBUSY;
  95. goto unlock;
  96. }
  97. if (level)
  98. curr = priv->fled_torch_used | BIT(led->led_no);
  99. else
  100. curr = priv->fled_torch_used & ~BIT(led->led_no);
  101. if (curr)
  102. val |= MT6370_TORCHEN_MASK;
  103. if (level) {
  104. level -= 1;
  105. if (led->led_no == MT6370_LED_JOINT) {
  106. u32 flevel[MT6370_MAX_LEDS];
  107. /*
  108. * There're two flash channels in MT6370. If joint flash output is used,
  109. * torch current will be averaged output from both channels.
  110. */
  111. flevel[0] = level / 2;
  112. flevel[1] = level - flevel[0];
  113. for (i = 0; i < MT6370_MAX_LEDS; i++) {
  114. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDITOR(i),
  115. MT6370_ITORCH_MASK, flevel[i]);
  116. if (ret)
  117. goto unlock;
  118. }
  119. } else {
  120. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDITOR(led->led_no),
  121. MT6370_ITORCH_MASK, level);
  122. if (ret)
  123. goto unlock;
  124. }
  125. }
  126. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, val);
  127. if (ret)
  128. goto unlock;
  129. priv->fled_torch_used = curr;
  130. unlock:
  131. mutex_unlock(&priv->lock);
  132. return ret;
  133. }
  134. static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness)
  135. {
  136. /*
  137. * Because of the current spikes when turning on the flash, the brightness should be kept
  138. * by the LED framework. This empty function is used to prevent checking failure when
  139. * led_classdev_flash registers ops.
  140. */
  141. return 0;
  142. }
  143. static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness)
  144. {
  145. struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
  146. struct mt6370_priv *priv = led->priv;
  147. struct led_flash_setting *setting = &fl_cdev->brightness;
  148. u32 val = (brightness - setting->min) / setting->step;
  149. int ret, i;
  150. if (led->led_no == MT6370_LED_JOINT) {
  151. u32 flevel[MT6370_MAX_LEDS];
  152. /*
  153. * There're two flash channels in MT6370. If joint flash output is used, storbe
  154. * current will be averaged output from both channels.
  155. */
  156. flevel[0] = val / 2;
  157. flevel[1] = val - flevel[0];
  158. for (i = 0; i < MT6370_MAX_LEDS; i++) {
  159. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDISTRB(i),
  160. MT6370_ISTROBE_MASK, flevel[i]);
  161. if (ret)
  162. break;
  163. }
  164. } else {
  165. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDISTRB(led->led_no),
  166. MT6370_ISTROBE_MASK, val);
  167. }
  168. return ret;
  169. }
  170. static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
  171. {
  172. struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
  173. struct mt6370_priv *priv = led->priv;
  174. struct led_classdev *lcdev = &fl_cdev->led_cdev;
  175. struct led_flash_setting *s = &fl_cdev->brightness;
  176. u32 led_enable_mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL :
  177. MT6370_FLCSEN_MASK(led->led_no);
  178. u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask;
  179. u32 val = state ? led_enable_mask : 0;
  180. u32 curr;
  181. int ret;
  182. mutex_lock(&priv->lock);
  183. /*
  184. * There is only one set of flash control logic, and this flag is used to check if 'torch'
  185. * is currently being used.
  186. */
  187. if (priv->fled_torch_used) {
  188. dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", priv->fled_torch_used);
  189. ret = -EBUSY;
  190. goto unlock;
  191. }
  192. if (state)
  193. curr = priv->fled_strobe_used | BIT(led->led_no);
  194. else
  195. curr = priv->fled_strobe_used & ~BIT(led->led_no);
  196. if (curr)
  197. val |= MT6370_STROBEN_MASK;
  198. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask, val);
  199. if (ret) {
  200. dev_err(lcdev->dev, "[%d] control current source %d fail\n", led->led_no, state);
  201. goto unlock;
  202. }
  203. /*
  204. * If the flash needs to turn on, configure the flash current to ramp up to the setting
  205. * value. Otherwise, always revert to the minimum one.
  206. */
  207. ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min);
  208. if (ret) {
  209. dev_err(lcdev->dev, "[%d] Failed to set brightness\n", led->led_no);
  210. goto unlock;
  211. }
  212. /*
  213. * For the flash to turn on/off, we must wait for HW ramping up/down time 5ms/500us to
  214. * prevent the unexpected problem.
  215. */
  216. if (!priv->fled_strobe_used && curr)
  217. usleep_range(5000, 6000);
  218. else if (priv->fled_strobe_used && !curr)
  219. usleep_range(500, 600);
  220. priv->fled_strobe_used = curr;
  221. unlock:
  222. mutex_unlock(&priv->lock);
  223. return ret;
  224. }
  225. static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
  226. {
  227. struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
  228. struct mt6370_priv *priv = led->priv;
  229. mutex_lock(&priv->lock);
  230. *state = !!(priv->fled_strobe_used & BIT(led->led_no));
  231. mutex_unlock(&priv->lock);
  232. return 0;
  233. }
  234. static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
  235. {
  236. struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
  237. struct mt6370_priv *priv = led->priv;
  238. struct led_flash_setting *s = &fl_cdev->timeout;
  239. u32 val = (timeout - s->min) / s->step;
  240. return regmap_update_bits(priv->regmap, MT6370_REG_STRBTO, MT6370_STRBTO_MASK, val);
  241. }
  242. static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
  243. {
  244. struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
  245. struct mt6370_priv *priv = led->priv;
  246. u16 fled_stat;
  247. unsigned int chg_stat, strobe_timeout_mask, fled_short_mask;
  248. u32 rfault = 0;
  249. int ret;
  250. ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat);
  251. if (ret)
  252. return ret;
  253. ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat, sizeof(fled_stat));
  254. if (ret)
  255. return ret;
  256. switch (led->led_no) {
  257. case MT6370_LED_FLASH1:
  258. strobe_timeout_mask = MT6370_FLED1STRBTO_MASK;
  259. fled_short_mask = MT6370_FLED1SHORT_MASK;
  260. break;
  261. case MT6370_LED_FLASH2:
  262. strobe_timeout_mask = MT6370_FLED2STRBTO_MASK;
  263. fled_short_mask = MT6370_FLED2SHORT_MASK;
  264. break;
  265. case MT6370_LED_JOINT:
  266. strobe_timeout_mask = MT6370_FLED1STRBTO_MASK | MT6370_FLED2STRBTO_MASK;
  267. fled_short_mask = MT6370_FLED1SHORT_MASK | MT6370_FLED2SHORT_MASK;
  268. break;
  269. default:
  270. return -EINVAL;
  271. }
  272. if (chg_stat & MT6370_FLEDCHGVINOVP_MASK)
  273. rfault |= LED_FAULT_INPUT_VOLTAGE;
  274. if (fled_stat & strobe_timeout_mask)
  275. rfault |= LED_FAULT_TIMEOUT;
  276. if (fled_stat & fled_short_mask)
  277. rfault |= LED_FAULT_SHORT_CIRCUIT;
  278. if (fled_stat & MT6370_FLEDLVF_MASK)
  279. rfault |= LED_FAULT_UNDER_VOLTAGE;
  280. *fault = rfault;
  281. return ret;
  282. }
  283. static const struct led_flash_ops mt6370_flash_ops = {
  284. .flash_brightness_set = mt6370_flash_brightness_set,
  285. .strobe_set = mt6370_strobe_set,
  286. .strobe_get = mt6370_strobe_get,
  287. .timeout_set = mt6370_timeout_set,
  288. .fault_get = mt6370_fault_get,
  289. };
  290. #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
  291. static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
  292. bool enable)
  293. {
  294. struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
  295. struct mt6370_led *led = to_mt6370_led(flash, flash);
  296. struct mt6370_priv *priv = led->priv;
  297. u32 mask = led->led_no == MT6370_LED_JOINT ? MT6370_FLCSEN_MASK_ALL :
  298. MT6370_FLCSEN_MASK(led->led_no);
  299. u32 val = enable ? mask : 0;
  300. int ret;
  301. mutex_lock(&priv->lock);
  302. ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val);
  303. if (ret)
  304. goto unlock;
  305. if (enable)
  306. priv->fled_strobe_used |= BIT(led->led_no);
  307. else
  308. priv->fled_strobe_used &= ~BIT(led->led_no);
  309. unlock:
  310. mutex_unlock(&priv->lock);
  311. return ret;
  312. }
  313. static const struct v4l2_flash_ops v4l2_flash_ops = {
  314. .external_strobe_set = mt6370_flash_external_strobe_set,
  315. };
  316. static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, struct v4l2_flash_config *cfg)
  317. {
  318. struct led_classdev *lcdev;
  319. struct led_flash_setting *s = &cfg->intensity;
  320. lcdev = &led->flash.led_cdev;
  321. s->min = MT6370_ITORCH_MIN_uA;
  322. s->step = MT6370_ITORCH_STEP_uA;
  323. s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step;
  324. cfg->has_external_strobe = 1;
  325. strscpy(cfg->dev_name, dev_name(lcdev->dev), sizeof(cfg->dev_name));
  326. cfg->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT |
  327. LED_FAULT_INPUT_VOLTAGE | LED_FAULT_UNDER_VOLTAGE;
  328. }
  329. #else
  330. static const struct v4l2_flash_ops v4l2_flash_ops;
  331. static void mt6370_init_v4l2_flash_config(struct mt6370_led *led, struct v4l2_flash_config *cfg)
  332. {
  333. }
  334. #endif
  335. static void mt6370_v4l2_flash_release(void *v4l2_flash)
  336. {
  337. v4l2_flash_release(v4l2_flash);
  338. }
  339. static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
  340. struct fwnode_handle *fwnode)
  341. {
  342. struct led_init_data init_data = { .fwnode = fwnode };
  343. struct v4l2_flash_config v4l2_config = {};
  344. int ret;
  345. ret = devm_led_classdev_flash_register_ext(parent, &led->flash, &init_data);
  346. if (ret)
  347. return dev_err_probe(parent, ret, "Couldn't register flash %d\n", led->led_no);
  348. mt6370_init_v4l2_flash_config(led, &v4l2_config);
  349. led->v4l2_flash = v4l2_flash_init(parent, fwnode, &led->flash, &v4l2_flash_ops,
  350. &v4l2_config);
  351. if (IS_ERR(led->v4l2_flash))
  352. return dev_err_probe(parent, PTR_ERR(led->v4l2_flash),
  353. "Failed to register %d v4l2 sd\n", led->led_no);
  354. return devm_add_action_or_reset(parent, mt6370_v4l2_flash_release, led->v4l2_flash);
  355. }
  356. static u32 mt6370_clamp(u32 val, u32 min, u32 max, u32 step)
  357. {
  358. u32 retval;
  359. retval = clamp_val(val, min, max);
  360. if (step > 1)
  361. retval = rounddown(retval - min, step) + min;
  362. return retval;
  363. }
  364. static int mt6370_init_flash_properties(struct device *dev, struct mt6370_led *led,
  365. struct fwnode_handle *fwnode)
  366. {
  367. struct led_classdev_flash *flash = &led->flash;
  368. struct led_classdev *lcdev = &flash->led_cdev;
  369. struct mt6370_priv *priv = led->priv;
  370. struct led_flash_setting *s;
  371. u32 sources[MT6370_MAX_LEDS];
  372. u32 max_ua, val;
  373. int i, ret, num;
  374. num = fwnode_property_count_u32(fwnode, "led-sources");
  375. if (num < 1)
  376. return dev_err_probe(dev, -EINVAL,
  377. "Not specified or wrong number of led-sources\n");
  378. ret = fwnode_property_read_u32_array(fwnode, "led-sources", sources, num);
  379. if (ret)
  380. return ret;
  381. for (i = 0; i < num; i++) {
  382. if (sources[i] >= MT6370_MAX_LEDS)
  383. return -EINVAL;
  384. if (priv->leds_active & BIT(sources[i]))
  385. return -EINVAL;
  386. priv->leds_active |= BIT(sources[i]);
  387. }
  388. /* If both channels are specified in 'led-sources', joint flash output mode is used */
  389. led->led_no = num == 2 ? MT6370_LED_JOINT : sources[0];
  390. max_ua = num == 2 ? MT6370_ITORCH_DOUBLE_MAX_uA : MT6370_ITORCH_MAX_uA;
  391. val = MT6370_ITORCH_MIN_uA;
  392. ret = fwnode_property_read_u32(fwnode, "led-max-microamp", &val);
  393. if (!ret)
  394. val = mt6370_clamp(val, MT6370_ITORCH_MIN_uA, max_ua, MT6370_ITORCH_STEP_uA);
  395. lcdev->max_brightness = (val - MT6370_ITORCH_MIN_uA) / MT6370_ITORCH_STEP_uA + 1;
  396. lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
  397. lcdev->flags |= LED_DEV_CAP_FLASH;
  398. max_ua = num == 2 ? MT6370_ISTRB_DOUBLE_MAX_uA : MT6370_ISTRB_MAX_uA;
  399. val = MT6370_ISTRB_MIN_uA;
  400. ret = fwnode_property_read_u32(fwnode, "flash-max-microamp", &val);
  401. if (!ret)
  402. val = mt6370_clamp(val, MT6370_ISTRB_MIN_uA, max_ua, MT6370_ISTRB_STEP_uA);
  403. s = &flash->brightness;
  404. s->min = MT6370_ISTRB_MIN_uA;
  405. s->step = MT6370_ISTRB_STEP_uA;
  406. s->val = s->max = val;
  407. /* Always configure to the minimum level when off to prevent flash current spikes. */
  408. ret = _mt6370_flash_brightness_set(flash, s->min);
  409. if (ret)
  410. return ret;
  411. val = MT6370_STRBTO_MIN_US;
  412. ret = fwnode_property_read_u32(fwnode, "flash-max-timeout-us", &val);
  413. if (!ret)
  414. val = mt6370_clamp(val, MT6370_STRBTO_MIN_US, MT6370_STRBTO_MAX_US,
  415. MT6370_STRBTO_STEP_US);
  416. s = &flash->timeout;
  417. s->min = MT6370_STRBTO_MIN_US;
  418. s->step = MT6370_STRBTO_STEP_US;
  419. s->val = s->max = val;
  420. flash->ops = &mt6370_flash_ops;
  421. return 0;
  422. }
  423. static int mt6370_led_probe(struct platform_device *pdev)
  424. {
  425. struct device *dev = &pdev->dev;
  426. struct mt6370_priv *priv;
  427. struct fwnode_handle *child;
  428. size_t count;
  429. int i = 0, ret;
  430. count = device_get_child_node_count(dev);
  431. if (!count || count > MT6370_MAX_LEDS)
  432. return dev_err_probe(dev, -EINVAL,
  433. "No child node or node count over max led number %zu\n", count);
  434. priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
  435. if (!priv)
  436. return -ENOMEM;
  437. priv->leds_count = count;
  438. mutex_init(&priv->lock);
  439. priv->regmap = dev_get_regmap(dev->parent, NULL);
  440. if (!priv->regmap)
  441. return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
  442. device_for_each_child_node(dev, child) {
  443. struct mt6370_led *led = priv->leds + i;
  444. led->priv = priv;
  445. ret = mt6370_init_flash_properties(dev, led, child);
  446. if (ret) {
  447. fwnode_handle_put(child);
  448. return ret;
  449. }
  450. ret = mt6370_led_register(dev, led, child);
  451. if (ret) {
  452. fwnode_handle_put(child);
  453. return ret;
  454. }
  455. i++;
  456. }
  457. return 0;
  458. }
  459. static const struct of_device_id mt6370_led_of_id[] = {
  460. { .compatible = "mediatek,mt6370-flashlight" },
  461. {}
  462. };
  463. MODULE_DEVICE_TABLE(of, mt6370_led_of_id);
  464. static struct platform_driver mt6370_led_driver = {
  465. .driver = {
  466. .name = "mt6370-flashlight",
  467. .of_match_table = mt6370_led_of_id,
  468. },
  469. .probe = mt6370_led_probe,
  470. };
  471. module_platform_driver(mt6370_led_driver);
  472. MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
  473. MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
  474. MODULE_DESCRIPTION("MT6370 FLASH LED Driver");
  475. MODULE_LICENSE("GPL");