18c2ecf20Sopenharmony_ci //SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Spreadtrum Communications Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 98c2ecf20Sopenharmony_ci#include <linux/regmap.h> 108c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * SC2731 regulator lock register 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci#define SC2731_PWR_WR_PROT 0xf0c 178c2ecf20Sopenharmony_ci#define SC2731_WR_UNLOCK_VALUE 0x6e7f 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * SC2731 enable register 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#define SC2731_POWER_PD_SW 0xc28 238c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA0_PD 0xcfc 248c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA1_PD 0xd04 258c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMMOT_PD 0xd0c 268c2ecf20Sopenharmony_ci#define SC2731_LDO_VLDO_PD 0xd6c 278c2ecf20Sopenharmony_ci#define SC2731_LDO_EMMCCORE_PD 0xd2c 288c2ecf20Sopenharmony_ci#define SC2731_LDO_SDCORE_PD 0xd74 298c2ecf20Sopenharmony_ci#define SC2731_LDO_SDIO_PD 0xd70 308c2ecf20Sopenharmony_ci#define SC2731_LDO_WIFIPA_PD 0xd4c 318c2ecf20Sopenharmony_ci#define SC2731_LDO_USB33_PD 0xd5c 328c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD0_PD 0xd7c 338c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD1_PD 0xd84 348c2ecf20Sopenharmony_ci#define SC2731_LDO_CON_PD 0xd8c 358c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMIO_PD 0xd94 368c2ecf20Sopenharmony_ci#define SC2731_LDO_SRAM_PD 0xd78 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * SC2731 enable mask 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU0_PD_MASK BIT(4) 428c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU1_PD_MASK BIT(3) 438c2ecf20Sopenharmony_ci#define SC2731_DCDC_RF_PD_MASK BIT(11) 448c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA0_PD_MASK BIT(0) 458c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA1_PD_MASK BIT(0) 468c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMMOT_PD_MASK BIT(0) 478c2ecf20Sopenharmony_ci#define SC2731_LDO_VLDO_PD_MASK BIT(0) 488c2ecf20Sopenharmony_ci#define SC2731_LDO_EMMCCORE_PD_MASK BIT(0) 498c2ecf20Sopenharmony_ci#define SC2731_LDO_SDCORE_PD_MASK BIT(0) 508c2ecf20Sopenharmony_ci#define SC2731_LDO_SDIO_PD_MASK BIT(0) 518c2ecf20Sopenharmony_ci#define SC2731_LDO_WIFIPA_PD_MASK BIT(0) 528c2ecf20Sopenharmony_ci#define SC2731_LDO_USB33_PD_MASK BIT(0) 538c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD0_PD_MASK BIT(0) 548c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD1_PD_MASK BIT(0) 558c2ecf20Sopenharmony_ci#define SC2731_LDO_CON_PD_MASK BIT(0) 568c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMIO_PD_MASK BIT(0) 578c2ecf20Sopenharmony_ci#define SC2731_LDO_SRAM_PD_MASK BIT(0) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * SC2731 vsel register 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU0_VOL 0xc54 638c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU1_VOL 0xc64 648c2ecf20Sopenharmony_ci#define SC2731_DCDC_RF_VOL 0xcb8 658c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA0_VOL 0xd00 668c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA1_VOL 0xd08 678c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMMOT_VOL 0xd10 688c2ecf20Sopenharmony_ci#define SC2731_LDO_VLDO_VOL 0xd28 698c2ecf20Sopenharmony_ci#define SC2731_LDO_EMMCCORE_VOL 0xd30 708c2ecf20Sopenharmony_ci#define SC2731_LDO_SDCORE_VOL 0xd38 718c2ecf20Sopenharmony_ci#define SC2731_LDO_SDIO_VOL 0xd40 728c2ecf20Sopenharmony_ci#define SC2731_LDO_WIFIPA_VOL 0xd50 738c2ecf20Sopenharmony_ci#define SC2731_LDO_USB33_VOL 0xd60 748c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD0_VOL 0xd80 758c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD1_VOL 0xd88 768c2ecf20Sopenharmony_ci#define SC2731_LDO_CON_VOL 0xd90 778c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMIO_VOL 0xd98 788c2ecf20Sopenharmony_ci#define SC2731_LDO_SRAM_VOL 0xdB0 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * SC2731 vsel register mask 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU0_VOL_MASK GENMASK(8, 0) 848c2ecf20Sopenharmony_ci#define SC2731_DCDC_CPU1_VOL_MASK GENMASK(8, 0) 858c2ecf20Sopenharmony_ci#define SC2731_DCDC_RF_VOL_MASK GENMASK(8, 0) 868c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA0_VOL_MASK GENMASK(7, 0) 878c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMA1_VOL_MASK GENMASK(7, 0) 888c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMMOT_VOL_MASK GENMASK(7, 0) 898c2ecf20Sopenharmony_ci#define SC2731_LDO_VLDO_VOL_MASK GENMASK(7, 0) 908c2ecf20Sopenharmony_ci#define SC2731_LDO_EMMCCORE_VOL_MASK GENMASK(7, 0) 918c2ecf20Sopenharmony_ci#define SC2731_LDO_SDCORE_VOL_MASK GENMASK(7, 0) 928c2ecf20Sopenharmony_ci#define SC2731_LDO_SDIO_VOL_MASK GENMASK(7, 0) 938c2ecf20Sopenharmony_ci#define SC2731_LDO_WIFIPA_VOL_MASK GENMASK(7, 0) 948c2ecf20Sopenharmony_ci#define SC2731_LDO_USB33_VOL_MASK GENMASK(7, 0) 958c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD0_VOL_MASK GENMASK(6, 0) 968c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMD1_VOL_MASK GENMASK(6, 0) 978c2ecf20Sopenharmony_ci#define SC2731_LDO_CON_VOL_MASK GENMASK(6, 0) 988c2ecf20Sopenharmony_ci#define SC2731_LDO_CAMIO_VOL_MASK GENMASK(6, 0) 998c2ecf20Sopenharmony_ci#define SC2731_LDO_SRAM_VOL_MASK GENMASK(6, 0) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cienum sc2731_regulator_id { 1028c2ecf20Sopenharmony_ci SC2731_BUCK_CPU0, 1038c2ecf20Sopenharmony_ci SC2731_BUCK_CPU1, 1048c2ecf20Sopenharmony_ci SC2731_BUCK_RF, 1058c2ecf20Sopenharmony_ci SC2731_LDO_CAMA0, 1068c2ecf20Sopenharmony_ci SC2731_LDO_CAMA1, 1078c2ecf20Sopenharmony_ci SC2731_LDO_CAMMOT, 1088c2ecf20Sopenharmony_ci SC2731_LDO_VLDO, 1098c2ecf20Sopenharmony_ci SC2731_LDO_EMMCCORE, 1108c2ecf20Sopenharmony_ci SC2731_LDO_SDCORE, 1118c2ecf20Sopenharmony_ci SC2731_LDO_SDIO, 1128c2ecf20Sopenharmony_ci SC2731_LDO_WIFIPA, 1138c2ecf20Sopenharmony_ci SC2731_LDO_USB33, 1148c2ecf20Sopenharmony_ci SC2731_LDO_CAMD0, 1158c2ecf20Sopenharmony_ci SC2731_LDO_CAMD1, 1168c2ecf20Sopenharmony_ci SC2731_LDO_CON, 1178c2ecf20Sopenharmony_ci SC2731_LDO_CAMIO, 1188c2ecf20Sopenharmony_ci SC2731_LDO_SRAM, 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic const struct regulator_ops sc2731_regu_linear_ops = { 1228c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 1238c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 1248c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 1258c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 1268c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 1278c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define SC2731_REGU_LINEAR(_id, en_reg, en_mask, vreg, vmask, \ 1318c2ecf20Sopenharmony_ci vstep, vmin, vmax) { \ 1328c2ecf20Sopenharmony_ci .name = #_id, \ 1338c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_id), \ 1348c2ecf20Sopenharmony_ci .ops = &sc2731_regu_linear_ops, \ 1358c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 1368c2ecf20Sopenharmony_ci .id = SC2731_##_id, \ 1378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 1388c2ecf20Sopenharmony_ci .min_uV = vmin, \ 1398c2ecf20Sopenharmony_ci .n_voltages = ((vmax) - (vmin)) / (vstep) + 1, \ 1408c2ecf20Sopenharmony_ci .uV_step = vstep, \ 1418c2ecf20Sopenharmony_ci .enable_is_inverted = true, \ 1428c2ecf20Sopenharmony_ci .enable_val = 0, \ 1438c2ecf20Sopenharmony_ci .enable_reg = en_reg, \ 1448c2ecf20Sopenharmony_ci .enable_mask = en_mask, \ 1458c2ecf20Sopenharmony_ci .vsel_reg = vreg, \ 1468c2ecf20Sopenharmony_ci .vsel_mask = vmask, \ 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct regulator_desc regulators[] = { 1508c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(BUCK_CPU0, SC2731_POWER_PD_SW, 1518c2ecf20Sopenharmony_ci SC2731_DCDC_CPU0_PD_MASK, SC2731_DCDC_CPU0_VOL, 1528c2ecf20Sopenharmony_ci SC2731_DCDC_CPU0_VOL_MASK, 3125, 400000, 1996875), 1538c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(BUCK_CPU1, SC2731_POWER_PD_SW, 1548c2ecf20Sopenharmony_ci SC2731_DCDC_CPU1_PD_MASK, SC2731_DCDC_CPU1_VOL, 1558c2ecf20Sopenharmony_ci SC2731_DCDC_CPU1_VOL_MASK, 3125, 400000, 1996875), 1568c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(BUCK_RF, SC2731_POWER_PD_SW, SC2731_DCDC_RF_PD_MASK, 1578c2ecf20Sopenharmony_ci SC2731_DCDC_RF_VOL, SC2731_DCDC_RF_VOL_MASK, 1588c2ecf20Sopenharmony_ci 3125, 600000, 2196875), 1598c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMA0, SC2731_LDO_CAMA0_PD, 1608c2ecf20Sopenharmony_ci SC2731_LDO_CAMA0_PD_MASK, SC2731_LDO_CAMA0_VOL, 1618c2ecf20Sopenharmony_ci SC2731_LDO_CAMA0_VOL_MASK, 10000, 1200000, 3750000), 1628c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMA1, SC2731_LDO_CAMA1_PD, 1638c2ecf20Sopenharmony_ci SC2731_LDO_CAMA1_PD_MASK, SC2731_LDO_CAMA1_VOL, 1648c2ecf20Sopenharmony_ci SC2731_LDO_CAMA1_VOL_MASK, 10000, 1200000, 3750000), 1658c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMMOT, SC2731_LDO_CAMMOT_PD, 1668c2ecf20Sopenharmony_ci SC2731_LDO_CAMMOT_PD_MASK, SC2731_LDO_CAMMOT_VOL, 1678c2ecf20Sopenharmony_ci SC2731_LDO_CAMMOT_VOL_MASK, 10000, 1200000, 3750000), 1688c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_VLDO, SC2731_LDO_VLDO_PD, 1698c2ecf20Sopenharmony_ci SC2731_LDO_VLDO_PD_MASK, SC2731_LDO_VLDO_VOL, 1708c2ecf20Sopenharmony_ci SC2731_LDO_VLDO_VOL_MASK, 10000, 1200000, 3750000), 1718c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_EMMCCORE, SC2731_LDO_EMMCCORE_PD, 1728c2ecf20Sopenharmony_ci SC2731_LDO_EMMCCORE_PD_MASK, SC2731_LDO_EMMCCORE_VOL, 1738c2ecf20Sopenharmony_ci SC2731_LDO_EMMCCORE_VOL_MASK, 10000, 1200000, 1748c2ecf20Sopenharmony_ci 3750000), 1758c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_SDCORE, SC2731_LDO_SDCORE_PD, 1768c2ecf20Sopenharmony_ci SC2731_LDO_SDCORE_PD_MASK, SC2731_LDO_SDCORE_VOL, 1778c2ecf20Sopenharmony_ci SC2731_LDO_SDCORE_VOL_MASK, 10000, 1200000, 3750000), 1788c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_SDIO, SC2731_LDO_SDIO_PD, 1798c2ecf20Sopenharmony_ci SC2731_LDO_SDIO_PD_MASK, SC2731_LDO_SDIO_VOL, 1808c2ecf20Sopenharmony_ci SC2731_LDO_SDIO_VOL_MASK, 10000, 1200000, 3750000), 1818c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_WIFIPA, SC2731_LDO_WIFIPA_PD, 1828c2ecf20Sopenharmony_ci SC2731_LDO_WIFIPA_PD_MASK, SC2731_LDO_WIFIPA_VOL, 1838c2ecf20Sopenharmony_ci SC2731_LDO_WIFIPA_VOL_MASK, 10000, 1200000, 3750000), 1848c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_USB33, SC2731_LDO_USB33_PD, 1858c2ecf20Sopenharmony_ci SC2731_LDO_USB33_PD_MASK, SC2731_LDO_USB33_VOL, 1868c2ecf20Sopenharmony_ci SC2731_LDO_USB33_VOL_MASK, 10000, 1200000, 3750000), 1878c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMD0, SC2731_LDO_CAMD0_PD, 1888c2ecf20Sopenharmony_ci SC2731_LDO_CAMD0_PD_MASK, SC2731_LDO_CAMD0_VOL, 1898c2ecf20Sopenharmony_ci SC2731_LDO_CAMD0_VOL_MASK, 6250, 1000000, 1793750), 1908c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMD1, SC2731_LDO_CAMD1_PD, 1918c2ecf20Sopenharmony_ci SC2731_LDO_CAMD1_PD_MASK, SC2731_LDO_CAMD1_VOL, 1928c2ecf20Sopenharmony_ci SC2731_LDO_CAMD1_VOL_MASK, 6250, 1000000, 1793750), 1938c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CON, SC2731_LDO_CON_PD, 1948c2ecf20Sopenharmony_ci SC2731_LDO_CON_PD_MASK, SC2731_LDO_CON_VOL, 1958c2ecf20Sopenharmony_ci SC2731_LDO_CON_VOL_MASK, 6250, 1000000, 1793750), 1968c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_CAMIO, SC2731_LDO_CAMIO_PD, 1978c2ecf20Sopenharmony_ci SC2731_LDO_CAMIO_PD_MASK, SC2731_LDO_CAMIO_VOL, 1988c2ecf20Sopenharmony_ci SC2731_LDO_CAMIO_VOL_MASK, 6250, 1000000, 1793750), 1998c2ecf20Sopenharmony_ci SC2731_REGU_LINEAR(LDO_SRAM, SC2731_LDO_SRAM_PD, 2008c2ecf20Sopenharmony_ci SC2731_LDO_SRAM_PD_MASK, SC2731_LDO_SRAM_VOL, 2018c2ecf20Sopenharmony_ci SC2731_LDO_SRAM_VOL_MASK, 6250, 1000000, 1793750), 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int sc2731_regulator_unlock(struct regmap *regmap) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return regmap_write(regmap, SC2731_PWR_WR_PROT, 2078c2ecf20Sopenharmony_ci SC2731_WR_UNLOCK_VALUE); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int sc2731_regulator_probe(struct platform_device *pdev) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci int i, ret; 2138c2ecf20Sopenharmony_ci struct regmap *regmap; 2148c2ecf20Sopenharmony_ci struct regulator_config config = { }; 2158c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci regmap = dev_get_regmap(pdev->dev.parent, NULL); 2188c2ecf20Sopenharmony_ci if (!regmap) { 2198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get regmap.\n"); 2208c2ecf20Sopenharmony_ci return -ENODEV; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = sc2731_regulator_unlock(regmap); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to release regulator lock\n"); 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci config.dev = &pdev->dev; 2308c2ecf20Sopenharmony_ci config.regmap = regmap; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulators); i++) { 2338c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, ®ulators[i], 2348c2ecf20Sopenharmony_ci &config); 2358c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 2368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 2378c2ecf20Sopenharmony_ci regulators[i].name); 2388c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic struct platform_driver sc2731_regulator_driver = { 2468c2ecf20Sopenharmony_ci .driver = { 2478c2ecf20Sopenharmony_ci .name = "sc27xx-regulator", 2488c2ecf20Sopenharmony_ci }, 2498c2ecf20Sopenharmony_ci .probe = sc2731_regulator_probe, 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cimodule_platform_driver(sc2731_regulator_driver); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chen Junhui <erick.chen@spreadtrum.com>"); 2558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Spreadtrum SC2731 regulator driver"); 2568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 257