18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Device driver for regulators in Hi655x IC 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2016 Hisilicon. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Authors: 88c2ecf20Sopenharmony_ci// Chen Feng <puck.chen@hisilicon.com> 98c2ecf20Sopenharmony_ci// Fei Wang <w.f@huawei.com> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 218c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/hi655x-pmic.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct hi655x_regulator { 258c2ecf20Sopenharmony_ci unsigned int disable_reg; 268c2ecf20Sopenharmony_ci unsigned int status_reg; 278c2ecf20Sopenharmony_ci struct regulator_desc rdesc; 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* LDO7 & LDO10 */ 318c2ecf20Sopenharmony_cistatic const unsigned int ldo7_voltages[] = { 328c2ecf20Sopenharmony_ci 1800000, 1850000, 2850000, 2900000, 338c2ecf20Sopenharmony_ci 3000000, 3100000, 3200000, 3300000, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic const unsigned int ldo19_voltages[] = { 378c2ecf20Sopenharmony_ci 1800000, 1850000, 1900000, 1750000, 388c2ecf20Sopenharmony_ci 2800000, 2850000, 2900000, 3000000, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const unsigned int ldo22_voltages[] = { 428c2ecf20Sopenharmony_ci 900000, 1000000, 1050000, 1100000, 438c2ecf20Sopenharmony_ci 1150000, 1175000, 1185000, 1200000, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cienum hi655x_regulator_id { 478c2ecf20Sopenharmony_ci HI655X_LDO0, 488c2ecf20Sopenharmony_ci HI655X_LDO1, 498c2ecf20Sopenharmony_ci HI655X_LDO2, 508c2ecf20Sopenharmony_ci HI655X_LDO3, 518c2ecf20Sopenharmony_ci HI655X_LDO4, 528c2ecf20Sopenharmony_ci HI655X_LDO5, 538c2ecf20Sopenharmony_ci HI655X_LDO6, 548c2ecf20Sopenharmony_ci HI655X_LDO7, 558c2ecf20Sopenharmony_ci HI655X_LDO8, 568c2ecf20Sopenharmony_ci HI655X_LDO9, 578c2ecf20Sopenharmony_ci HI655X_LDO10, 588c2ecf20Sopenharmony_ci HI655X_LDO11, 598c2ecf20Sopenharmony_ci HI655X_LDO12, 608c2ecf20Sopenharmony_ci HI655X_LDO13, 618c2ecf20Sopenharmony_ci HI655X_LDO14, 628c2ecf20Sopenharmony_ci HI655X_LDO15, 638c2ecf20Sopenharmony_ci HI655X_LDO16, 648c2ecf20Sopenharmony_ci HI655X_LDO17, 658c2ecf20Sopenharmony_ci HI655X_LDO18, 668c2ecf20Sopenharmony_ci HI655X_LDO19, 678c2ecf20Sopenharmony_ci HI655X_LDO20, 688c2ecf20Sopenharmony_ci HI655X_LDO21, 698c2ecf20Sopenharmony_ci HI655X_LDO22, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int hi655x_is_enabled(struct regulator_dev *rdev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci unsigned int value = 0; 758c2ecf20Sopenharmony_ci const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci regmap_read(rdev->regmap, regulator->status_reg, &value); 788c2ecf20Sopenharmony_ci return (value & rdev->desc->enable_mask); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int hi655x_disable(struct regulator_dev *rdev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return regmap_write(rdev->regmap, regulator->disable_reg, 868c2ecf20Sopenharmony_ci rdev->desc->enable_mask); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct regulator_ops hi655x_regulator_ops = { 908c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 918c2ecf20Sopenharmony_ci .disable = hi655x_disable, 928c2ecf20Sopenharmony_ci .is_enabled = hi655x_is_enabled, 938c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 948c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 958c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct regulator_ops hi655x_ldo_linear_ops = { 998c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 1008c2ecf20Sopenharmony_ci .disable = hi655x_disable, 1018c2ecf20Sopenharmony_ci .is_enabled = hi655x_is_enabled, 1028c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 1038c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 1048c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \ 1088c2ecf20Sopenharmony_ci sreg, cmask, vtable) { \ 1098c2ecf20Sopenharmony_ci .rdesc = { \ 1108c2ecf20Sopenharmony_ci .name = #_ID, \ 1118c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_ID), \ 1128c2ecf20Sopenharmony_ci .ops = &hi655x_regulator_ops, \ 1138c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 1148c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 1158c2ecf20Sopenharmony_ci .id = HI655X_##_ID, \ 1168c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 1178c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(vtable), \ 1188c2ecf20Sopenharmony_ci .volt_table = vtable, \ 1198c2ecf20Sopenharmony_ci .vsel_reg = HI655X_BUS_ADDR(vreg), \ 1208c2ecf20Sopenharmony_ci .vsel_mask = vmask, \ 1218c2ecf20Sopenharmony_ci .enable_reg = HI655X_BUS_ADDR(ereg), \ 1228c2ecf20Sopenharmony_ci .enable_mask = BIT(cmask), \ 1238c2ecf20Sopenharmony_ci }, \ 1248c2ecf20Sopenharmony_ci .disable_reg = HI655X_BUS_ADDR(dreg), \ 1258c2ecf20Sopenharmony_ci .status_reg = HI655X_BUS_ADDR(sreg), \ 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \ 1298c2ecf20Sopenharmony_ci sreg, cmask, minv, nvolt, vstep) { \ 1308c2ecf20Sopenharmony_ci .rdesc = { \ 1318c2ecf20Sopenharmony_ci .name = #_ID, \ 1328c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_ID), \ 1338c2ecf20Sopenharmony_ci .ops = &hi655x_ldo_linear_ops, \ 1348c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 1358c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 1368c2ecf20Sopenharmony_ci .id = HI655X_##_ID, \ 1378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 1388c2ecf20Sopenharmony_ci .min_uV = minv, \ 1398c2ecf20Sopenharmony_ci .n_voltages = nvolt, \ 1408c2ecf20Sopenharmony_ci .uV_step = vstep, \ 1418c2ecf20Sopenharmony_ci .vsel_reg = HI655X_BUS_ADDR(vreg), \ 1428c2ecf20Sopenharmony_ci .vsel_mask = vmask, \ 1438c2ecf20Sopenharmony_ci .enable_reg = HI655X_BUS_ADDR(ereg), \ 1448c2ecf20Sopenharmony_ci .enable_mask = BIT(cmask), \ 1458c2ecf20Sopenharmony_ci }, \ 1468c2ecf20Sopenharmony_ci .disable_reg = HI655X_BUS_ADDR(dreg), \ 1478c2ecf20Sopenharmony_ci .status_reg = HI655X_BUS_ADDR(sreg), \ 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct hi655x_regulator regulators[] = { 1518c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01, 1528c2ecf20Sopenharmony_ci 2500000, 8, 100000), 1538c2ecf20Sopenharmony_ci HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages), 1548c2ecf20Sopenharmony_ci HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages), 1558c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04, 1568c2ecf20Sopenharmony_ci 1600000, 8, 50000), 1578c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05, 1588c2ecf20Sopenharmony_ci 2500000, 8, 100000), 1598c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06, 1608c2ecf20Sopenharmony_ci 1600000, 8, 50000), 1618c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00, 1628c2ecf20Sopenharmony_ci 2500000, 8, 100000), 1638c2ecf20Sopenharmony_ci HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages), 1648c2ecf20Sopenharmony_ci HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04, 1658c2ecf20Sopenharmony_ci 1650000, 8, 50000), 1668c2ecf20Sopenharmony_ci HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages), 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int hi655x_regulator_probe(struct platform_device *pdev) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned int i; 1728c2ecf20Sopenharmony_ci struct hi655x_pmic *pmic; 1738c2ecf20Sopenharmony_ci struct regulator_config config = { }; 1748c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci pmic = dev_get_drvdata(pdev->dev.parent); 1778c2ecf20Sopenharmony_ci if (!pmic) { 1788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no pmic in the regulator parent node\n"); 1798c2ecf20Sopenharmony_ci return -ENODEV; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci config.dev = pdev->dev.parent; 1838c2ecf20Sopenharmony_ci config.regmap = pmic->regmap; 1848c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulators); i++) { 1858c2ecf20Sopenharmony_ci config.driver_data = (void *) ®ulators[i]; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, 1888c2ecf20Sopenharmony_ci ®ulators[i].rdesc, 1898c2ecf20Sopenharmony_ci &config); 1908c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 1918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 1928c2ecf20Sopenharmony_ci regulators[i].rdesc.name); 1938c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci return 0; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const struct platform_device_id hi655x_regulator_table[] = { 2008c2ecf20Sopenharmony_ci { .name = "hi655x-regulator" }, 2018c2ecf20Sopenharmony_ci {}, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, hi655x_regulator_table); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic struct platform_driver hi655x_regulator_driver = { 2068c2ecf20Sopenharmony_ci .id_table = hi655x_regulator_table, 2078c2ecf20Sopenharmony_ci .driver = { 2088c2ecf20Sopenharmony_ci .name = "hi655x-regulator", 2098c2ecf20Sopenharmony_ci }, 2108c2ecf20Sopenharmony_ci .probe = hi655x_regulator_probe, 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_cimodule_platform_driver(hi655x_regulator_driver); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>"); 2158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon Hi655x regulator driver"); 2168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 217