18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Regulator driver for National Semiconductors LP3972 PMIC chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Based on lp3971.c 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bug.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 148c2ecf20Sopenharmony_ci#include <linux/regulator/lp3972.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct lp3972 { 188c2ecf20Sopenharmony_ci struct device *dev; 198c2ecf20Sopenharmony_ci struct mutex io_lock; 208c2ecf20Sopenharmony_ci struct i2c_client *i2c; 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* LP3972 Control Registers */ 248c2ecf20Sopenharmony_ci#define LP3972_SCR_REG 0x07 258c2ecf20Sopenharmony_ci#define LP3972_OVER1_REG 0x10 268c2ecf20Sopenharmony_ci#define LP3972_OVSR1_REG 0x11 278c2ecf20Sopenharmony_ci#define LP3972_OVER2_REG 0x12 288c2ecf20Sopenharmony_ci#define LP3972_OVSR2_REG 0x13 298c2ecf20Sopenharmony_ci#define LP3972_VCC1_REG 0x20 308c2ecf20Sopenharmony_ci#define LP3972_ADTV1_REG 0x23 318c2ecf20Sopenharmony_ci#define LP3972_ADTV2_REG 0x24 328c2ecf20Sopenharmony_ci#define LP3972_AVRC_REG 0x25 338c2ecf20Sopenharmony_ci#define LP3972_CDTC1_REG 0x26 348c2ecf20Sopenharmony_ci#define LP3972_CDTC2_REG 0x27 358c2ecf20Sopenharmony_ci#define LP3972_SDTV1_REG 0x29 368c2ecf20Sopenharmony_ci#define LP3972_SDTV2_REG 0x2A 378c2ecf20Sopenharmony_ci#define LP3972_MDTV1_REG 0x32 388c2ecf20Sopenharmony_ci#define LP3972_MDTV2_REG 0x33 398c2ecf20Sopenharmony_ci#define LP3972_L2VCR_REG 0x39 408c2ecf20Sopenharmony_ci#define LP3972_L34VCR_REG 0x3A 418c2ecf20Sopenharmony_ci#define LP3972_SCR1_REG 0x80 428c2ecf20Sopenharmony_ci#define LP3972_SCR2_REG 0x81 438c2ecf20Sopenharmony_ci#define LP3972_OEN3_REG 0x82 448c2ecf20Sopenharmony_ci#define LP3972_OSR3_REG 0x83 458c2ecf20Sopenharmony_ci#define LP3972_LOER4_REG 0x84 468c2ecf20Sopenharmony_ci#define LP3972_B2TV_REG 0x85 478c2ecf20Sopenharmony_ci#define LP3972_B3TV_REG 0x86 488c2ecf20Sopenharmony_ci#define LP3972_B32RC_REG 0x87 498c2ecf20Sopenharmony_ci#define LP3972_ISRA_REG 0x88 508c2ecf20Sopenharmony_ci#define LP3972_BCCR_REG 0x89 518c2ecf20Sopenharmony_ci#define LP3972_II1RR_REG 0x8E 528c2ecf20Sopenharmony_ci#define LP3972_II2RR_REG 0x8F 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define LP3972_SYS_CONTROL1_REG LP3972_SCR1_REG 558c2ecf20Sopenharmony_ci/* System control register 1 initial value, 568c2ecf20Sopenharmony_ci * bits 5, 6 and 7 are EPROM programmable */ 578c2ecf20Sopenharmony_ci#define SYS_CONTROL1_INIT_VAL 0x02 588c2ecf20Sopenharmony_ci#define SYS_CONTROL1_INIT_MASK 0x1F 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_REG LP3972_VCC1_REG 618c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_FLAG_GO 0x01 628c2ecf20Sopenharmony_ci#define LP3972_VOL_CHANGE_FLAG_MASK 0x03 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* LDO output enable mask */ 658c2ecf20Sopenharmony_ci#define LP3972_OEN3_L1EN BIT(0) 668c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO2_EN BIT(2) 678c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO3_EN BIT(3) 688c2ecf20Sopenharmony_ci#define LP3972_OVER2_LDO4_EN BIT(4) 698c2ecf20Sopenharmony_ci#define LP3972_OVER1_S_EN BIT(2) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic const unsigned int ldo1_voltage_map[] = { 728c2ecf20Sopenharmony_ci 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, 738c2ecf20Sopenharmony_ci 1900000, 1925000, 1950000, 1975000, 2000000, 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic const unsigned int ldo23_voltage_map[] = { 778c2ecf20Sopenharmony_ci 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 788c2ecf20Sopenharmony_ci 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const unsigned int ldo4_voltage_map[] = { 828c2ecf20Sopenharmony_ci 1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 838c2ecf20Sopenharmony_ci 1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const unsigned int ldo5_voltage_map[] = { 878c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 850000, 875000, 900000, 888c2ecf20Sopenharmony_ci 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 898c2ecf20Sopenharmony_ci 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 908c2ecf20Sopenharmony_ci 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic const unsigned int buck1_voltage_map[] = { 948c2ecf20Sopenharmony_ci 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000, 958c2ecf20Sopenharmony_ci 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000, 968c2ecf20Sopenharmony_ci 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000, 978c2ecf20Sopenharmony_ci 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const unsigned int buck23_voltage_map[] = { 1018c2ecf20Sopenharmony_ci 0, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1028c2ecf20Sopenharmony_ci 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1038c2ecf20Sopenharmony_ci 1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000, 1048c2ecf20Sopenharmony_ci 3000000, 3300000, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic const int ldo_output_enable_mask[] = { 1088c2ecf20Sopenharmony_ci LP3972_OEN3_L1EN, 1098c2ecf20Sopenharmony_ci LP3972_OVER2_LDO2_EN, 1108c2ecf20Sopenharmony_ci LP3972_OVER2_LDO3_EN, 1118c2ecf20Sopenharmony_ci LP3972_OVER2_LDO4_EN, 1128c2ecf20Sopenharmony_ci LP3972_OVER1_S_EN, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic const int ldo_output_enable_addr[] = { 1168c2ecf20Sopenharmony_ci LP3972_OEN3_REG, 1178c2ecf20Sopenharmony_ci LP3972_OVER2_REG, 1188c2ecf20Sopenharmony_ci LP3972_OVER2_REG, 1198c2ecf20Sopenharmony_ci LP3972_OVER2_REG, 1208c2ecf20Sopenharmony_ci LP3972_OVER1_REG, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const int ldo_vol_ctl_addr[] = { 1248c2ecf20Sopenharmony_ci LP3972_MDTV1_REG, 1258c2ecf20Sopenharmony_ci LP3972_L2VCR_REG, 1268c2ecf20Sopenharmony_ci LP3972_L34VCR_REG, 1278c2ecf20Sopenharmony_ci LP3972_L34VCR_REG, 1288c2ecf20Sopenharmony_ci LP3972_SDTV1_REG, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic const int buck_vol_enable_addr[] = { 1328c2ecf20Sopenharmony_ci LP3972_OVER1_REG, 1338c2ecf20Sopenharmony_ci LP3972_OEN3_REG, 1348c2ecf20Sopenharmony_ci LP3972_OEN3_REG, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const int buck_base_addr[] = { 1388c2ecf20Sopenharmony_ci LP3972_ADTV1_REG, 1398c2ecf20Sopenharmony_ci LP3972_B2TV_REG, 1408c2ecf20Sopenharmony_ci LP3972_B3TV_REG, 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x]) 1448c2ecf20Sopenharmony_ci#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x]) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* LDO voltage control registers shift: 1478c2ecf20Sopenharmony_ci LP3972_LDO1 -> 0, LP3972_LDO2 -> 4 1488c2ecf20Sopenharmony_ci LP3972_LDO3 -> 0, LP3972_LDO4 -> 4 1498c2ecf20Sopenharmony_ci LP3972_LDO5 -> 0 1508c2ecf20Sopenharmony_ci*/ 1518c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2) 1528c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x]) 1538c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f) 1568c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00) 1578c2ecf20Sopenharmony_ci#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) 1608c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) 1618c2ecf20Sopenharmony_ci#define LP3972_BUCK_VOL_MASK 0x1f 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, 1648c2ecf20Sopenharmony_ci u16 *dest) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int ret; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (count != 1) 1698c2ecf20Sopenharmony_ci return -EIO; 1708c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(i2c, reg); 1718c2ecf20Sopenharmony_ci if (ret < 0) 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci *dest = ret; 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count, 1798c2ecf20Sopenharmony_ci const u16 *src) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (count != 1) 1828c2ecf20Sopenharmony_ci return -EIO; 1838c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(i2c, reg, *src); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u16 val = 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci mutex_lock(&lp3972->io_lock); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci lp3972_i2c_read(lp3972->i2c, reg, 1, &val); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, 1958c2ecf20Sopenharmony_ci (unsigned)val & 0xff); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci mutex_unlock(&lp3972->io_lock); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return val & 0xff; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u16 tmp; 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci mutex_lock(&lp3972->io_lock); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp); 2108c2ecf20Sopenharmony_ci if (ret == 0) { 2118c2ecf20Sopenharmony_ci tmp = (tmp & ~mask) | val; 2128c2ecf20Sopenharmony_ci ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp); 2138c2ecf20Sopenharmony_ci dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, 2148c2ecf20Sopenharmony_ci (unsigned)val & 0xff); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci mutex_unlock(&lp3972->io_lock); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int lp3972_ldo_is_enabled(struct regulator_dev *dev) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2248c2ecf20Sopenharmony_ci int ldo = rdev_get_id(dev) - LP3972_LDO1; 2258c2ecf20Sopenharmony_ci u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2268c2ecf20Sopenharmony_ci u16 val; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo)); 2298c2ecf20Sopenharmony_ci return !!(val & mask); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int lp3972_ldo_enable(struct regulator_dev *dev) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2358c2ecf20Sopenharmony_ci int ldo = rdev_get_id(dev) - LP3972_LDO1; 2368c2ecf20Sopenharmony_ci u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), 2398c2ecf20Sopenharmony_ci mask, mask); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int lp3972_ldo_disable(struct regulator_dev *dev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2458c2ecf20Sopenharmony_ci int ldo = rdev_get_id(dev) - LP3972_LDO1; 2468c2ecf20Sopenharmony_ci u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), 2498c2ecf20Sopenharmony_ci mask, 0); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2558c2ecf20Sopenharmony_ci int ldo = rdev_get_id(dev) - LP3972_LDO1; 2568c2ecf20Sopenharmony_ci u16 mask = LP3972_LDO_VOL_MASK(ldo); 2578c2ecf20Sopenharmony_ci u16 val, reg; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); 2608c2ecf20Sopenharmony_ci val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return val; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, 2668c2ecf20Sopenharmony_ci unsigned int selector) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 2698c2ecf20Sopenharmony_ci int ldo = rdev_get_id(dev) - LP3972_LDO1; 2708c2ecf20Sopenharmony_ci int shift, ret; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); 2738c2ecf20Sopenharmony_ci ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), 2748c2ecf20Sopenharmony_ci LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (ret) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * LDO1 and LDO5 support voltage control by either target voltage1 2818c2ecf20Sopenharmony_ci * or target voltage2 register. 2828c2ecf20Sopenharmony_ci * We use target voltage1 register for LDO1 and LDO5 in this driver. 2838c2ecf20Sopenharmony_ci * We need to update voltage change control register(0x20) to enable 2848c2ecf20Sopenharmony_ci * LDO1 and LDO5 to change to their programmed target values. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci switch (ldo) { 2878c2ecf20Sopenharmony_ci case LP3972_LDO1: 2888c2ecf20Sopenharmony_ci case LP3972_LDO5: 2898c2ecf20Sopenharmony_ci shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo); 2908c2ecf20Sopenharmony_ci ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 2918c2ecf20Sopenharmony_ci LP3972_VOL_CHANGE_FLAG_MASK << shift, 2928c2ecf20Sopenharmony_ci LP3972_VOL_CHANGE_FLAG_GO << shift); 2938c2ecf20Sopenharmony_ci if (ret) 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 2978c2ecf20Sopenharmony_ci LP3972_VOL_CHANGE_FLAG_MASK << shift, 0); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic const struct regulator_ops lp3972_ldo_ops = { 3058c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 3068c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 3078c2ecf20Sopenharmony_ci .is_enabled = lp3972_ldo_is_enabled, 3088c2ecf20Sopenharmony_ci .enable = lp3972_ldo_enable, 3098c2ecf20Sopenharmony_ci .disable = lp3972_ldo_disable, 3108c2ecf20Sopenharmony_ci .get_voltage_sel = lp3972_ldo_get_voltage_sel, 3118c2ecf20Sopenharmony_ci .set_voltage_sel = lp3972_ldo_set_voltage_sel, 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int lp3972_dcdc_is_enabled(struct regulator_dev *dev) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3178c2ecf20Sopenharmony_ci int buck = rdev_get_id(dev) - LP3972_DCDC1; 3188c2ecf20Sopenharmony_ci u16 mask = 1 << (buck * 2); 3198c2ecf20Sopenharmony_ci u16 val; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck)); 3228c2ecf20Sopenharmony_ci return !!(val & mask); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int lp3972_dcdc_enable(struct regulator_dev *dev) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3288c2ecf20Sopenharmony_ci int buck = rdev_get_id(dev) - LP3972_DCDC1; 3298c2ecf20Sopenharmony_ci u16 mask = 1 << (buck * 2); 3308c2ecf20Sopenharmony_ci u16 val; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), 3338c2ecf20Sopenharmony_ci mask, mask); 3348c2ecf20Sopenharmony_ci return val; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int lp3972_dcdc_disable(struct regulator_dev *dev) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3408c2ecf20Sopenharmony_ci int buck = rdev_get_id(dev) - LP3972_DCDC1; 3418c2ecf20Sopenharmony_ci u16 mask = 1 << (buck * 2); 3428c2ecf20Sopenharmony_ci u16 val; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), 3458c2ecf20Sopenharmony_ci mask, 0); 3468c2ecf20Sopenharmony_ci return val; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3528c2ecf20Sopenharmony_ci int buck = rdev_get_id(dev) - LP3972_DCDC1; 3538c2ecf20Sopenharmony_ci u16 reg; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); 3568c2ecf20Sopenharmony_ci reg &= LP3972_BUCK_VOL_MASK; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return reg; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, 3628c2ecf20Sopenharmony_ci unsigned int selector) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct lp3972 *lp3972 = rdev_get_drvdata(dev); 3658c2ecf20Sopenharmony_ci int buck = rdev_get_id(dev) - LP3972_DCDC1; 3668c2ecf20Sopenharmony_ci int ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), 3698c2ecf20Sopenharmony_ci LP3972_BUCK_VOL_MASK, selector); 3708c2ecf20Sopenharmony_ci if (ret) 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (buck != 0) 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 3778c2ecf20Sopenharmony_ci LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO); 3788c2ecf20Sopenharmony_ci if (ret) 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, 3828c2ecf20Sopenharmony_ci LP3972_VOL_CHANGE_FLAG_MASK, 0); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic const struct regulator_ops lp3972_dcdc_ops = { 3868c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 3878c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 3888c2ecf20Sopenharmony_ci .is_enabled = lp3972_dcdc_is_enabled, 3898c2ecf20Sopenharmony_ci .enable = lp3972_dcdc_enable, 3908c2ecf20Sopenharmony_ci .disable = lp3972_dcdc_disable, 3918c2ecf20Sopenharmony_ci .get_voltage_sel = lp3972_dcdc_get_voltage_sel, 3928c2ecf20Sopenharmony_ci .set_voltage_sel = lp3972_dcdc_set_voltage_sel, 3938c2ecf20Sopenharmony_ci}; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic const struct regulator_desc regulators[] = { 3968c2ecf20Sopenharmony_ci { 3978c2ecf20Sopenharmony_ci .name = "LDO1", 3988c2ecf20Sopenharmony_ci .id = LP3972_LDO1, 3998c2ecf20Sopenharmony_ci .ops = &lp3972_ldo_ops, 4008c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ldo1_voltage_map), 4018c2ecf20Sopenharmony_ci .volt_table = ldo1_voltage_map, 4028c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4038c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4048c2ecf20Sopenharmony_ci }, 4058c2ecf20Sopenharmony_ci { 4068c2ecf20Sopenharmony_ci .name = "LDO2", 4078c2ecf20Sopenharmony_ci .id = LP3972_LDO2, 4088c2ecf20Sopenharmony_ci .ops = &lp3972_ldo_ops, 4098c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ldo23_voltage_map), 4108c2ecf20Sopenharmony_ci .volt_table = ldo23_voltage_map, 4118c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4128c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci { 4158c2ecf20Sopenharmony_ci .name = "LDO3", 4168c2ecf20Sopenharmony_ci .id = LP3972_LDO3, 4178c2ecf20Sopenharmony_ci .ops = &lp3972_ldo_ops, 4188c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ldo23_voltage_map), 4198c2ecf20Sopenharmony_ci .volt_table = ldo23_voltage_map, 4208c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4218c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4228c2ecf20Sopenharmony_ci }, 4238c2ecf20Sopenharmony_ci { 4248c2ecf20Sopenharmony_ci .name = "LDO4", 4258c2ecf20Sopenharmony_ci .id = LP3972_LDO4, 4268c2ecf20Sopenharmony_ci .ops = &lp3972_ldo_ops, 4278c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ldo4_voltage_map), 4288c2ecf20Sopenharmony_ci .volt_table = ldo4_voltage_map, 4298c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4308c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4318c2ecf20Sopenharmony_ci }, 4328c2ecf20Sopenharmony_ci { 4338c2ecf20Sopenharmony_ci .name = "LDO5", 4348c2ecf20Sopenharmony_ci .id = LP3972_LDO5, 4358c2ecf20Sopenharmony_ci .ops = &lp3972_ldo_ops, 4368c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(ldo5_voltage_map), 4378c2ecf20Sopenharmony_ci .volt_table = ldo5_voltage_map, 4388c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4398c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4408c2ecf20Sopenharmony_ci }, 4418c2ecf20Sopenharmony_ci { 4428c2ecf20Sopenharmony_ci .name = "DCDC1", 4438c2ecf20Sopenharmony_ci .id = LP3972_DCDC1, 4448c2ecf20Sopenharmony_ci .ops = &lp3972_dcdc_ops, 4458c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(buck1_voltage_map), 4468c2ecf20Sopenharmony_ci .volt_table = buck1_voltage_map, 4478c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4488c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4498c2ecf20Sopenharmony_ci }, 4508c2ecf20Sopenharmony_ci { 4518c2ecf20Sopenharmony_ci .name = "DCDC2", 4528c2ecf20Sopenharmony_ci .id = LP3972_DCDC2, 4538c2ecf20Sopenharmony_ci .ops = &lp3972_dcdc_ops, 4548c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(buck23_voltage_map), 4558c2ecf20Sopenharmony_ci .volt_table = buck23_voltage_map, 4568c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4588c2ecf20Sopenharmony_ci }, 4598c2ecf20Sopenharmony_ci { 4608c2ecf20Sopenharmony_ci .name = "DCDC3", 4618c2ecf20Sopenharmony_ci .id = LP3972_DCDC3, 4628c2ecf20Sopenharmony_ci .ops = &lp3972_dcdc_ops, 4638c2ecf20Sopenharmony_ci .n_voltages = ARRAY_SIZE(buck23_voltage_map), 4648c2ecf20Sopenharmony_ci .volt_table = buck23_voltage_map, 4658c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, 4668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4678c2ecf20Sopenharmony_ci }, 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int setup_regulators(struct lp3972 *lp3972, 4718c2ecf20Sopenharmony_ci struct lp3972_platform_data *pdata) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci int i, err; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Instantiate the regulators */ 4768c2ecf20Sopenharmony_ci for (i = 0; i < pdata->num_regulators; i++) { 4778c2ecf20Sopenharmony_ci struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; 4788c2ecf20Sopenharmony_ci struct regulator_config config = { }; 4798c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci config.dev = lp3972->dev; 4828c2ecf20Sopenharmony_ci config.init_data = reg->initdata; 4838c2ecf20Sopenharmony_ci config.driver_data = lp3972; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci rdev = devm_regulator_register(lp3972->dev, 4868c2ecf20Sopenharmony_ci ®ulators[reg->id], &config); 4878c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 4888c2ecf20Sopenharmony_ci err = PTR_ERR(rdev); 4898c2ecf20Sopenharmony_ci dev_err(lp3972->dev, "regulator init failed: %d\n", 4908c2ecf20Sopenharmony_ci err); 4918c2ecf20Sopenharmony_ci return err; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int lp3972_i2c_probe(struct i2c_client *i2c, 4998c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct lp3972 *lp3972; 5028c2ecf20Sopenharmony_ci struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev); 5038c2ecf20Sopenharmony_ci int ret; 5048c2ecf20Sopenharmony_ci u16 val; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (!pdata) { 5078c2ecf20Sopenharmony_ci dev_dbg(&i2c->dev, "No platform init data supplied\n"); 5088c2ecf20Sopenharmony_ci return -ENODEV; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci lp3972 = devm_kzalloc(&i2c->dev, sizeof(struct lp3972), GFP_KERNEL); 5128c2ecf20Sopenharmony_ci if (!lp3972) 5138c2ecf20Sopenharmony_ci return -ENOMEM; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci lp3972->i2c = i2c; 5168c2ecf20Sopenharmony_ci lp3972->dev = &i2c->dev; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci mutex_init(&lp3972->io_lock); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Detect LP3972 */ 5218c2ecf20Sopenharmony_ci ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val); 5228c2ecf20Sopenharmony_ci if (ret == 0 && 5238c2ecf20Sopenharmony_ci (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) { 5248c2ecf20Sopenharmony_ci ret = -ENODEV; 5258c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci if (ret < 0) { 5288c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret); 5298c2ecf20Sopenharmony_ci return ret; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = setup_regulators(lp3972, pdata); 5338c2ecf20Sopenharmony_ci if (ret < 0) 5348c2ecf20Sopenharmony_ci return ret; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, lp3972); 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic const struct i2c_device_id lp3972_i2c_id[] = { 5418c2ecf20Sopenharmony_ci { "lp3972", 0 }, 5428c2ecf20Sopenharmony_ci { } 5438c2ecf20Sopenharmony_ci}; 5448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic struct i2c_driver lp3972_i2c_driver = { 5478c2ecf20Sopenharmony_ci .driver = { 5488c2ecf20Sopenharmony_ci .name = "lp3972", 5498c2ecf20Sopenharmony_ci }, 5508c2ecf20Sopenharmony_ci .probe = lp3972_i2c_probe, 5518c2ecf20Sopenharmony_ci .id_table = lp3972_i2c_id, 5528c2ecf20Sopenharmony_ci}; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int __init lp3972_module_init(void) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci return i2c_add_driver(&lp3972_i2c_driver); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_cisubsys_initcall(lp3972_module_init); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void __exit lp3972_module_exit(void) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci i2c_del_driver(&lp3972_i2c_driver); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_cimodule_exit(lp3972_module_exit); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>"); 5688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LP3972 PMIC driver"); 569