1*8b84d712SAlex Elder // SPDX-License-Identifier: GPL-2.0 2*8b84d712SAlex Elder /* 3*8b84d712SAlex Elder * Driver for regulators found in the SpacemiT P1 PMIC 4*8b84d712SAlex Elder * 5*8b84d712SAlex Elder * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved. 6*8b84d712SAlex Elder * Derived from code from SpacemiT. 7*8b84d712SAlex Elder * Copyright (c) 2023, SPACEMIT Co., Ltd 8*8b84d712SAlex Elder */ 9*8b84d712SAlex Elder 10*8b84d712SAlex Elder #include <linux/array_size.h> 11*8b84d712SAlex Elder #include <linux/bits.h> 12*8b84d712SAlex Elder #include <linux/device.h> 13*8b84d712SAlex Elder #include <linux/linear_range.h> 14*8b84d712SAlex Elder #include <linux/module.h> 15*8b84d712SAlex Elder #include <linux/of.h> 16*8b84d712SAlex Elder #include <linux/platform_device.h> 17*8b84d712SAlex Elder #include <linux/regulator/driver.h> 18*8b84d712SAlex Elder 19*8b84d712SAlex Elder #define MOD_NAME "spacemit-p1-regulator" 20*8b84d712SAlex Elder 21*8b84d712SAlex Elder enum p1_regulator_id { 22*8b84d712SAlex Elder P1_BUCK1, 23*8b84d712SAlex Elder P1_BUCK2, 24*8b84d712SAlex Elder P1_BUCK3, 25*8b84d712SAlex Elder P1_BUCK4, 26*8b84d712SAlex Elder P1_BUCK5, 27*8b84d712SAlex Elder P1_BUCK6, 28*8b84d712SAlex Elder 29*8b84d712SAlex Elder P1_ALDO1, 30*8b84d712SAlex Elder P1_ALDO2, 31*8b84d712SAlex Elder P1_ALDO3, 32*8b84d712SAlex Elder P1_ALDO4, 33*8b84d712SAlex Elder 34*8b84d712SAlex Elder P1_DLDO1, 35*8b84d712SAlex Elder P1_DLDO2, 36*8b84d712SAlex Elder P1_DLDO3, 37*8b84d712SAlex Elder P1_DLDO4, 38*8b84d712SAlex Elder P1_DLDO5, 39*8b84d712SAlex Elder P1_DLDO6, 40*8b84d712SAlex Elder P1_DLDO7, 41*8b84d712SAlex Elder }; 42*8b84d712SAlex Elder 43*8b84d712SAlex Elder static const struct regulator_ops p1_regulator_ops = { 44*8b84d712SAlex Elder .list_voltage = regulator_list_voltage_linear_range, 45*8b84d712SAlex Elder .get_voltage_sel = regulator_get_voltage_sel_regmap, 46*8b84d712SAlex Elder .set_voltage_sel = regulator_set_voltage_sel_regmap, 47*8b84d712SAlex Elder .set_voltage_time_sel = regulator_set_voltage_time_sel, 48*8b84d712SAlex Elder .enable = regulator_enable_regmap, 49*8b84d712SAlex Elder .disable = regulator_disable_regmap, 50*8b84d712SAlex Elder .is_enabled = regulator_is_enabled_regmap, 51*8b84d712SAlex Elder }; 52*8b84d712SAlex Elder 53*8b84d712SAlex Elder /* Selector value 255 can be used to disable the buck converter on sleep */ 54*8b84d712SAlex Elder static const struct linear_range p1_buck_ranges[] = { 55*8b84d712SAlex Elder REGULATOR_LINEAR_RANGE(500000, 0, 170, 5000), 56*8b84d712SAlex Elder REGULATOR_LINEAR_RANGE(1375000, 171, 254, 25000), 57*8b84d712SAlex Elder }; 58*8b84d712SAlex Elder 59*8b84d712SAlex Elder /* Selector value 0 can be used for suspend */ 60*8b84d712SAlex Elder static const struct linear_range p1_ldo_ranges[] = { 61*8b84d712SAlex Elder REGULATOR_LINEAR_RANGE(500000, 11, 127, 25000), 62*8b84d712SAlex Elder }; 63*8b84d712SAlex Elder 64*8b84d712SAlex Elder /* These define the voltage selector field for buck and LDO regulators */ 65*8b84d712SAlex Elder #define BUCK_MASK GENMASK(7, 0) 66*8b84d712SAlex Elder #define LDO_MASK GENMASK(6, 0) 67*8b84d712SAlex Elder 68*8b84d712SAlex Elder #define P1_ID(_TYPE, _n) P1_ ## _TYPE ## _n 69*8b84d712SAlex Elder #define P1_ENABLE_REG(_off, _n) ((_off) + 3 * ((_n) - 1)) 70*8b84d712SAlex Elder 71*8b84d712SAlex Elder #define P1_REG_DESC(_TYPE, _type, _n, _s, _off, _mask, _nv, _ranges) \ 72*8b84d712SAlex Elder { \ 73*8b84d712SAlex Elder .name = #_type #_n, \ 74*8b84d712SAlex Elder .supply_name = _s, \ 75*8b84d712SAlex Elder .of_match = of_match_ptr(#_type #_n), \ 76*8b84d712SAlex Elder .regulators_node = of_match_ptr("regulators"), \ 77*8b84d712SAlex Elder .id = P1_ID(_TYPE, _n), \ 78*8b84d712SAlex Elder .n_voltages = _nv, \ 79*8b84d712SAlex Elder .ops = &p1_regulator_ops, \ 80*8b84d712SAlex Elder .owner = THIS_MODULE, \ 81*8b84d712SAlex Elder .linear_ranges = _ranges, \ 82*8b84d712SAlex Elder .n_linear_ranges = ARRAY_SIZE(_ranges), \ 83*8b84d712SAlex Elder .vsel_reg = P1_ENABLE_REG(_off, _n) + 1, \ 84*8b84d712SAlex Elder .vsel_mask = _mask, \ 85*8b84d712SAlex Elder .enable_reg = P1_ENABLE_REG(_off, _n), \ 86*8b84d712SAlex Elder .enable_mask = BIT(0), \ 87*8b84d712SAlex Elder } 88*8b84d712SAlex Elder 89*8b84d712SAlex Elder #define P1_BUCK_DESC(_n) \ 90*8b84d712SAlex Elder P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges) 91*8b84d712SAlex Elder 92*8b84d712SAlex Elder #define P1_ALDO_DESC(_n) \ 93*8b84d712SAlex Elder P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges) 94*8b84d712SAlex Elder 95*8b84d712SAlex Elder #define P1_DLDO_DESC(_n) \ 96*8b84d712SAlex Elder P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges) 97*8b84d712SAlex Elder 98*8b84d712SAlex Elder static const struct regulator_desc p1_regulator_desc[] = { 99*8b84d712SAlex Elder P1_BUCK_DESC(1), 100*8b84d712SAlex Elder P1_BUCK_DESC(2), 101*8b84d712SAlex Elder P1_BUCK_DESC(3), 102*8b84d712SAlex Elder P1_BUCK_DESC(4), 103*8b84d712SAlex Elder P1_BUCK_DESC(5), 104*8b84d712SAlex Elder P1_BUCK_DESC(6), 105*8b84d712SAlex Elder 106*8b84d712SAlex Elder P1_ALDO_DESC(1), 107*8b84d712SAlex Elder P1_ALDO_DESC(2), 108*8b84d712SAlex Elder P1_ALDO_DESC(3), 109*8b84d712SAlex Elder P1_ALDO_DESC(4), 110*8b84d712SAlex Elder 111*8b84d712SAlex Elder P1_DLDO_DESC(1), 112*8b84d712SAlex Elder P1_DLDO_DESC(2), 113*8b84d712SAlex Elder P1_DLDO_DESC(3), 114*8b84d712SAlex Elder P1_DLDO_DESC(4), 115*8b84d712SAlex Elder P1_DLDO_DESC(5), 116*8b84d712SAlex Elder P1_DLDO_DESC(6), 117*8b84d712SAlex Elder P1_DLDO_DESC(7), 118*8b84d712SAlex Elder }; 119*8b84d712SAlex Elder 120*8b84d712SAlex Elder static int p1_regulator_probe(struct platform_device *pdev) 121*8b84d712SAlex Elder { 122*8b84d712SAlex Elder struct regulator_config config = { }; 123*8b84d712SAlex Elder struct device *dev = &pdev->dev; 124*8b84d712SAlex Elder u32 i; 125*8b84d712SAlex Elder 126*8b84d712SAlex Elder /* 127*8b84d712SAlex Elder * The parent device (PMIC) owns the regmap. Since we don't 128*8b84d712SAlex Elder * provide one in the config structure, that one will be used. 129*8b84d712SAlex Elder */ 130*8b84d712SAlex Elder config.dev = dev->parent; 131*8b84d712SAlex Elder 132*8b84d712SAlex Elder for (i = 0; i < ARRAY_SIZE(p1_regulator_desc); i++) { 133*8b84d712SAlex Elder const struct regulator_desc *desc = &p1_regulator_desc[i]; 134*8b84d712SAlex Elder struct regulator_dev *rdev; 135*8b84d712SAlex Elder 136*8b84d712SAlex Elder rdev = devm_regulator_register(dev, desc, &config); 137*8b84d712SAlex Elder if (IS_ERR(rdev)) 138*8b84d712SAlex Elder return dev_err_probe(dev, PTR_ERR(rdev), 139*8b84d712SAlex Elder "error registering regulator %s\n", 140*8b84d712SAlex Elder desc->name); 141*8b84d712SAlex Elder } 142*8b84d712SAlex Elder 143*8b84d712SAlex Elder return 0; 144*8b84d712SAlex Elder } 145*8b84d712SAlex Elder 146*8b84d712SAlex Elder static struct platform_driver p1_regulator_driver = { 147*8b84d712SAlex Elder .probe = p1_regulator_probe, 148*8b84d712SAlex Elder .driver = { 149*8b84d712SAlex Elder .name = MOD_NAME, 150*8b84d712SAlex Elder }, 151*8b84d712SAlex Elder }; 152*8b84d712SAlex Elder 153*8b84d712SAlex Elder module_platform_driver(p1_regulator_driver); 154*8b84d712SAlex Elder 155*8b84d712SAlex Elder MODULE_DESCRIPTION("SpacemiT P1 regulator driver"); 156*8b84d712SAlex Elder MODULE_LICENSE("GPL"); 157*8b84d712SAlex Elder MODULE_ALIAS("platform:" MOD_NAME); 158