light-regulator-aon.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2021 Alibaba Group Holding Limited.
  4. */
  5. #include <linux/debugfs.h>
  6. #include <linux/err.h>
  7. #include <linux/slab.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/module.h>
  10. #include <linux/of.h>
  11. #include <linux/of_device.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/regulator/driver.h>
  14. #include <linux/regulator/machine.h>
  15. #include <linux/regulator/of_regulator.h>
  16. #include <linux/regulator/machine.h>
  17. #include <linux/slab.h>
  18. #include <linux/uaccess.h>
  19. #include <linux/firmware/thead/ipc.h>
  20. #define MBOX_MAX_MSG_LEN 28
  21. #define CONFIG_AON_REG_DEBUG 1
  22. struct rpc_msg_regu_vol_set {
  23. u16 regu_id; ///< virtual regu id
  24. u16 is_dual_rail; ///< whether this regu has dual rails
  25. u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail
  26. u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false
  27. u16 reserved[6];
  28. } __packed __aligned(4);
  29. struct rpc_msg_regu_vol_get {
  30. u16 regu_id; ///< virtual regu id
  31. u16 is_dual_rail; ///< whether this regu has dual rails
  32. u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail
  33. u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false
  34. u16 reserved[6];
  35. } __packed __aligned(4);
  36. struct rpc_msg_regu_pwr_set {
  37. u16 regu_id; ///< virtual regu id
  38. u16 status; ///< 0: power off; 1: powr on
  39. u32 reserved[5];
  40. } __packed __aligned(4);
  41. struct rpc_msg_regu_pwr_get {
  42. u16 regu_id; ///< virtual regu id
  43. u16 status; ///< 0: power off; 1: powr on
  44. u32 reserved[5];
  45. } __packed __aligned(4);
  46. struct light_aon_msg_regulator_ctrl {
  47. struct light_aon_rpc_msg_hdr hdr;
  48. union rpc_func_t {
  49. struct rpc_msg_regu_vol_set regu_vol_set;
  50. struct rpc_msg_regu_vol_get regu_vol_get;
  51. struct rpc_msg_regu_pwr_set regu_pwr_set;
  52. struct rpc_msg_regu_pwr_get regu_pwr_get;
  53. } __packed __aligned(4) rpc;
  54. } __packed __aligned(4);
  55. enum pm_resource {
  56. SOC_DVDD18_AON, /*da9063: ldo-3 */
  57. SOC_AVDD33_USB3, /*da9063: ldo-9 */
  58. SOC_DVDD08_AON, /*da9063: ldo-2 */
  59. SOC_APCPU_DVDD_DVDDM,/*da9063: vbcore1 & vbcore2*/
  60. SOC_DVDD08_DDR, /*da9063: buckperi */
  61. SOC_VDD_DDR_1V8, /*da9063: ldo-4 */
  62. SOC_VDD_DDR_1V1, /*da9063: buckmem & buckio */
  63. SOC_VDD_DDR_0V6, /*da9063: buckpro */
  64. SOC_DVDD18_AP, /*da9063: ldo-11 */
  65. SOC_DVDD08_AP, /*da9121: da9121_ex */
  66. SOC_AVDD08_MIPI_HDMI,/*da9063: ldo-1 */
  67. SOC_AVDD18_MIPI_HDMI,/*da9063: ldo-5 */
  68. SOC_DVDD33_EMMC, /*da9063: ldo-10 */
  69. SOC_DVDD18_EMMC, /*slg51000:ldo-3 */
  70. SOC_DOVDD18_SCAN, /*da9063: ldo-6 */
  71. SOC_VEXT_2V8, /*da9063: ldo-7 */
  72. SOC_DVDD12_SCAN, /*da9063: ld0-8 */
  73. SOC_AVDD28_SCAN_EN, /*da9063: gpio4 */
  74. SOC_AVDD28_RGB, /*slg51000:ldo-1 */
  75. SOC_DOVDD18_RGB, /*slg51000:ldo-4 */
  76. SOC_DVDD12_RGB, /*slg51000:ldo-5 */
  77. SOC_AVDD25_IR, /*slg51000:ldo-2 */
  78. SOC_DOVDD18_IR, /*slg51000:ldo-7 */
  79. SOC_DVDD12_IR, /*slg51000:ldo-6 */
  80. SOC_ADC_VREF,
  81. SOC_LCD0_EN,
  82. SOC_VEXT_1V8,
  83. SOC_REGU_MAX
  84. };
  85. struct apcpu_vol_set {
  86. u32 vdd; ///< cpu core voltage
  87. u32 vddm; ///< cpu core-mem voltage
  88. };
  89. struct aon_regu_desc {
  90. struct regulator_desc *regu_desc; ///< discription of regulator
  91. u32 regu_num; ///< element number of regulators,which point to regu-dsc-array
  92. };
  93. struct aon_regu_info {
  94. struct device *dev;
  95. const struct apcpu_vol_set *cpu_vol; ///< signed-off voltage of cpu
  96. u32 vddm; ///< cpu-mem voltage
  97. struct aon_regu_desc *regu_desc; ///< regu-desc set
  98. struct light_aon_ipc *ipc_handle; ///< handle of mail-box
  99. };
  100. static struct aon_regu_info light_aon_pmic_info;
  101. #define APCPU_VOL_DEF(_vdd, _vddm) \
  102. { \
  103. .vdd = _vdd, \
  104. .vddm = _vddm, \
  105. }
  106. static const struct apcpu_vol_set apcpu_volts[] = {
  107. /*300Mhz*/
  108. APCPU_VOL_DEF(600000U, 750000U),
  109. APCPU_VOL_DEF(600000U, 800000U),
  110. APCPU_VOL_DEF(650000U, 800000U),
  111. APCPU_VOL_DEF(720000U, 770000U),
  112. /*800Mhz*/
  113. APCPU_VOL_DEF(700000U,800000U),
  114. APCPU_VOL_DEF(720000U,820000U),
  115. /*1500Mhz*/
  116. APCPU_VOL_DEF(800000U,800000U),
  117. APCPU_VOL_DEF(820000U,820000U),
  118. /*1850Mhz*/
  119. APCPU_VOL_DEF(1000000U,1000000U),
  120. };
  121. /* dc2 is valid when is_dual_rail is true
  122. *
  123. * dual-rail regulator means that a virtual regulator involes two hw-regulators
  124. */
  125. static int aon_set_regulator(struct light_aon_ipc *ipc, u16 regu_id,
  126. u32 dc1, u32 dc2, u16 is_dual_rail)
  127. {
  128. struct light_aon_msg_regulator_ctrl msg = {0};
  129. struct light_aon_rpc_msg_hdr *hdr = &msg.hdr;
  130. hdr->ver = LIGHT_AON_RPC_VERSION;
  131. hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM;
  132. hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR;
  133. hdr->size = LIGHT_AON_RPC_MSG_NUM;
  134. msg.rpc.regu_vol_set.regu_id = regu_id;
  135. msg.rpc.regu_vol_set.is_dual_rail = is_dual_rail;
  136. msg.rpc.regu_vol_set.dc1 = dc1;
  137. msg.rpc.regu_vol_set.dc2 = dc2;
  138. return light_aon_call_rpc(ipc, &msg, true);
  139. }
  140. /* dc2 is valid when is_dual_rail is true
  141. *
  142. * dual-rail regulator means that a virtual regulator involes two hw-regulators
  143. */
  144. static int aon_get_regulator(struct light_aon_ipc *ipc, u16 regu_id,
  145. u32 *dc1, u32 *dc2, u16 is_dual_rail)
  146. {
  147. struct light_aon_msg_regulator_ctrl msg = {0};
  148. struct light_aon_rpc_msg_hdr *hdr = &msg.hdr;
  149. int ret;
  150. hdr->ver = LIGHT_AON_RPC_VERSION;
  151. hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM;
  152. hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR;
  153. hdr->size = LIGHT_AON_RPC_MSG_NUM;
  154. msg.rpc.regu_vol_get.regu_id = regu_id;
  155. msg.rpc.regu_vol_get.is_dual_rail = is_dual_rail;
  156. ret = light_aon_call_rpc(ipc, &msg, true);
  157. if (ret)
  158. return ret;
  159. if (dc1 != NULL)
  160. *dc1 = msg.rpc.regu_vol_get.dc1;
  161. if (dc2 != NULL)
  162. *dc2 = msg.rpc.regu_vol_get.dc2;
  163. return 0;
  164. }
  165. static int aon_regu_power_ctrl(struct light_aon_ipc *ipc,u32 regu_id,u16 pwr_on)
  166. {
  167. struct light_aon_msg_regulator_ctrl msg = {0};
  168. struct light_aon_rpc_msg_hdr *hdr = &msg.hdr;
  169. hdr->ver = LIGHT_AON_RPC_VERSION;
  170. hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM;
  171. hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_SET;
  172. hdr->size = LIGHT_AON_RPC_MSG_NUM;
  173. msg.rpc.regu_pwr_set.regu_id = regu_id;
  174. msg.rpc.regu_pwr_set.status = pwr_on;
  175. return light_aon_call_rpc(ipc, &msg, true);
  176. }
  177. static int aon_regu_dummy_enable(struct regulator_dev *reg)
  178. {
  179. return 0;
  180. }
  181. static int aon_regu_dummy_disable(struct regulator_dev *reg)
  182. {
  183. return 0;
  184. }
  185. static int aon_regu_dummy_is_enabled(struct regulator_dev *reg)
  186. {
  187. return 0;
  188. }
  189. static int aon_regu_enable(struct regulator_dev *reg)
  190. {
  191. u16 regu_id =(u16) rdev_get_id(reg);
  192. return aon_regu_power_ctrl(light_aon_pmic_info.ipc_handle, regu_id, 1);
  193. }
  194. static int aon_regu_disable(struct regulator_dev *reg)
  195. {
  196. u16 regu_id =(u16) rdev_get_id(reg);
  197. return aon_regu_power_ctrl(light_aon_pmic_info.ipc_handle, regu_id, 0);
  198. }
  199. static int aon_regu_is_enabled(struct regulator_dev *reg)
  200. {
  201. struct light_aon_msg_regulator_ctrl msg = {0};
  202. struct light_aon_rpc_msg_hdr *hdr = &msg.hdr;
  203. int ret;
  204. u16 regu_id =(u16) rdev_get_id(reg);
  205. hdr->ver = LIGHT_AON_RPC_VERSION;
  206. hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM;
  207. hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_GET;
  208. hdr->size = LIGHT_AON_RPC_MSG_NUM;
  209. msg.rpc.regu_pwr_get.regu_id = regu_id;
  210. ret = light_aon_call_rpc(light_aon_pmic_info.ipc_handle, &msg, true);
  211. if (ret < 0) {
  212. return ret;
  213. }
  214. return (int) msg.rpc.regu_pwr_get.status;
  215. }
  216. static int aon_regu_set_voltage(struct regulator_dev *reg,
  217. int minuV, int uV, unsigned *selector)
  218. {
  219. u16 regu_id =(u16) rdev_get_id(reg);
  220. u32 voltage = minuV; /* uV */
  221. int err;
  222. pr_debug("[%s,%d]minuV = %d, uV = %d\n", __func__, __LINE__, minuV, uV);
  223. err = aon_set_regulator(light_aon_pmic_info.ipc_handle, regu_id,
  224. voltage, 0, 0);
  225. if (err) {
  226. pr_err("failed to set Voltages to %d!\n", minuV);
  227. return -EINVAL;
  228. }
  229. return 0;
  230. }
  231. static int aon_regu_get_voltage(struct regulator_dev *reg)
  232. {
  233. u16 regu_id = (u16) rdev_get_id(reg);
  234. int voltage, ret;
  235. ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, regu_id,
  236. &voltage, NULL, 0);
  237. if (ret) {
  238. pr_err("failed to get voltage\n");
  239. return -EINVAL;
  240. }
  241. pr_debug("[%s,%d]voltage = %d\n", __func__, __LINE__, voltage);
  242. return voltage;
  243. }
  244. static const struct apcpu_vol_set *apcpu_get_matched_signed_off_voltage(u32 vdd, u32 vddm)
  245. {
  246. int vol_count = ARRAY_SIZE(apcpu_volts);
  247. int i;
  248. for (i = 0; i < vol_count; i++)
  249. if ((vdd == apcpu_volts[i].vdd) &&
  250. (vddm == apcpu_volts[i].vddm))
  251. return &apcpu_volts[i];
  252. #ifdef CONFIG_AON_REG_DEBUG
  253. return &apcpu_volts[2];
  254. #else
  255. return NULL;
  256. #endif
  257. }
  258. static int apcpu_set_vdd_vddm_voltage(struct regulator_dev *reg,
  259. int minuV, int uV, unsigned *selector)
  260. {
  261. struct aon_regu_info *info = rdev_get_drvdata(reg);
  262. const struct apcpu_vol_set *cpu_vol;
  263. u32 vol = minuV; /* uV */
  264. u32 dc1, dc2;
  265. int err;
  266. cpu_vol = apcpu_get_matched_signed_off_voltage(vol, light_aon_pmic_info.vddm);
  267. if (!cpu_vol) {
  268. dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n");
  269. #ifndef CONFIG_AON_REG_DEBUG
  270. return -EINVAL;
  271. #endif
  272. }
  273. dc1 = cpu_vol->vdd;
  274. dc2 = cpu_vol->vddm;
  275. info->cpu_vol = cpu_vol;
  276. info->vddm = cpu_vol->vddm;
  277. err = aon_set_regulator(light_aon_pmic_info.ipc_handle, (u16)SOC_APCPU_DVDD_DVDDM,
  278. dc1, dc2, 1);
  279. if (err) {
  280. dev_err(info->dev, "failed to set Voltages to %d!\n", uV);
  281. return -EINVAL;
  282. }
  283. return 0;
  284. }
  285. static int apcpu_set_vddm_voltage(struct regulator_dev *reg,
  286. int minuV, int uV, unsigned *selector)
  287. {
  288. struct aon_regu_info *info = rdev_get_drvdata(reg);
  289. int bcore_table_count = ARRAY_SIZE(apcpu_volts);
  290. u32 vol = minuV; /* uV */
  291. int i;
  292. for (i = 0; i < bcore_table_count; i++)
  293. if (vol == apcpu_volts[i].vddm)
  294. break;
  295. if (i >= bcore_table_count) {
  296. dev_err(info->dev, "The vol is not existed in matching table\n");
  297. #ifndef CONFIG_AON_REG_DEBUG
  298. return -EINVAL;
  299. #endif
  300. }
  301. /* update the vddm */
  302. info->vddm = vol;
  303. return 0;
  304. }
  305. static int apcpu_get_voltage(struct regulator_dev *reg, bool is_vdd)
  306. {
  307. struct aon_regu_info *info = rdev_get_drvdata(reg);
  308. const struct apcpu_vol_set *cpu_vol;
  309. u32 dc1, dc2;
  310. int err;
  311. err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM,
  312. &dc1, &dc2, 1);
  313. if (err) {
  314. dev_err(info->dev, "failed to get Voltages!\n");
  315. return -EINVAL;
  316. }
  317. cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2);
  318. if (!cpu_vol) {
  319. dev_err(info->dev, "Voltage [%d:%d] is not existing in matching table\n", dc1, dc2);
  320. return -EINVAL;
  321. }
  322. info->cpu_vol = cpu_vol;
  323. return is_vdd ? cpu_vol->vdd : cpu_vol->vddm;
  324. }
  325. static int apcpu_get_vdd_voltage(struct regulator_dev *reg)
  326. {
  327. return apcpu_get_voltage(reg, true);
  328. }
  329. static int apcpu_get_vddm_voltage(struct regulator_dev *reg)
  330. {
  331. return apcpu_get_voltage(reg, false);
  332. }
  333. static const struct regulator_ops regu_common_ops = {
  334. .enable = aon_regu_enable,
  335. .disable = aon_regu_disable,
  336. .is_enabled = aon_regu_is_enabled,
  337. .list_voltage = regulator_list_voltage_linear,
  338. .set_voltage = aon_regu_set_voltage,
  339. .get_voltage = aon_regu_get_voltage,
  340. };
  341. static const struct regulator_ops apcpu_dvdd_ops = {
  342. .enable = aon_regu_dummy_enable,
  343. .disable = aon_regu_dummy_disable,
  344. .is_enabled = aon_regu_dummy_is_enabled,
  345. .list_voltage = regulator_list_voltage_linear,
  346. .set_voltage = apcpu_set_vdd_vddm_voltage,
  347. .get_voltage = apcpu_get_vdd_voltage,
  348. };
  349. static const struct regulator_ops apcpu_dvddm_ops = {
  350. .enable = aon_regu_dummy_enable,
  351. .disable = aon_regu_dummy_disable,
  352. .is_enabled = aon_regu_dummy_is_enabled,
  353. .list_voltage = regulator_list_voltage_linear,
  354. .set_voltage = apcpu_set_vddm_voltage,
  355. .get_voltage = apcpu_get_vddm_voltage,
  356. };
  357. /* Macros for voltage DC/DC converters (BUCKs) for cpu */
  358. #define REGU_DSC_DEF(regu_id, of_math_name) \
  359. .id = regu_id, \
  360. .name = #regu_id, \
  361. .of_match = of_match_ptr(__stringify(of_math_name)), \
  362. .ops = &regu_common_ops, \
  363. .type = REGULATOR_VOLTAGE, \
  364. .owner = THIS_MODULE
  365. #define BUCK_APCPU_DVDD(regu_id,min_mV, step_mV, max_mV) \
  366. .id = regu_id, \
  367. .name = "APCPU_DVDD", \
  368. .of_match = of_match_ptr("appcpu_dvdd"), \
  369. .ops = &apcpu_dvdd_ops, \
  370. .min_uV = (min_mV), \
  371. .uV_step = (step_mV), \
  372. .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \
  373. .type = REGULATOR_VOLTAGE, \
  374. .owner = THIS_MODULE
  375. #define BUCK_APCPU_DVDDM(regu_id, min_mV, step_mV, max_mV) \
  376. .id = regu_id, \
  377. .name = "APCPU_DVDDM", \
  378. .of_match = of_match_ptr("appcpu_dvddm"), \
  379. .ops = &apcpu_dvddm_ops, \
  380. .min_uV = (min_mV) , \
  381. .uV_step = (step_mV), \
  382. .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \
  383. .type = REGULATOR_VOLTAGE, \
  384. .owner = THIS_MODULE
  385. /* regulator desc for dialog */
  386. static struct regulator_desc light_dialog_ant_regu_desc[] = {
  387. /*cpu vdd vddm regulators, used to adjust vol dynamicaly */
  388. {
  389. BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000),
  390. },
  391. {
  392. BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000),
  393. },
  394. /*common regu ,no need to adjust vol dynamicaly */
  395. {
  396. REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon),
  397. },
  398. {
  399. REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3),
  400. },
  401. {
  402. REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon),
  403. },
  404. {
  405. REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr),
  406. },
  407. {
  408. REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8),
  409. },
  410. {
  411. REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1),
  412. },
  413. {
  414. REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6),
  415. },
  416. {
  417. REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap),
  418. },
  419. {
  420. REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap),
  421. },
  422. {
  423. REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi),
  424. },
  425. {
  426. REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi),
  427. },
  428. {
  429. REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc),
  430. },
  431. {
  432. REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc),
  433. },
  434. {
  435. REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan),
  436. },
  437. {
  438. REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan),
  439. },
  440. {
  441. REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en),
  442. },
  443. };
  444. static struct regulator_desc light_dialog_regu_desc[] = {
  445. /*cpu vdd vddm regulators, used to adjust vol dynamicaly */
  446. {
  447. BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000),
  448. },
  449. {
  450. BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000),
  451. },
  452. /*common regu ,no need to adjust vol dynamicaly */
  453. {
  454. REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon),
  455. },
  456. {
  457. REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3),
  458. },
  459. {
  460. REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon),
  461. },
  462. {
  463. REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr),
  464. },
  465. {
  466. REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8),
  467. },
  468. {
  469. REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1),
  470. },
  471. {
  472. REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6),
  473. },
  474. {
  475. REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap),
  476. },
  477. {
  478. REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap),
  479. },
  480. {
  481. REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi),
  482. },
  483. {
  484. REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi),
  485. },
  486. {
  487. REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc),
  488. },
  489. {
  490. REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc),
  491. },
  492. {
  493. REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan),
  494. },
  495. {
  496. REGU_DSC_DEF(SOC_VEXT_2V8,soc_vext_2v8),
  497. },
  498. {
  499. REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan),
  500. },
  501. {
  502. REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en),
  503. },
  504. {
  505. REGU_DSC_DEF(SOC_AVDD28_RGB,soc_avdd28_rgb),
  506. },
  507. {
  508. REGU_DSC_DEF(SOC_DOVDD18_RGB,soc_dovdd18_rgb),
  509. },
  510. {
  511. REGU_DSC_DEF(SOC_DVDD12_RGB,soc_dvdd12_rgb),
  512. },
  513. {
  514. REGU_DSC_DEF(SOC_AVDD25_IR,soc_avdd25_ir),
  515. },
  516. {
  517. REGU_DSC_DEF(SOC_DOVDD18_IR,soc_dovdd18_ir),
  518. },
  519. {
  520. REGU_DSC_DEF(SOC_DVDD12_IR,soc_dvdd12_ir),
  521. },
  522. };
  523. /* regulator desc for ricoh */
  524. static struct regulator_desc light_ricoh_regu_desc[] = {
  525. /*cpu vdd vddm regulators, used to adjust vol dynamicaly */
  526. {
  527. BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000),
  528. },
  529. {
  530. BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000),
  531. },
  532. /*common regu ,no need to adjust vol dynamicaly */
  533. {
  534. REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon),
  535. },
  536. {
  537. REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3),
  538. },
  539. {
  540. REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon),
  541. },
  542. {
  543. REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr),
  544. },
  545. {
  546. REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8),
  547. },
  548. {
  549. REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1),
  550. },
  551. {
  552. REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6),
  553. },
  554. {
  555. REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap),
  556. },
  557. {
  558. REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap),
  559. },
  560. {
  561. REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi),
  562. },
  563. {
  564. REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi),
  565. },
  566. {
  567. REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc),
  568. },
  569. {
  570. REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc),
  571. },
  572. {
  573. REGU_DSC_DEF(SOC_LCD0_EN,soc_lcd0_en),
  574. },
  575. {
  576. REGU_DSC_DEF(SOC_VEXT_1V8,soc_vext_1v8),
  577. },
  578. };
  579. #define GEN_REGISTER_SHOW(x, y) \
  580. static ssize_t x##_registers_show(struct device *dev, \
  581. struct device_attribute *attr, \
  582. char *buf) \
  583. { \
  584. struct platform_device *pdev = to_platform_device(dev); \
  585. struct aon_regu_info *info = platform_get_drvdata(pdev); \
  586. u32 dc1, dc2; \
  587. ssize_t ret; \
  588. \
  589. ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, y, \
  590. &dc1, &dc2, 0); \
  591. if (ret) { \
  592. dev_err(info->dev, "failed to get Voltages!\n"); \
  593. return -EINVAL; \
  594. } \
  595. \
  596. ret = sprintf(buf, "%u\n", dc1); \
  597. return ret; \
  598. }
  599. #define GEN_REGISTER_STORE(x, y) \
  600. static ssize_t x##_register_store(struct device *dev, \
  601. struct device_attribute *attr, \
  602. const char *buf, size_t count) \
  603. { \
  604. struct platform_device *pdev = to_platform_device(dev); \
  605. struct aon_regu_info *info = platform_get_drvdata(pdev); \
  606. unsigned long dc1, dc2 = 0; \
  607. int err; \
  608. \
  609. if (kstrtoul(buf, 0, &dc1)) \
  610. return -EINVAL; \
  611. \
  612. err = aon_set_regulator(light_aon_pmic_info.ipc_handle, y, \
  613. dc1, dc2, 0); \
  614. if (err) { \
  615. dev_err(info->dev, "failed to set Voltages to [%lu]!\n", dc1); \
  616. return -EINVAL; \
  617. } \
  618. \
  619. return count; \
  620. }
  621. static ssize_t soc_apcpu_dvdd_dvddm_registers_show(struct device *dev,
  622. struct device_attribute *attr, char *buf)
  623. {
  624. struct platform_device *pdev = to_platform_device(dev);
  625. struct aon_regu_info *info = platform_get_drvdata(pdev);
  626. size_t bufpos = 0, count = 26;
  627. const struct apcpu_vol_set *cpu_vol;
  628. u32 dc1, dc2;
  629. int i = 0;
  630. int err;
  631. err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM,
  632. &dc1, &dc2, 1);
  633. if (err) {
  634. dev_err(info->dev, "failed to get Voltages!\n");
  635. return -EINVAL;
  636. }
  637. cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2);
  638. if (!cpu_vol)
  639. dev_err(info->dev, "Read [%d:%d] is not existing in matching table\n", dc1, dc2);
  640. snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i);
  641. bufpos += 4;
  642. snprintf(buf + bufpos, count - bufpos, "%u", dc1);
  643. bufpos += 8;
  644. buf[bufpos++] = '\n';
  645. i++;
  646. snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i);
  647. bufpos += 4;
  648. snprintf(buf + bufpos, count - bufpos, "%u", dc2);
  649. bufpos += 8;
  650. buf[bufpos++] = '\n';
  651. return bufpos;
  652. }
  653. static ssize_t soc_apcpu_dvdd_dvddm_register_store(struct device *dev,
  654. struct device_attribute *attr,
  655. const char *buf, size_t size)
  656. {
  657. struct platform_device *pdev = to_platform_device(dev);
  658. struct aon_regu_info *info = platform_get_drvdata(pdev);
  659. const struct apcpu_vol_set *cpu_vol;
  660. char *start = (char *)buf;
  661. unsigned long dc1, dc2;
  662. int err;
  663. while (*start == ' ')
  664. start++;
  665. dc1 = simple_strtoul(start, &start, 0);
  666. while (*start == ' ')
  667. start++;
  668. if (kstrtoul(start, 0, &dc2))
  669. return -EINVAL;
  670. cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2);
  671. if (!cpu_vol) {
  672. dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n");
  673. #ifndef CONFIG_AON_REG_DEBUG
  674. return -EINVAL;
  675. #endif
  676. }
  677. info->cpu_vol = cpu_vol;
  678. info->vddm = cpu_vol->vddm;
  679. err = aon_set_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM,
  680. dc1, dc2, 1);
  681. if (err) {
  682. dev_err(info->dev, "failed to set Voltages to [%lu,%lu]!\n", dc1, dc2);
  683. #ifndef CONFIG_AON_REG_DEBUG
  684. return -EINVAL;
  685. #endif
  686. }
  687. return size;
  688. }
  689. GEN_REGISTER_SHOW(soc_dvdd18_aon, SOC_DVDD18_AON)
  690. GEN_REGISTER_STORE(soc_dvdd18_aon, SOC_DVDD18_AON)
  691. GEN_REGISTER_SHOW(soc_dvdd08_ap, SOC_DVDD08_AP)
  692. GEN_REGISTER_STORE(soc_dvdd08_ap, SOC_DVDD08_AP)
  693. GEN_REGISTER_SHOW(soc_dvdd18_emmc, SOC_DVDD18_EMMC)
  694. GEN_REGISTER_STORE(soc_dvdd18_emmc, SOC_DVDD18_EMMC)
  695. GEN_REGISTER_SHOW(soc_dvdd33_emmc, SOC_DVDD33_EMMC)
  696. GEN_REGISTER_STORE(soc_dvdd33_emmc, SOC_DVDD33_EMMC)
  697. static DEVICE_ATTR(soc_dvdd18_aon_regs, 0644, soc_dvdd18_aon_registers_show, soc_dvdd18_aon_register_store);
  698. static DEVICE_ATTR(soc_dvdd08_ap_regs, 0644, soc_dvdd08_ap_registers_show, soc_dvdd08_ap_register_store);
  699. static DEVICE_ATTR(soc_dvdd33_emmc_regs, 0644, soc_dvdd33_emmc_registers_show, soc_dvdd33_emmc_register_store);
  700. static DEVICE_ATTR(soc_dvdd18_emmc_regs, 0644, soc_dvdd18_emmc_registers_show, soc_dvdd18_emmc_register_store);
  701. static DEVICE_ATTR(soc_apcpu_dvdd_dvddm_regs, 0644, soc_apcpu_dvdd_dvddm_registers_show, soc_apcpu_dvdd_dvddm_register_store);
  702. static struct attribute *aon_regs_sysfs_entries[] = {
  703. &dev_attr_soc_dvdd18_aon_regs.attr,
  704. &dev_attr_soc_dvdd08_ap_regs.attr,
  705. &dev_attr_soc_dvdd33_emmc_regs.attr,
  706. &dev_attr_soc_dvdd18_emmc_regs.attr,
  707. &dev_attr_soc_apcpu_dvdd_dvddm_regs.attr,
  708. NULL
  709. };
  710. static const struct attribute_group dev_attr_aon_regs_group = {
  711. .attrs = aon_regs_sysfs_entries,
  712. };
  713. static const struct aon_regu_desc light_dialog_regus = {
  714. .regu_desc = (struct regulator_desc*) &light_dialog_regu_desc,
  715. .regu_num = ARRAY_SIZE(light_dialog_regu_desc),
  716. };
  717. static const struct aon_regu_desc light_dialog_ant_regus = {
  718. .regu_desc = (struct regulator_desc*) &light_dialog_ant_regu_desc,
  719. .regu_num = ARRAY_SIZE(light_dialog_ant_regu_desc),
  720. };
  721. static const struct aon_regu_desc light_ricoh_regus = {
  722. .regu_desc = (struct regulator_desc*)&light_ricoh_regu_desc,
  723. .regu_num = ARRAY_SIZE(light_ricoh_regu_desc),
  724. };
  725. static int light_aon_regulator_probe(struct platform_device *pdev)
  726. {
  727. struct device_node *np = pdev->dev.of_node;
  728. struct regulator_config config = { };
  729. int i;
  730. int ret;
  731. struct aon_regu_desc *regus_set = NULL;
  732. if (!np)
  733. return -ENODEV;
  734. regus_set = (struct aon_regu_desc*)of_device_get_match_data(&pdev->dev);
  735. if (!regus_set) {
  736. return -ENODEV;
  737. }
  738. /*get ipc handle */
  739. ret = light_aon_get_handle(&(light_aon_pmic_info.ipc_handle));
  740. if (ret) {
  741. dev_err(&pdev->dev, "failed to get ipc_handle\n");
  742. return ret;
  743. }
  744. /*init private drv data */
  745. light_aon_pmic_info.dev = &pdev->dev;
  746. light_aon_pmic_info.regu_desc = regus_set;
  747. light_aon_pmic_info.cpu_vol = &apcpu_volts[2]; /* pmic default voltages */
  748. light_aon_pmic_info.vddm = light_aon_pmic_info.cpu_vol->vddm;
  749. /*register all regulators*/
  750. config.dev = &pdev->dev;
  751. config.driver_data = &light_aon_pmic_info;
  752. for (i = 0; i < regus_set->regu_num; i++) {
  753. struct regulator_dev *rdev;
  754. struct regulator_desc *desc;
  755. desc = &regus_set->regu_desc[i];
  756. rdev = devm_regulator_register(&pdev->dev, desc, &config);
  757. if (IS_ERR(rdev)) {
  758. dev_err(&pdev->dev,
  759. "Failed to initialize regulator-%d\n", i);
  760. return PTR_ERR(rdev);
  761. }
  762. }
  763. i = sysfs_create_group(&config.dev->kobj, &dev_attr_aon_regs_group);
  764. if (i) {
  765. dev_err(&pdev->dev, "Failed to create aon regs debug sysfs.\n");
  766. return i;
  767. }
  768. platform_set_drvdata(pdev, &light_aon_pmic_info);
  769. return 0;
  770. }
  771. static const struct of_device_id light_pmic_dev_id[] = {
  772. { .compatible = "thead,light-dialog-pmic-ant", .data = &light_dialog_ant_regus},
  773. { .compatible = "thead,light-dialog-pmic", .data = &light_dialog_regus},
  774. { .compatible = "thead,light-ricoh-pmic", .data = &light_ricoh_regus},
  775. {},
  776. };
  777. MODULE_DEVICE_TABLE(of, light_pmic_dev_id);
  778. static struct platform_driver light_aon_regulator_driver = {
  779. .driver = {
  780. .name = "light-aon-reg",
  781. .owner = THIS_MODULE,
  782. .of_match_table = light_pmic_dev_id,
  783. },
  784. .probe = light_aon_regulator_probe,
  785. };
  786. module_platform_driver(light_aon_regulator_driver);
  787. MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>");
  788. MODULE_AUTHOR("linghui.zlh <linghui.zlh@linux.alibaba.com>");
  789. MODULE_DESCRIPTION("Thead Light Aon regulator virtual driver");
  790. MODULE_LICENSE("GPL v2");