258 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2017 Spreadtrum Communications Inc.4 */5 6#include <linux/module.h>7#include <linux/of.h>8#include <linux/platform_device.h>9#include <linux/regmap.h>10#include <linux/regulator/driver.h>11#include <linux/regulator/of_regulator.h>12 13/*14 * SC2731 regulator lock register15 */16#define SC2731_PWR_WR_PROT 0xf0c17#define SC2731_WR_UNLOCK_VALUE 0x6e7f18 19/*20 * SC2731 enable register21 */22#define SC2731_POWER_PD_SW 0xc2823#define SC2731_LDO_CAMA0_PD 0xcfc24#define SC2731_LDO_CAMA1_PD 0xd0425#define SC2731_LDO_CAMMOT_PD 0xd0c26#define SC2731_LDO_VLDO_PD 0xd6c27#define SC2731_LDO_EMMCCORE_PD 0xd2c28#define SC2731_LDO_SDCORE_PD 0xd7429#define SC2731_LDO_SDIO_PD 0xd7030#define SC2731_LDO_WIFIPA_PD 0xd4c31#define SC2731_LDO_USB33_PD 0xd5c32#define SC2731_LDO_CAMD0_PD 0xd7c33#define SC2731_LDO_CAMD1_PD 0xd8434#define SC2731_LDO_CON_PD 0xd8c35#define SC2731_LDO_CAMIO_PD 0xd9436#define SC2731_LDO_SRAM_PD 0xd7837 38/*39 * SC2731 enable mask40 */41#define SC2731_DCDC_CPU0_PD_MASK BIT(4)42#define SC2731_DCDC_CPU1_PD_MASK BIT(3)43#define SC2731_DCDC_RF_PD_MASK BIT(11)44#define SC2731_LDO_CAMA0_PD_MASK BIT(0)45#define SC2731_LDO_CAMA1_PD_MASK BIT(0)46#define SC2731_LDO_CAMMOT_PD_MASK BIT(0)47#define SC2731_LDO_VLDO_PD_MASK BIT(0)48#define SC2731_LDO_EMMCCORE_PD_MASK BIT(0)49#define SC2731_LDO_SDCORE_PD_MASK BIT(0)50#define SC2731_LDO_SDIO_PD_MASK BIT(0)51#define SC2731_LDO_WIFIPA_PD_MASK BIT(0)52#define SC2731_LDO_USB33_PD_MASK BIT(0)53#define SC2731_LDO_CAMD0_PD_MASK BIT(0)54#define SC2731_LDO_CAMD1_PD_MASK BIT(0)55#define SC2731_LDO_CON_PD_MASK BIT(0)56#define SC2731_LDO_CAMIO_PD_MASK BIT(0)57#define SC2731_LDO_SRAM_PD_MASK BIT(0)58 59/*60 * SC2731 vsel register61 */62#define SC2731_DCDC_CPU0_VOL 0xc5463#define SC2731_DCDC_CPU1_VOL 0xc6464#define SC2731_DCDC_RF_VOL 0xcb865#define SC2731_LDO_CAMA0_VOL 0xd0066#define SC2731_LDO_CAMA1_VOL 0xd0867#define SC2731_LDO_CAMMOT_VOL 0xd1068#define SC2731_LDO_VLDO_VOL 0xd2869#define SC2731_LDO_EMMCCORE_VOL 0xd3070#define SC2731_LDO_SDCORE_VOL 0xd3871#define SC2731_LDO_SDIO_VOL 0xd4072#define SC2731_LDO_WIFIPA_VOL 0xd5073#define SC2731_LDO_USB33_VOL 0xd6074#define SC2731_LDO_CAMD0_VOL 0xd8075#define SC2731_LDO_CAMD1_VOL 0xd8876#define SC2731_LDO_CON_VOL 0xd9077#define SC2731_LDO_CAMIO_VOL 0xd9878#define SC2731_LDO_SRAM_VOL 0xdB079 80/*81 * SC2731 vsel register mask82 */83#define SC2731_DCDC_CPU0_VOL_MASK GENMASK(8, 0)84#define SC2731_DCDC_CPU1_VOL_MASK GENMASK(8, 0)85#define SC2731_DCDC_RF_VOL_MASK GENMASK(8, 0)86#define SC2731_LDO_CAMA0_VOL_MASK GENMASK(7, 0)87#define SC2731_LDO_CAMA1_VOL_MASK GENMASK(7, 0)88#define SC2731_LDO_CAMMOT_VOL_MASK GENMASK(7, 0)89#define SC2731_LDO_VLDO_VOL_MASK GENMASK(7, 0)90#define SC2731_LDO_EMMCCORE_VOL_MASK GENMASK(7, 0)91#define SC2731_LDO_SDCORE_VOL_MASK GENMASK(7, 0)92#define SC2731_LDO_SDIO_VOL_MASK GENMASK(7, 0)93#define SC2731_LDO_WIFIPA_VOL_MASK GENMASK(7, 0)94#define SC2731_LDO_USB33_VOL_MASK GENMASK(7, 0)95#define SC2731_LDO_CAMD0_VOL_MASK GENMASK(6, 0)96#define SC2731_LDO_CAMD1_VOL_MASK GENMASK(6, 0)97#define SC2731_LDO_CON_VOL_MASK GENMASK(6, 0)98#define SC2731_LDO_CAMIO_VOL_MASK GENMASK(6, 0)99#define SC2731_LDO_SRAM_VOL_MASK GENMASK(6, 0)100 101enum sc2731_regulator_id {102 SC2731_BUCK_CPU0,103 SC2731_BUCK_CPU1,104 SC2731_BUCK_RF,105 SC2731_LDO_CAMA0,106 SC2731_LDO_CAMA1,107 SC2731_LDO_CAMMOT,108 SC2731_LDO_VLDO,109 SC2731_LDO_EMMCCORE,110 SC2731_LDO_SDCORE,111 SC2731_LDO_SDIO,112 SC2731_LDO_WIFIPA,113 SC2731_LDO_USB33,114 SC2731_LDO_CAMD0,115 SC2731_LDO_CAMD1,116 SC2731_LDO_CON,117 SC2731_LDO_CAMIO,118 SC2731_LDO_SRAM,119};120 121static const struct regulator_ops sc2731_regu_linear_ops = {122 .enable = regulator_enable_regmap,123 .disable = regulator_disable_regmap,124 .is_enabled = regulator_is_enabled_regmap,125 .list_voltage = regulator_list_voltage_linear,126 .get_voltage_sel = regulator_get_voltage_sel_regmap,127 .set_voltage_sel = regulator_set_voltage_sel_regmap,128};129 130#define SC2731_REGU_LINEAR(_id, en_reg, en_mask, vreg, vmask, \131 vstep, vmin, vmax) { \132 .name = #_id, \133 .of_match = of_match_ptr(#_id), \134 .ops = &sc2731_regu_linear_ops, \135 .type = REGULATOR_VOLTAGE, \136 .id = SC2731_##_id, \137 .owner = THIS_MODULE, \138 .min_uV = vmin, \139 .n_voltages = ((vmax) - (vmin)) / (vstep) + 1, \140 .uV_step = vstep, \141 .enable_is_inverted = true, \142 .enable_val = 0, \143 .enable_reg = en_reg, \144 .enable_mask = en_mask, \145 .vsel_reg = vreg, \146 .vsel_mask = vmask, \147}148 149static const struct regulator_desc regulators[] = {150 SC2731_REGU_LINEAR(BUCK_CPU0, SC2731_POWER_PD_SW,151 SC2731_DCDC_CPU0_PD_MASK, SC2731_DCDC_CPU0_VOL,152 SC2731_DCDC_CPU0_VOL_MASK, 3125, 400000, 1996875),153 SC2731_REGU_LINEAR(BUCK_CPU1, SC2731_POWER_PD_SW,154 SC2731_DCDC_CPU1_PD_MASK, SC2731_DCDC_CPU1_VOL,155 SC2731_DCDC_CPU1_VOL_MASK, 3125, 400000, 1996875),156 SC2731_REGU_LINEAR(BUCK_RF, SC2731_POWER_PD_SW, SC2731_DCDC_RF_PD_MASK,157 SC2731_DCDC_RF_VOL, SC2731_DCDC_RF_VOL_MASK,158 3125, 600000, 2196875),159 SC2731_REGU_LINEAR(LDO_CAMA0, SC2731_LDO_CAMA0_PD,160 SC2731_LDO_CAMA0_PD_MASK, SC2731_LDO_CAMA0_VOL,161 SC2731_LDO_CAMA0_VOL_MASK, 10000, 1200000, 3750000),162 SC2731_REGU_LINEAR(LDO_CAMA1, SC2731_LDO_CAMA1_PD,163 SC2731_LDO_CAMA1_PD_MASK, SC2731_LDO_CAMA1_VOL,164 SC2731_LDO_CAMA1_VOL_MASK, 10000, 1200000, 3750000),165 SC2731_REGU_LINEAR(LDO_CAMMOT, SC2731_LDO_CAMMOT_PD,166 SC2731_LDO_CAMMOT_PD_MASK, SC2731_LDO_CAMMOT_VOL,167 SC2731_LDO_CAMMOT_VOL_MASK, 10000, 1200000, 3750000),168 SC2731_REGU_LINEAR(LDO_VLDO, SC2731_LDO_VLDO_PD,169 SC2731_LDO_VLDO_PD_MASK, SC2731_LDO_VLDO_VOL,170 SC2731_LDO_VLDO_VOL_MASK, 10000, 1200000, 3750000),171 SC2731_REGU_LINEAR(LDO_EMMCCORE, SC2731_LDO_EMMCCORE_PD,172 SC2731_LDO_EMMCCORE_PD_MASK, SC2731_LDO_EMMCCORE_VOL,173 SC2731_LDO_EMMCCORE_VOL_MASK, 10000, 1200000,174 3750000),175 SC2731_REGU_LINEAR(LDO_SDCORE, SC2731_LDO_SDCORE_PD,176 SC2731_LDO_SDCORE_PD_MASK, SC2731_LDO_SDCORE_VOL,177 SC2731_LDO_SDCORE_VOL_MASK, 10000, 1200000, 3750000),178 SC2731_REGU_LINEAR(LDO_SDIO, SC2731_LDO_SDIO_PD,179 SC2731_LDO_SDIO_PD_MASK, SC2731_LDO_SDIO_VOL,180 SC2731_LDO_SDIO_VOL_MASK, 10000, 1200000, 3750000),181 SC2731_REGU_LINEAR(LDO_WIFIPA, SC2731_LDO_WIFIPA_PD,182 SC2731_LDO_WIFIPA_PD_MASK, SC2731_LDO_WIFIPA_VOL,183 SC2731_LDO_WIFIPA_VOL_MASK, 10000, 1200000, 3750000),184 SC2731_REGU_LINEAR(LDO_USB33, SC2731_LDO_USB33_PD,185 SC2731_LDO_USB33_PD_MASK, SC2731_LDO_USB33_VOL,186 SC2731_LDO_USB33_VOL_MASK, 10000, 1200000, 3750000),187 SC2731_REGU_LINEAR(LDO_CAMD0, SC2731_LDO_CAMD0_PD,188 SC2731_LDO_CAMD0_PD_MASK, SC2731_LDO_CAMD0_VOL,189 SC2731_LDO_CAMD0_VOL_MASK, 6250, 1000000, 1793750),190 SC2731_REGU_LINEAR(LDO_CAMD1, SC2731_LDO_CAMD1_PD,191 SC2731_LDO_CAMD1_PD_MASK, SC2731_LDO_CAMD1_VOL,192 SC2731_LDO_CAMD1_VOL_MASK, 6250, 1000000, 1793750),193 SC2731_REGU_LINEAR(LDO_CON, SC2731_LDO_CON_PD,194 SC2731_LDO_CON_PD_MASK, SC2731_LDO_CON_VOL,195 SC2731_LDO_CON_VOL_MASK, 6250, 1000000, 1793750),196 SC2731_REGU_LINEAR(LDO_CAMIO, SC2731_LDO_CAMIO_PD,197 SC2731_LDO_CAMIO_PD_MASK, SC2731_LDO_CAMIO_VOL,198 SC2731_LDO_CAMIO_VOL_MASK, 6250, 1000000, 1793750),199 SC2731_REGU_LINEAR(LDO_SRAM, SC2731_LDO_SRAM_PD,200 SC2731_LDO_SRAM_PD_MASK, SC2731_LDO_SRAM_VOL,201 SC2731_LDO_SRAM_VOL_MASK, 6250, 1000000, 1793750),202};203 204static int sc2731_regulator_unlock(struct regmap *regmap)205{206 return regmap_write(regmap, SC2731_PWR_WR_PROT,207 SC2731_WR_UNLOCK_VALUE);208}209 210static int sc2731_regulator_probe(struct platform_device *pdev)211{212 int i, ret;213 struct regmap *regmap;214 struct regulator_config config = { };215 struct regulator_dev *rdev;216 217 regmap = dev_get_regmap(pdev->dev.parent, NULL);218 if (!regmap) {219 dev_err(&pdev->dev, "failed to get regmap.\n");220 return -ENODEV;221 }222 223 ret = sc2731_regulator_unlock(regmap);224 if (ret) {225 dev_err(&pdev->dev, "failed to release regulator lock\n");226 return ret;227 }228 229 config.dev = &pdev->dev;230 config.regmap = regmap;231 232 for (i = 0; i < ARRAY_SIZE(regulators); i++) {233 rdev = devm_regulator_register(&pdev->dev, ®ulators[i],234 &config);235 if (IS_ERR(rdev)) {236 dev_err(&pdev->dev, "failed to register regulator %s\n",237 regulators[i].name);238 return PTR_ERR(rdev);239 }240 }241 242 return 0;243}244 245static struct platform_driver sc2731_regulator_driver = {246 .driver = {247 .name = "sc27xx-regulator",248 .probe_type = PROBE_PREFER_ASYNCHRONOUS,249 },250 .probe = sc2731_regulator_probe,251};252 253module_platform_driver(sc2731_regulator_driver);254 255MODULE_AUTHOR("Chen Junhui <erick.chen@spreadtrum.com>");256MODULE_DESCRIPTION("Spreadtrum SC2731 regulator driver");257MODULE_LICENSE("GPL v2");258