mt6360_charger.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2021 MediaTek Inc.
  4. */
  5. #include <linux/devm-helpers.h>
  6. #include <linux/init.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/kernel.h>
  9. #include <linux/linear_range.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/power_supply.h>
  14. #include <linux/property.h>
  15. #include <linux/regmap.h>
  16. #include <linux/regulator/driver.h>
  17. #define MT6360_PMU_CHG_CTRL1 0x311
  18. #define MT6360_PMU_CHG_CTRL2 0x312
  19. #define MT6360_PMU_CHG_CTRL3 0x313
  20. #define MT6360_PMU_CHG_CTRL4 0x314
  21. #define MT6360_PMU_CHG_CTRL5 0x315
  22. #define MT6360_PMU_CHG_CTRL6 0x316
  23. #define MT6360_PMU_CHG_CTRL7 0x317
  24. #define MT6360_PMU_CHG_CTRL8 0x318
  25. #define MT6360_PMU_CHG_CTRL9 0x319
  26. #define MT6360_PMU_CHG_CTRL10 0x31A
  27. #define MT6360_PMU_DEVICE_TYPE 0x322
  28. #define MT6360_PMU_USB_STATUS1 0x327
  29. #define MT6360_PMU_CHG_STAT 0x34A
  30. #define MT6360_PMU_CHG_CTRL19 0x361
  31. #define MT6360_PMU_FOD_STAT 0x3E7
  32. /* MT6360_PMU_CHG_CTRL1 */
  33. #define MT6360_FSLP_SHFT (3)
  34. #define MT6360_FSLP_MASK BIT(MT6360_FSLP_SHFT)
  35. #define MT6360_OPA_MODE_SHFT (0)
  36. #define MT6360_OPA_MODE_MASK BIT(MT6360_OPA_MODE_SHFT)
  37. /* MT6360_PMU_CHG_CTRL2 */
  38. #define MT6360_IINLMTSEL_SHFT (2)
  39. #define MT6360_IINLMTSEL_MASK GENMASK(3, 2)
  40. /* MT6360_PMU_CHG_CTRL3 */
  41. #define MT6360_IAICR_SHFT (2)
  42. #define MT6360_IAICR_MASK GENMASK(7, 2)
  43. #define MT6360_ILIM_EN_MASK BIT(0)
  44. /* MT6360_PMU_CHG_CTRL4 */
  45. #define MT6360_VOREG_SHFT (1)
  46. #define MT6360_VOREG_MASK GENMASK(7, 1)
  47. /* MT6360_PMU_CHG_CTRL5 */
  48. #define MT6360_VOBST_MASK GENMASK(7, 2)
  49. /* MT6360_PMU_CHG_CTRL6 */
  50. #define MT6360_VMIVR_SHFT (1)
  51. #define MT6360_VMIVR_MASK GENMASK(7, 1)
  52. /* MT6360_PMU_CHG_CTRL7 */
  53. #define MT6360_ICHG_SHFT (2)
  54. #define MT6360_ICHG_MASK GENMASK(7, 2)
  55. /* MT6360_PMU_CHG_CTRL8 */
  56. #define MT6360_IPREC_SHFT (0)
  57. #define MT6360_IPREC_MASK GENMASK(3, 0)
  58. /* MT6360_PMU_CHG_CTRL9 */
  59. #define MT6360_IEOC_SHFT (4)
  60. #define MT6360_IEOC_MASK GENMASK(7, 4)
  61. /* MT6360_PMU_CHG_CTRL10 */
  62. #define MT6360_OTG_OC_MASK GENMASK(3, 0)
  63. /* MT6360_PMU_DEVICE_TYPE */
  64. #define MT6360_USBCHGEN_MASK BIT(7)
  65. /* MT6360_PMU_USB_STATUS1 */
  66. #define MT6360_USB_STATUS_SHFT (4)
  67. #define MT6360_USB_STATUS_MASK GENMASK(6, 4)
  68. /* MT6360_PMU_CHG_STAT */
  69. #define MT6360_CHG_STAT_SHFT (6)
  70. #define MT6360_CHG_STAT_MASK GENMASK(7, 6)
  71. #define MT6360_VBAT_LVL_MASK BIT(5)
  72. /* MT6360_PMU_CHG_CTRL19 */
  73. #define MT6360_VINOVP_SHFT (5)
  74. #define MT6360_VINOVP_MASK GENMASK(6, 5)
  75. /* MT6360_PMU_FOD_STAT */
  76. #define MT6360_CHRDET_EXT_MASK BIT(4)
  77. /* uV */
  78. #define MT6360_VMIVR_MIN 3900000
  79. #define MT6360_VMIVR_MAX 13400000
  80. #define MT6360_VMIVR_STEP 100000
  81. /* uA */
  82. #define MT6360_ICHG_MIN 100000
  83. #define MT6360_ICHG_MAX 5000000
  84. #define MT6360_ICHG_STEP 100000
  85. /* uV */
  86. #define MT6360_VOREG_MIN 3900000
  87. #define MT6360_VOREG_MAX 4710000
  88. #define MT6360_VOREG_STEP 10000
  89. /* uA */
  90. #define MT6360_AICR_MIN 100000
  91. #define MT6360_AICR_MAX 3250000
  92. #define MT6360_AICR_STEP 50000
  93. /* uA */
  94. #define MT6360_IPREC_MIN 100000
  95. #define MT6360_IPREC_MAX 850000
  96. #define MT6360_IPREC_STEP 50000
  97. /* uA */
  98. #define MT6360_IEOC_MIN 100000
  99. #define MT6360_IEOC_MAX 850000
  100. #define MT6360_IEOC_STEP 50000
  101. enum {
  102. MT6360_RANGE_VMIVR,
  103. MT6360_RANGE_ICHG,
  104. MT6360_RANGE_VOREG,
  105. MT6360_RANGE_AICR,
  106. MT6360_RANGE_IPREC,
  107. MT6360_RANGE_IEOC,
  108. MT6360_RANGE_MAX,
  109. };
  110. #define MT6360_LINEAR_RANGE(idx, _min, _min_sel, _max_sel, _step) \
  111. [idx] = REGULATOR_LINEAR_RANGE(_min, _min_sel, _max_sel, _step)
  112. static const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = {
  113. MT6360_LINEAR_RANGE(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000),
  114. MT6360_LINEAR_RANGE(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000),
  115. MT6360_LINEAR_RANGE(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000),
  116. MT6360_LINEAR_RANGE(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000),
  117. MT6360_LINEAR_RANGE(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000),
  118. MT6360_LINEAR_RANGE(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000),
  119. };
  120. struct mt6360_chg_info {
  121. struct device *dev;
  122. struct regmap *regmap;
  123. struct power_supply_desc psy_desc;
  124. struct power_supply *psy;
  125. struct regulator_dev *otg_rdev;
  126. struct mutex chgdet_lock;
  127. u32 vinovp;
  128. bool pwr_rdy;
  129. bool bc12_en;
  130. int psy_usb_type;
  131. struct work_struct chrdet_work;
  132. };
  133. enum mt6360_iinlmtsel {
  134. MT6360_IINLMTSEL_AICR_3250 = 0,
  135. MT6360_IINLMTSEL_CHG_TYPE,
  136. MT6360_IINLMTSEL_AICR,
  137. MT6360_IINLMTSEL_LOWER_LEVEL,
  138. };
  139. enum mt6360_pmu_chg_type {
  140. MT6360_CHG_TYPE_NOVBUS = 0,
  141. MT6360_CHG_TYPE_UNDER_GOING,
  142. MT6360_CHG_TYPE_SDP,
  143. MT6360_CHG_TYPE_SDPNSTD,
  144. MT6360_CHG_TYPE_DCP,
  145. MT6360_CHG_TYPE_CDP,
  146. MT6360_CHG_TYPE_DISABLE_BC12,
  147. MT6360_CHG_TYPE_MAX,
  148. };
  149. static enum power_supply_usb_type mt6360_charger_usb_types[] = {
  150. POWER_SUPPLY_USB_TYPE_UNKNOWN,
  151. POWER_SUPPLY_USB_TYPE_SDP,
  152. POWER_SUPPLY_USB_TYPE_DCP,
  153. POWER_SUPPLY_USB_TYPE_CDP,
  154. };
  155. static int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci,
  156. bool *pwr_rdy)
  157. {
  158. int ret;
  159. unsigned int regval;
  160. ret = regmap_read(mci->regmap, MT6360_PMU_FOD_STAT, &regval);
  161. if (ret < 0)
  162. return ret;
  163. *pwr_rdy = (regval & MT6360_CHRDET_EXT_MASK) ? true : false;
  164. return 0;
  165. }
  166. static int mt6360_charger_get_online(struct mt6360_chg_info *mci,
  167. union power_supply_propval *val)
  168. {
  169. int ret;
  170. bool pwr_rdy;
  171. ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
  172. if (ret < 0)
  173. return ret;
  174. val->intval = pwr_rdy ? true : false;
  175. return 0;
  176. }
  177. static int mt6360_charger_get_status(struct mt6360_chg_info *mci,
  178. union power_supply_propval *val)
  179. {
  180. int status, ret;
  181. unsigned int regval;
  182. bool pwr_rdy;
  183. ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
  184. if (ret < 0)
  185. return ret;
  186. if (!pwr_rdy) {
  187. status = POWER_SUPPLY_STATUS_DISCHARGING;
  188. goto out;
  189. }
  190. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, &regval);
  191. if (ret < 0)
  192. return ret;
  193. regval &= MT6360_CHG_STAT_MASK;
  194. regval >>= MT6360_CHG_STAT_SHFT;
  195. switch (regval) {
  196. case 0x0:
  197. status = POWER_SUPPLY_STATUS_NOT_CHARGING;
  198. break;
  199. case 0x1:
  200. status = POWER_SUPPLY_STATUS_CHARGING;
  201. break;
  202. case 0x2:
  203. status = POWER_SUPPLY_STATUS_FULL;
  204. break;
  205. default:
  206. ret = -EIO;
  207. }
  208. out:
  209. if (!ret)
  210. val->intval = status;
  211. return ret;
  212. }
  213. static int mt6360_charger_get_charge_type(struct mt6360_chg_info *mci,
  214. union power_supply_propval *val)
  215. {
  216. int type, ret;
  217. unsigned int regval;
  218. u8 chg_stat;
  219. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, &regval);
  220. if (ret < 0)
  221. return ret;
  222. chg_stat = (regval & MT6360_CHG_STAT_MASK) >> MT6360_CHG_STAT_SHFT;
  223. switch (chg_stat) {
  224. case 0x01: /* Charge in Progress */
  225. if (regval & MT6360_VBAT_LVL_MASK)
  226. type = POWER_SUPPLY_CHARGE_TYPE_FAST;
  227. else
  228. type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
  229. break;
  230. case 0x00: /* Not Charging */
  231. case 0x02: /* Charge Done */
  232. case 0x03: /* Charge Fault */
  233. default:
  234. type = POWER_SUPPLY_CHARGE_TYPE_NONE;
  235. break;
  236. }
  237. val->intval = type;
  238. return 0;
  239. }
  240. static int mt6360_charger_get_ichg(struct mt6360_chg_info *mci,
  241. union power_supply_propval *val)
  242. {
  243. int ret;
  244. u32 sel, value;
  245. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL7, &sel);
  246. if (ret < 0)
  247. return ret;
  248. sel = (sel & MT6360_ICHG_MASK) >> MT6360_ICHG_SHFT;
  249. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_ICHG], sel, &value);
  250. if (!ret)
  251. val->intval = value;
  252. return ret;
  253. }
  254. static int mt6360_charger_get_max_ichg(struct mt6360_chg_info *mci,
  255. union power_supply_propval *val)
  256. {
  257. val->intval = MT6360_ICHG_MAX;
  258. return 0;
  259. }
  260. static int mt6360_charger_get_cv(struct mt6360_chg_info *mci,
  261. union power_supply_propval *val)
  262. {
  263. int ret;
  264. u32 sel, value;
  265. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL4, &sel);
  266. if (ret < 0)
  267. return ret;
  268. sel = (sel & MT6360_VOREG_MASK) >> MT6360_VOREG_SHFT;
  269. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VOREG], sel, &value);
  270. if (!ret)
  271. val->intval = value;
  272. return ret;
  273. }
  274. static int mt6360_charger_get_max_cv(struct mt6360_chg_info *mci,
  275. union power_supply_propval *val)
  276. {
  277. val->intval = MT6360_VOREG_MAX;
  278. return 0;
  279. }
  280. static int mt6360_charger_get_aicr(struct mt6360_chg_info *mci,
  281. union power_supply_propval *val)
  282. {
  283. int ret;
  284. u32 sel, value;
  285. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL3, &sel);
  286. if (ret < 0)
  287. return ret;
  288. sel = (sel & MT6360_IAICR_MASK) >> MT6360_IAICR_SHFT;
  289. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_AICR], sel, &value);
  290. if (!ret)
  291. val->intval = value;
  292. return ret;
  293. }
  294. static int mt6360_charger_get_mivr(struct mt6360_chg_info *mci,
  295. union power_supply_propval *val)
  296. {
  297. int ret;
  298. u32 sel, value;
  299. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL6, &sel);
  300. if (ret < 0)
  301. return ret;
  302. sel = (sel & MT6360_VMIVR_MASK) >> MT6360_VMIVR_SHFT;
  303. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VMIVR], sel, &value);
  304. if (!ret)
  305. val->intval = value;
  306. return ret;
  307. }
  308. static int mt6360_charger_get_iprechg(struct mt6360_chg_info *mci,
  309. union power_supply_propval *val)
  310. {
  311. int ret;
  312. u32 sel, value;
  313. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL8, &sel);
  314. if (ret < 0)
  315. return ret;
  316. sel = (sel & MT6360_IPREC_MASK) >> MT6360_IPREC_SHFT;
  317. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IPREC], sel, &value);
  318. if (!ret)
  319. val->intval = value;
  320. return ret;
  321. }
  322. static int mt6360_charger_get_ieoc(struct mt6360_chg_info *mci,
  323. union power_supply_propval *val)
  324. {
  325. int ret;
  326. u32 sel, value;
  327. ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL9, &sel);
  328. if (ret < 0)
  329. return ret;
  330. sel = (sel & MT6360_IEOC_MASK) >> MT6360_IEOC_SHFT;
  331. ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IEOC], sel, &value);
  332. if (!ret)
  333. val->intval = value;
  334. return ret;
  335. }
  336. static int mt6360_charger_set_online(struct mt6360_chg_info *mci,
  337. const union power_supply_propval *val)
  338. {
  339. u8 force_sleep = val->intval ? 0 : 1;
  340. return regmap_update_bits(mci->regmap,
  341. MT6360_PMU_CHG_CTRL1,
  342. MT6360_FSLP_MASK,
  343. force_sleep << MT6360_FSLP_SHFT);
  344. }
  345. static int mt6360_charger_set_ichg(struct mt6360_chg_info *mci,
  346. const union power_supply_propval *val)
  347. {
  348. u32 sel;
  349. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_ICHG], val->intval, &sel);
  350. return regmap_update_bits(mci->regmap,
  351. MT6360_PMU_CHG_CTRL7,
  352. MT6360_ICHG_MASK,
  353. sel << MT6360_ICHG_SHFT);
  354. }
  355. static int mt6360_charger_set_cv(struct mt6360_chg_info *mci,
  356. const union power_supply_propval *val)
  357. {
  358. u32 sel;
  359. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VOREG], val->intval, &sel);
  360. return regmap_update_bits(mci->regmap,
  361. MT6360_PMU_CHG_CTRL4,
  362. MT6360_VOREG_MASK,
  363. sel << MT6360_VOREG_SHFT);
  364. }
  365. static int mt6360_charger_set_aicr(struct mt6360_chg_info *mci,
  366. const union power_supply_propval *val)
  367. {
  368. u32 sel;
  369. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_AICR], val->intval, &sel);
  370. return regmap_update_bits(mci->regmap,
  371. MT6360_PMU_CHG_CTRL3,
  372. MT6360_IAICR_MASK,
  373. sel << MT6360_IAICR_SHFT);
  374. }
  375. static int mt6360_charger_set_mivr(struct mt6360_chg_info *mci,
  376. const union power_supply_propval *val)
  377. {
  378. u32 sel;
  379. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VMIVR], val->intval, &sel);
  380. return regmap_update_bits(mci->regmap,
  381. MT6360_PMU_CHG_CTRL3,
  382. MT6360_VMIVR_MASK,
  383. sel << MT6360_VMIVR_SHFT);
  384. }
  385. static int mt6360_charger_set_iprechg(struct mt6360_chg_info *mci,
  386. const union power_supply_propval *val)
  387. {
  388. u32 sel;
  389. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IPREC], val->intval, &sel);
  390. return regmap_update_bits(mci->regmap,
  391. MT6360_PMU_CHG_CTRL8,
  392. MT6360_IPREC_MASK,
  393. sel << MT6360_IPREC_SHFT);
  394. }
  395. static int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci,
  396. const union power_supply_propval *val)
  397. {
  398. u32 sel;
  399. linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IEOC], val->intval, &sel);
  400. return regmap_update_bits(mci->regmap,
  401. MT6360_PMU_CHG_CTRL9,
  402. MT6360_IEOC_MASK,
  403. sel << MT6360_IEOC_SHFT);
  404. }
  405. static int mt6360_charger_get_property(struct power_supply *psy,
  406. enum power_supply_property psp,
  407. union power_supply_propval *val)
  408. {
  409. struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
  410. int ret = 0;
  411. switch (psp) {
  412. case POWER_SUPPLY_PROP_ONLINE:
  413. ret = mt6360_charger_get_online(mci, val);
  414. break;
  415. case POWER_SUPPLY_PROP_STATUS:
  416. ret = mt6360_charger_get_status(mci, val);
  417. break;
  418. case POWER_SUPPLY_PROP_CHARGE_TYPE:
  419. ret = mt6360_charger_get_charge_type(mci, val);
  420. break;
  421. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  422. ret = mt6360_charger_get_ichg(mci, val);
  423. break;
  424. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
  425. ret = mt6360_charger_get_max_ichg(mci, val);
  426. break;
  427. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  428. ret = mt6360_charger_get_cv(mci, val);
  429. break;
  430. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
  431. ret = mt6360_charger_get_max_cv(mci, val);
  432. break;
  433. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  434. ret = mt6360_charger_get_aicr(mci, val);
  435. break;
  436. case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
  437. ret = mt6360_charger_get_mivr(mci, val);
  438. break;
  439. case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
  440. ret = mt6360_charger_get_iprechg(mci, val);
  441. break;
  442. case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
  443. ret = mt6360_charger_get_ieoc(mci, val);
  444. break;
  445. case POWER_SUPPLY_PROP_USB_TYPE:
  446. val->intval = mci->psy_usb_type;
  447. break;
  448. default:
  449. ret = -ENODATA;
  450. }
  451. return ret;
  452. }
  453. static int mt6360_charger_set_property(struct power_supply *psy,
  454. enum power_supply_property psp,
  455. const union power_supply_propval *val)
  456. {
  457. struct mt6360_chg_info *mci = power_supply_get_drvdata(psy);
  458. int ret;
  459. switch (psp) {
  460. case POWER_SUPPLY_PROP_ONLINE:
  461. ret = mt6360_charger_set_online(mci, val);
  462. break;
  463. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  464. ret = mt6360_charger_set_ichg(mci, val);
  465. break;
  466. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  467. ret = mt6360_charger_set_cv(mci, val);
  468. break;
  469. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  470. ret = mt6360_charger_set_aicr(mci, val);
  471. break;
  472. case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
  473. ret = mt6360_charger_set_mivr(mci, val);
  474. break;
  475. case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
  476. ret = mt6360_charger_set_iprechg(mci, val);
  477. break;
  478. case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
  479. ret = mt6360_charger_set_ieoc(mci, val);
  480. break;
  481. default:
  482. ret = -EINVAL;
  483. }
  484. return ret;
  485. }
  486. static int mt6360_charger_property_is_writeable(struct power_supply *psy,
  487. enum power_supply_property psp)
  488. {
  489. switch (psp) {
  490. case POWER_SUPPLY_PROP_ONLINE:
  491. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
  492. case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
  493. case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
  494. case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
  495. case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
  496. case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
  497. return 1;
  498. default:
  499. return 0;
  500. }
  501. }
  502. static enum power_supply_property mt6360_charger_properties[] = {
  503. POWER_SUPPLY_PROP_ONLINE,
  504. POWER_SUPPLY_PROP_STATUS,
  505. POWER_SUPPLY_PROP_CHARGE_TYPE,
  506. POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
  507. POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
  508. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
  509. POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
  510. POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
  511. POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
  512. POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
  513. POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
  514. POWER_SUPPLY_PROP_USB_TYPE,
  515. };
  516. static const struct power_supply_desc mt6360_charger_desc = {
  517. .type = POWER_SUPPLY_TYPE_USB,
  518. .properties = mt6360_charger_properties,
  519. .num_properties = ARRAY_SIZE(mt6360_charger_properties),
  520. .get_property = mt6360_charger_get_property,
  521. .set_property = mt6360_charger_set_property,
  522. .property_is_writeable = mt6360_charger_property_is_writeable,
  523. .usb_types = mt6360_charger_usb_types,
  524. .num_usb_types = ARRAY_SIZE(mt6360_charger_usb_types),
  525. };
  526. static const struct regulator_ops mt6360_chg_otg_ops = {
  527. .list_voltage = regulator_list_voltage_linear,
  528. .enable = regulator_enable_regmap,
  529. .disable = regulator_disable_regmap,
  530. .is_enabled = regulator_is_enabled_regmap,
  531. .set_voltage_sel = regulator_set_voltage_sel_regmap,
  532. .get_voltage_sel = regulator_get_voltage_sel_regmap,
  533. };
  534. static const struct regulator_desc mt6360_otg_rdesc = {
  535. .of_match = "usb-otg-vbus",
  536. .name = "usb-otg-vbus",
  537. .ops = &mt6360_chg_otg_ops,
  538. .owner = THIS_MODULE,
  539. .type = REGULATOR_VOLTAGE,
  540. .min_uV = 4425000,
  541. .uV_step = 25000,
  542. .n_voltages = 57,
  543. .vsel_reg = MT6360_PMU_CHG_CTRL5,
  544. .vsel_mask = MT6360_VOBST_MASK,
  545. .enable_reg = MT6360_PMU_CHG_CTRL1,
  546. .enable_mask = MT6360_OPA_MODE_MASK,
  547. };
  548. static irqreturn_t mt6360_pmu_attach_i_handler(int irq, void *data)
  549. {
  550. struct mt6360_chg_info *mci = data;
  551. int ret;
  552. unsigned int usb_status;
  553. int last_usb_type;
  554. mutex_lock(&mci->chgdet_lock);
  555. if (!mci->bc12_en) {
  556. dev_warn(mci->dev, "Received attach interrupt, bc12 disabled, ignore irq\n");
  557. goto out;
  558. }
  559. last_usb_type = mci->psy_usb_type;
  560. /* Plug in */
  561. ret = regmap_read(mci->regmap, MT6360_PMU_USB_STATUS1, &usb_status);
  562. if (ret < 0)
  563. goto out;
  564. usb_status &= MT6360_USB_STATUS_MASK;
  565. usb_status >>= MT6360_USB_STATUS_SHFT;
  566. switch (usb_status) {
  567. case MT6360_CHG_TYPE_NOVBUS:
  568. dev_dbg(mci->dev, "Received attach interrupt, no vbus\n");
  569. goto out;
  570. case MT6360_CHG_TYPE_UNDER_GOING:
  571. dev_dbg(mci->dev, "Received attach interrupt, under going...\n");
  572. goto out;
  573. case MT6360_CHG_TYPE_SDP:
  574. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
  575. break;
  576. case MT6360_CHG_TYPE_SDPNSTD:
  577. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
  578. break;
  579. case MT6360_CHG_TYPE_CDP:
  580. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
  581. break;
  582. case MT6360_CHG_TYPE_DCP:
  583. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
  584. break;
  585. case MT6360_CHG_TYPE_DISABLE_BC12:
  586. dev_dbg(mci->dev, "Received attach interrupt, bc12 detect not enable\n");
  587. goto out;
  588. default:
  589. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
  590. dev_dbg(mci->dev, "Received attach interrupt, reserved address\n");
  591. goto out;
  592. }
  593. dev_dbg(mci->dev, "Received attach interrupt, chg_type = %d\n", mci->psy_usb_type);
  594. if (last_usb_type != mci->psy_usb_type)
  595. power_supply_changed(mci->psy);
  596. out:
  597. mutex_unlock(&mci->chgdet_lock);
  598. return IRQ_HANDLED;
  599. }
  600. static void mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info *mci)
  601. {
  602. int ret;
  603. bool pwr_rdy;
  604. mutex_lock(&mci->chgdet_lock);
  605. ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy);
  606. if (ret < 0)
  607. goto out;
  608. if (mci->pwr_rdy == pwr_rdy) {
  609. dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy is same(%d)\n", pwr_rdy);
  610. goto out;
  611. }
  612. mci->pwr_rdy = pwr_rdy;
  613. dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy = %d\n", pwr_rdy);
  614. if (!pwr_rdy) {
  615. mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
  616. power_supply_changed(mci->psy);
  617. }
  618. ret = regmap_update_bits(mci->regmap,
  619. MT6360_PMU_DEVICE_TYPE,
  620. MT6360_USBCHGEN_MASK,
  621. pwr_rdy ? MT6360_USBCHGEN_MASK : 0);
  622. if (ret < 0)
  623. goto out;
  624. mci->bc12_en = pwr_rdy;
  625. out:
  626. mutex_unlock(&mci->chgdet_lock);
  627. }
  628. static void mt6360_chrdet_work(struct work_struct *work)
  629. {
  630. struct mt6360_chg_info *mci = (struct mt6360_chg_info *)container_of(
  631. work, struct mt6360_chg_info, chrdet_work);
  632. mt6360_handle_chrdet_ext_evt(mci);
  633. }
  634. static irqreturn_t mt6360_pmu_chrdet_ext_evt_handler(int irq, void *data)
  635. {
  636. struct mt6360_chg_info *mci = data;
  637. mt6360_handle_chrdet_ext_evt(mci);
  638. return IRQ_HANDLED;
  639. }
  640. static int mt6360_chg_irq_register(struct platform_device *pdev)
  641. {
  642. const struct {
  643. const char *name;
  644. irq_handler_t handler;
  645. } irq_descs[] = {
  646. { "attach_i", mt6360_pmu_attach_i_handler },
  647. { "chrdet_ext_evt", mt6360_pmu_chrdet_ext_evt_handler }
  648. };
  649. int i, ret;
  650. for (i = 0; i < ARRAY_SIZE(irq_descs); i++) {
  651. ret = platform_get_irq_byname(pdev, irq_descs[i].name);
  652. if (ret < 0)
  653. return ret;
  654. ret = devm_request_threaded_irq(&pdev->dev, ret, NULL,
  655. irq_descs[i].handler,
  656. IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
  657. irq_descs[i].name,
  658. platform_get_drvdata(pdev));
  659. if (ret < 0)
  660. return dev_err_probe(&pdev->dev, ret, "Failed to request %s irq\n",
  661. irq_descs[i].name);
  662. }
  663. return 0;
  664. }
  665. static u32 mt6360_vinovp_trans_to_sel(u32 val)
  666. {
  667. u32 vinovp_tbl[] = { 5500000, 6500000, 11000000, 14500000 };
  668. int i;
  669. /* Select the smaller and equal supported value */
  670. for (i = 0; i < ARRAY_SIZE(vinovp_tbl)-1; i++) {
  671. if (val < vinovp_tbl[i+1])
  672. break;
  673. }
  674. return i;
  675. }
  676. static int mt6360_chg_init_setting(struct mt6360_chg_info *mci)
  677. {
  678. int ret;
  679. u32 sel;
  680. sel = mt6360_vinovp_trans_to_sel(mci->vinovp);
  681. ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL19,
  682. MT6360_VINOVP_MASK, sel << MT6360_VINOVP_SHFT);
  683. if (ret)
  684. return dev_err_probe(mci->dev, ret, "%s: Failed to apply vinovp\n", __func__);
  685. ret = regmap_update_bits(mci->regmap, MT6360_PMU_DEVICE_TYPE,
  686. MT6360_USBCHGEN_MASK, 0);
  687. if (ret)
  688. return dev_err_probe(mci->dev, ret, "%s: Failed to disable bc12\n", __func__);
  689. ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL2,
  690. MT6360_IINLMTSEL_MASK,
  691. MT6360_IINLMTSEL_AICR <<
  692. MT6360_IINLMTSEL_SHFT);
  693. if (ret)
  694. return dev_err_probe(mci->dev, ret,
  695. "%s: Failed to switch iinlmtsel to aicr\n", __func__);
  696. usleep_range(5000, 6000);
  697. ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL3,
  698. MT6360_ILIM_EN_MASK, 0);
  699. if (ret)
  700. return dev_err_probe(mci->dev, ret,
  701. "%s: Failed to disable ilim\n", __func__);
  702. ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL10,
  703. MT6360_OTG_OC_MASK, MT6360_OTG_OC_MASK);
  704. if (ret)
  705. return dev_err_probe(mci->dev, ret,
  706. "%s: Failed to config otg oc to 3A\n", __func__);
  707. return 0;
  708. }
  709. static int mt6360_charger_probe(struct platform_device *pdev)
  710. {
  711. struct mt6360_chg_info *mci;
  712. struct power_supply_config charger_cfg = {};
  713. struct regulator_config config = { };
  714. int ret;
  715. mci = devm_kzalloc(&pdev->dev, sizeof(*mci), GFP_KERNEL);
  716. if (!mci)
  717. return -ENOMEM;
  718. mci->dev = &pdev->dev;
  719. mci->vinovp = 6500000;
  720. mutex_init(&mci->chgdet_lock);
  721. platform_set_drvdata(pdev, mci);
  722. ret = devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work);
  723. if (ret)
  724. return dev_err_probe(&pdev->dev, ret, "Failed to set delayed work\n");
  725. ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp);
  726. if (ret)
  727. dev_warn(&pdev->dev, "Failed to parse vinovp in DT, keep default 6.5v\n");
  728. mci->regmap = dev_get_regmap(pdev->dev.parent, NULL);
  729. if (!mci->regmap)
  730. return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get parent regmap\n");
  731. ret = mt6360_chg_init_setting(mci);
  732. if (ret)
  733. return dev_err_probe(&pdev->dev, ret, "Failed to initial setting\n");
  734. memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc));
  735. mci->psy_desc.name = dev_name(&pdev->dev);
  736. charger_cfg.drv_data = mci;
  737. charger_cfg.of_node = pdev->dev.of_node;
  738. mci->psy = devm_power_supply_register(&pdev->dev,
  739. &mci->psy_desc, &charger_cfg);
  740. if (IS_ERR(mci->psy))
  741. return dev_err_probe(&pdev->dev, PTR_ERR(mci->psy),
  742. "Failed to register power supply dev\n");
  743. ret = mt6360_chg_irq_register(pdev);
  744. if (ret)
  745. return dev_err_probe(&pdev->dev, ret, "Failed to register irqs\n");
  746. config.dev = &pdev->dev;
  747. config.regmap = mci->regmap;
  748. mci->otg_rdev = devm_regulator_register(&pdev->dev, &mt6360_otg_rdesc,
  749. &config);
  750. if (IS_ERR(mci->otg_rdev))
  751. return PTR_ERR(mci->otg_rdev);
  752. schedule_work(&mci->chrdet_work);
  753. return 0;
  754. }
  755. static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = {
  756. { .compatible = "mediatek,mt6360-chg", },
  757. {},
  758. };
  759. MODULE_DEVICE_TABLE(of, mt6360_charger_of_id);
  760. static const struct platform_device_id mt6360_charger_id[] = {
  761. { "mt6360-chg", 0 },
  762. {},
  763. };
  764. MODULE_DEVICE_TABLE(platform, mt6360_charger_id);
  765. static struct platform_driver mt6360_charger_driver = {
  766. .driver = {
  767. .name = "mt6360-chg",
  768. .of_match_table = of_match_ptr(mt6360_charger_of_id),
  769. },
  770. .probe = mt6360_charger_probe,
  771. .id_table = mt6360_charger_id,
  772. };
  773. module_platform_driver(mt6360_charger_driver);
  774. MODULE_AUTHOR("Gene Chen <[email protected]>");
  775. MODULE_DESCRIPTION("MT6360 Charger Driver");
  776. MODULE_LICENSE("GPL");