18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * tps6507x-regulator.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Regulator driver for TPS65073 PMIC 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/ 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 108c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, 138c2ecf20Sopenharmony_ci * whether express or implied; without even the implied warranty of 148c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 158c2ecf20Sopenharmony_ci * General Public License for more details. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/err.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 248c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 258c2ecf20Sopenharmony_ci#include <linux/regulator/tps6507x.h> 268c2ecf20Sopenharmony_ci#include <linux/of.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/mfd/tps6507x.h> 298c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* DCDC's */ 328c2ecf20Sopenharmony_ci#define TPS6507X_DCDC_1 0 338c2ecf20Sopenharmony_ci#define TPS6507X_DCDC_2 1 348c2ecf20Sopenharmony_ci#define TPS6507X_DCDC_3 2 358c2ecf20Sopenharmony_ci/* LDOs */ 368c2ecf20Sopenharmony_ci#define TPS6507X_LDO_1 3 378c2ecf20Sopenharmony_ci#define TPS6507X_LDO_2 4 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define TPS6507X_MAX_REG_ID TPS6507X_LDO_2 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Number of step-down converters available */ 428c2ecf20Sopenharmony_ci#define TPS6507X_NUM_DCDC 3 438c2ecf20Sopenharmony_ci/* Number of LDO voltage regulators available */ 448c2ecf20Sopenharmony_ci#define TPS6507X_NUM_LDO 2 458c2ecf20Sopenharmony_ci/* Number of total regulators available */ 468c2ecf20Sopenharmony_ci#define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Supported voltage values for regulators (in microVolts) */ 498c2ecf20Sopenharmony_cistatic const unsigned int VDCDCx_VSEL_table[] = { 508c2ecf20Sopenharmony_ci 725000, 750000, 775000, 800000, 518c2ecf20Sopenharmony_ci 825000, 850000, 875000, 900000, 528c2ecf20Sopenharmony_ci 925000, 950000, 975000, 1000000, 538c2ecf20Sopenharmony_ci 1025000, 1050000, 1075000, 1100000, 548c2ecf20Sopenharmony_ci 1125000, 1150000, 1175000, 1200000, 558c2ecf20Sopenharmony_ci 1225000, 1250000, 1275000, 1300000, 568c2ecf20Sopenharmony_ci 1325000, 1350000, 1375000, 1400000, 578c2ecf20Sopenharmony_ci 1425000, 1450000, 1475000, 1500000, 588c2ecf20Sopenharmony_ci 1550000, 1600000, 1650000, 1700000, 598c2ecf20Sopenharmony_ci 1750000, 1800000, 1850000, 1900000, 608c2ecf20Sopenharmony_ci 1950000, 2000000, 2050000, 2100000, 618c2ecf20Sopenharmony_ci 2150000, 2200000, 2250000, 2300000, 628c2ecf20Sopenharmony_ci 2350000, 2400000, 2450000, 2500000, 638c2ecf20Sopenharmony_ci 2550000, 2600000, 2650000, 2700000, 648c2ecf20Sopenharmony_ci 2750000, 2800000, 2850000, 2900000, 658c2ecf20Sopenharmony_ci 3000000, 3100000, 3200000, 3300000, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const unsigned int LDO1_VSEL_table[] = { 698c2ecf20Sopenharmony_ci 1000000, 1100000, 1200000, 1250000, 708c2ecf20Sopenharmony_ci 1300000, 1350000, 1400000, 1500000, 718c2ecf20Sopenharmony_ci 1600000, 1800000, 2500000, 2750000, 728c2ecf20Sopenharmony_ci 2800000, 3000000, 3100000, 3300000, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* The voltage mapping table for LDO2 is the same as VDCDCx */ 768c2ecf20Sopenharmony_ci#define LDO2_VSEL_table VDCDCx_VSEL_table 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct tps_info { 798c2ecf20Sopenharmony_ci const char *name; 808c2ecf20Sopenharmony_ci u8 table_len; 818c2ecf20Sopenharmony_ci const unsigned int *table; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Does DCDC high or the low register defines output voltage? */ 848c2ecf20Sopenharmony_ci bool defdcdc_default; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct tps_info tps6507x_pmic_regs[] = { 888c2ecf20Sopenharmony_ci { 898c2ecf20Sopenharmony_ci .name = "VDCDC1", 908c2ecf20Sopenharmony_ci .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 918c2ecf20Sopenharmony_ci .table = VDCDCx_VSEL_table, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .name = "VDCDC2", 958c2ecf20Sopenharmony_ci .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 968c2ecf20Sopenharmony_ci .table = VDCDCx_VSEL_table, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci .name = "VDCDC3", 1008c2ecf20Sopenharmony_ci .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), 1018c2ecf20Sopenharmony_ci .table = VDCDCx_VSEL_table, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci { 1048c2ecf20Sopenharmony_ci .name = "LDO1", 1058c2ecf20Sopenharmony_ci .table_len = ARRAY_SIZE(LDO1_VSEL_table), 1068c2ecf20Sopenharmony_ci .table = LDO1_VSEL_table, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci .name = "LDO2", 1108c2ecf20Sopenharmony_ci .table_len = ARRAY_SIZE(LDO2_VSEL_table), 1118c2ecf20Sopenharmony_ci .table = LDO2_VSEL_table, 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistruct tps6507x_pmic { 1168c2ecf20Sopenharmony_ci struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; 1178c2ecf20Sopenharmony_ci struct tps6507x_dev *mfd; 1188c2ecf20Sopenharmony_ci struct tps_info *info[TPS6507X_NUM_REGULATOR]; 1198c2ecf20Sopenharmony_ci struct mutex io_lock; 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_cistatic inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci u8 val; 1248c2ecf20Sopenharmony_ci int err; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci err = tps->mfd->read_dev(tps->mfd, reg, 1, &val); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (err) 1298c2ecf20Sopenharmony_ci return err; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return val; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci return tps->mfd->write_dev(tps->mfd, reg, 1, &val); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int err, data; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci mutex_lock(&tps->io_lock); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci data = tps6507x_pmic_read(tps, reg); 1468c2ecf20Sopenharmony_ci if (data < 0) { 1478c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1488c2ecf20Sopenharmony_ci err = data; 1498c2ecf20Sopenharmony_ci goto out; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci data |= mask; 1538c2ecf20Sopenharmony_ci err = tps6507x_pmic_write(tps, reg, data); 1548c2ecf20Sopenharmony_ci if (err) 1558c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciout: 1588c2ecf20Sopenharmony_ci mutex_unlock(&tps->io_lock); 1598c2ecf20Sopenharmony_ci return err; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci int err, data; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci mutex_lock(&tps->io_lock); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci data = tps6507x_pmic_read(tps, reg); 1698c2ecf20Sopenharmony_ci if (data < 0) { 1708c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1718c2ecf20Sopenharmony_ci err = data; 1728c2ecf20Sopenharmony_ci goto out; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci data &= ~mask; 1768c2ecf20Sopenharmony_ci err = tps6507x_pmic_write(tps, reg, data); 1778c2ecf20Sopenharmony_ci if (err) 1788c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciout: 1818c2ecf20Sopenharmony_ci mutex_unlock(&tps->io_lock); 1828c2ecf20Sopenharmony_ci return err; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int data; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_lock(&tps->io_lock); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci data = tps6507x_pmic_read(tps, reg); 1928c2ecf20Sopenharmony_ci if (data < 0) 1938c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mutex_unlock(&tps->io_lock); 1968c2ecf20Sopenharmony_ci return data; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci int err; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci mutex_lock(&tps->io_lock); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci err = tps6507x_pmic_write(tps, reg, val); 2068c2ecf20Sopenharmony_ci if (err < 0) 2078c2ecf20Sopenharmony_ci dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mutex_unlock(&tps->io_lock); 2108c2ecf20Sopenharmony_ci return err; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic int tps6507x_pmic_is_enabled(struct regulator_dev *dev) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 2168c2ecf20Sopenharmony_ci int data, rid = rdev_get_id(dev); 2178c2ecf20Sopenharmony_ci u8 shift; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci shift = TPS6507X_MAX_REG_ID - rid; 2238c2ecf20Sopenharmony_ci data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (data < 0) 2268c2ecf20Sopenharmony_ci return data; 2278c2ecf20Sopenharmony_ci else 2288c2ecf20Sopenharmony_ci return (data & 1<<shift) ? 1 : 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int tps6507x_pmic_enable(struct regulator_dev *dev) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 2348c2ecf20Sopenharmony_ci int rid = rdev_get_id(dev); 2358c2ecf20Sopenharmony_ci u8 shift; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci shift = TPS6507X_MAX_REG_ID - rid; 2418c2ecf20Sopenharmony_ci return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int tps6507x_pmic_disable(struct regulator_dev *dev) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 2478c2ecf20Sopenharmony_ci int rid = rdev_get_id(dev); 2488c2ecf20Sopenharmony_ci u8 shift; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci shift = TPS6507X_MAX_REG_ID - rid; 2548c2ecf20Sopenharmony_ci return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 2558c2ecf20Sopenharmony_ci 1 << shift); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 2618c2ecf20Sopenharmony_ci int data, rid = rdev_get_id(dev); 2628c2ecf20Sopenharmony_ci u8 reg, mask; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci switch (rid) { 2658c2ecf20Sopenharmony_ci case TPS6507X_DCDC_1: 2668c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC1; 2678c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci case TPS6507X_DCDC_2: 2708c2ecf20Sopenharmony_ci if (tps->info[rid]->defdcdc_default) 2718c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC2_HIGH; 2728c2ecf20Sopenharmony_ci else 2738c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC2_LOW; 2748c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case TPS6507X_DCDC_3: 2778c2ecf20Sopenharmony_ci if (tps->info[rid]->defdcdc_default) 2788c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC3_HIGH; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC3_LOW; 2818c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case TPS6507X_LDO_1: 2848c2ecf20Sopenharmony_ci reg = TPS6507X_REG_LDO_CTRL1; 2858c2ecf20Sopenharmony_ci mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci case TPS6507X_LDO_2: 2888c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFLDO2; 2898c2ecf20Sopenharmony_ci mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci data = tps6507x_pmic_reg_read(tps, reg); 2968c2ecf20Sopenharmony_ci if (data < 0) 2978c2ecf20Sopenharmony_ci return data; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci data &= mask; 3008c2ecf20Sopenharmony_ci return data; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, 3048c2ecf20Sopenharmony_ci unsigned selector) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = rdev_get_drvdata(dev); 3078c2ecf20Sopenharmony_ci int data, rid = rdev_get_id(dev); 3088c2ecf20Sopenharmony_ci u8 reg, mask; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci switch (rid) { 3118c2ecf20Sopenharmony_ci case TPS6507X_DCDC_1: 3128c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC1; 3138c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case TPS6507X_DCDC_2: 3168c2ecf20Sopenharmony_ci if (tps->info[rid]->defdcdc_default) 3178c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC2_HIGH; 3188c2ecf20Sopenharmony_ci else 3198c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC2_LOW; 3208c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case TPS6507X_DCDC_3: 3238c2ecf20Sopenharmony_ci if (tps->info[rid]->defdcdc_default) 3248c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC3_HIGH; 3258c2ecf20Sopenharmony_ci else 3268c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFDCDC3_LOW; 3278c2ecf20Sopenharmony_ci mask = TPS6507X_DEFDCDCX_DCDC_MASK; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case TPS6507X_LDO_1: 3308c2ecf20Sopenharmony_ci reg = TPS6507X_REG_LDO_CTRL1; 3318c2ecf20Sopenharmony_ci mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case TPS6507X_LDO_2: 3348c2ecf20Sopenharmony_ci reg = TPS6507X_REG_DEFLDO2; 3358c2ecf20Sopenharmony_ci mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci default: 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci data = tps6507x_pmic_reg_read(tps, reg); 3428c2ecf20Sopenharmony_ci if (data < 0) 3438c2ecf20Sopenharmony_ci return data; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci data &= ~mask; 3468c2ecf20Sopenharmony_ci data |= selector; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return tps6507x_pmic_reg_write(tps, reg, data); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic const struct regulator_ops tps6507x_pmic_ops = { 3528c2ecf20Sopenharmony_ci .is_enabled = tps6507x_pmic_is_enabled, 3538c2ecf20Sopenharmony_ci .enable = tps6507x_pmic_enable, 3548c2ecf20Sopenharmony_ci .disable = tps6507x_pmic_disable, 3558c2ecf20Sopenharmony_ci .get_voltage_sel = tps6507x_pmic_get_voltage_sel, 3568c2ecf20Sopenharmony_ci .set_voltage_sel = tps6507x_pmic_set_voltage_sel, 3578c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 3588c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int tps6507x_pmic_of_parse_cb(struct device_node *np, 3628c2ecf20Sopenharmony_ci const struct regulator_desc *desc, 3638c2ecf20Sopenharmony_ci struct regulator_config *config) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps = config->driver_data; 3668c2ecf20Sopenharmony_ci struct tps_info *info = tps->info[desc->id]; 3678c2ecf20Sopenharmony_ci u32 prop; 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "ti,defdcdc_default", &prop); 3718c2ecf20Sopenharmony_ci if (!ret) 3728c2ecf20Sopenharmony_ci info->defdcdc_default = prop; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int tps6507x_pmic_probe(struct platform_device *pdev) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 3808c2ecf20Sopenharmony_ci struct tps_info *info = &tps6507x_pmic_regs[0]; 3818c2ecf20Sopenharmony_ci struct regulator_config config = { }; 3828c2ecf20Sopenharmony_ci struct regulator_init_data *init_data = NULL; 3838c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 3848c2ecf20Sopenharmony_ci struct tps6507x_pmic *tps; 3858c2ecf20Sopenharmony_ci struct tps6507x_board *tps_board; 3868c2ecf20Sopenharmony_ci int i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /** 3898c2ecf20Sopenharmony_ci * tps_board points to pmic related constants 3908c2ecf20Sopenharmony_ci * coming from the board-evm file. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci tps_board = dev_get_platdata(tps6507x_dev->dev); 3948c2ecf20Sopenharmony_ci if (tps_board) 3958c2ecf20Sopenharmony_ci init_data = tps_board->tps6507x_pmic_init_data; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL); 3988c2ecf20Sopenharmony_ci if (!tps) 3998c2ecf20Sopenharmony_ci return -ENOMEM; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci mutex_init(&tps->io_lock); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* common for all regulators */ 4048c2ecf20Sopenharmony_ci tps->mfd = tps6507x_dev; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++) { 4078c2ecf20Sopenharmony_ci /* Register the regulators */ 4088c2ecf20Sopenharmony_ci tps->info[i] = info; 4098c2ecf20Sopenharmony_ci if (init_data && init_data[i].driver_data) { 4108c2ecf20Sopenharmony_ci struct tps6507x_reg_platform_data *data = 4118c2ecf20Sopenharmony_ci init_data[i].driver_data; 4128c2ecf20Sopenharmony_ci info->defdcdc_default = data->defdcdc_default; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci tps->desc[i].name = info->name; 4168c2ecf20Sopenharmony_ci tps->desc[i].of_match = of_match_ptr(info->name); 4178c2ecf20Sopenharmony_ci tps->desc[i].regulators_node = of_match_ptr("regulators"); 4188c2ecf20Sopenharmony_ci tps->desc[i].of_parse_cb = tps6507x_pmic_of_parse_cb; 4198c2ecf20Sopenharmony_ci tps->desc[i].id = i; 4208c2ecf20Sopenharmony_ci tps->desc[i].n_voltages = info->table_len; 4218c2ecf20Sopenharmony_ci tps->desc[i].volt_table = info->table; 4228c2ecf20Sopenharmony_ci tps->desc[i].ops = &tps6507x_pmic_ops; 4238c2ecf20Sopenharmony_ci tps->desc[i].type = REGULATOR_VOLTAGE; 4248c2ecf20Sopenharmony_ci tps->desc[i].owner = THIS_MODULE; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci config.dev = tps6507x_dev->dev; 4278c2ecf20Sopenharmony_ci config.init_data = init_data; 4288c2ecf20Sopenharmony_ci config.driver_data = tps; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, &tps->desc[i], 4318c2ecf20Sopenharmony_ci &config); 4328c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 4338c2ecf20Sopenharmony_ci dev_err(tps6507x_dev->dev, 4348c2ecf20Sopenharmony_ci "failed to register %s regulator\n", 4358c2ecf20Sopenharmony_ci pdev->name); 4368c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci tps6507x_dev->pmic = tps; 4418c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, tps6507x_dev); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic struct platform_driver tps6507x_pmic_driver = { 4478c2ecf20Sopenharmony_ci .driver = { 4488c2ecf20Sopenharmony_ci .name = "tps6507x-pmic", 4498c2ecf20Sopenharmony_ci }, 4508c2ecf20Sopenharmony_ci .probe = tps6507x_pmic_probe, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int __init tps6507x_pmic_init(void) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci return platform_driver_register(&tps6507x_pmic_driver); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_cisubsys_initcall(tps6507x_pmic_init); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void __exit tps6507x_pmic_cleanup(void) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci platform_driver_unregister(&tps6507x_pmic_driver); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_cimodule_exit(tps6507x_pmic_cleanup); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments"); 4668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TPS6507x voltage regulator driver"); 4678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4688c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:tps6507x-pmic"); 469