11394fd28SCyril Chemparathy /* 21394fd28SCyril Chemparathy * Regulator driver for TPS6524x PMIC 31394fd28SCyril Chemparathy * 41394fd28SCyril Chemparathy * Copyright (C) 2010 Texas Instruments 51394fd28SCyril Chemparathy * 61394fd28SCyril Chemparathy * This program is free software; you can redistribute it and/or 71394fd28SCyril Chemparathy * modify it under the terms of the GNU General Public License as 81394fd28SCyril Chemparathy * published by the Free Software Foundation version 2. 91394fd28SCyril Chemparathy * 101394fd28SCyril Chemparathy * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, 111394fd28SCyril Chemparathy * whether express or implied; without even the implied warranty of 121394fd28SCyril Chemparathy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 131394fd28SCyril Chemparathy * General Public License for more details. 141394fd28SCyril Chemparathy */ 151394fd28SCyril Chemparathy 161394fd28SCyril Chemparathy #include <linux/kernel.h> 171394fd28SCyril Chemparathy #include <linux/module.h> 181394fd28SCyril Chemparathy #include <linux/err.h> 191394fd28SCyril Chemparathy #include <linux/errno.h> 201394fd28SCyril Chemparathy #include <linux/slab.h> 211394fd28SCyril Chemparathy #include <linux/spi/spi.h> 221394fd28SCyril Chemparathy #include <linux/regulator/driver.h> 231394fd28SCyril Chemparathy #include <linux/regulator/machine.h> 241394fd28SCyril Chemparathy 251394fd28SCyril Chemparathy #define REG_LDO_SET 0x0 261394fd28SCyril Chemparathy #define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ 271394fd28SCyril Chemparathy #define LDO_VSEL_MASK 0x0f 281394fd28SCyril Chemparathy #define LDO2_ILIM_SHIFT 12 291394fd28SCyril Chemparathy #define LDO2_VSEL_SHIFT 4 301394fd28SCyril Chemparathy #define LDO1_ILIM_SHIFT 8 311394fd28SCyril Chemparathy #define LDO1_VSEL_SHIFT 0 321394fd28SCyril Chemparathy 331394fd28SCyril Chemparathy #define REG_BLOCK_EN 0x1 341394fd28SCyril Chemparathy #define BLOCK_MASK 1 351394fd28SCyril Chemparathy #define BLOCK_LDO1_SHIFT 0 361394fd28SCyril Chemparathy #define BLOCK_LDO2_SHIFT 1 371394fd28SCyril Chemparathy #define BLOCK_LCD_SHIFT 2 381394fd28SCyril Chemparathy #define BLOCK_USB_SHIFT 3 391394fd28SCyril Chemparathy 401394fd28SCyril Chemparathy #define REG_DCDC_SET 0x2 411394fd28SCyril Chemparathy #define DCDC_VDCDC_MASK 0x1f 421394fd28SCyril Chemparathy #define DCDC_VDCDC1_SHIFT 0 431394fd28SCyril Chemparathy #define DCDC_VDCDC2_SHIFT 5 441394fd28SCyril Chemparathy #define DCDC_VDCDC3_SHIFT 10 451394fd28SCyril Chemparathy 461394fd28SCyril Chemparathy #define REG_DCDC_EN 0x3 471394fd28SCyril Chemparathy #define DCDCDCDC_EN_MASK 0x1 481394fd28SCyril Chemparathy #define DCDCDCDC1_EN_SHIFT 0 491394fd28SCyril Chemparathy #define DCDCDCDC1_PG_MSK BIT(1) 501394fd28SCyril Chemparathy #define DCDCDCDC2_EN_SHIFT 2 511394fd28SCyril Chemparathy #define DCDCDCDC2_PG_MSK BIT(3) 521394fd28SCyril Chemparathy #define DCDCDCDC3_EN_SHIFT 4 531394fd28SCyril Chemparathy #define DCDCDCDC3_PG_MSK BIT(5) 541394fd28SCyril Chemparathy 551394fd28SCyril Chemparathy #define REG_USB 0x4 561394fd28SCyril Chemparathy #define USB_ILIM_SHIFT 0 571394fd28SCyril Chemparathy #define USB_ILIM_MASK 0x3 581394fd28SCyril Chemparathy #define USB_TSD_SHIFT 2 591394fd28SCyril Chemparathy #define USB_TSD_MASK 0x3 601394fd28SCyril Chemparathy #define USB_TWARN_SHIFT 4 611394fd28SCyril Chemparathy #define USB_TWARN_MASK 0x3 621394fd28SCyril Chemparathy #define USB_IWARN_SD BIT(6) 631394fd28SCyril Chemparathy #define USB_FAST_LOOP BIT(7) 641394fd28SCyril Chemparathy 651394fd28SCyril Chemparathy #define REG_ALARM 0x5 661394fd28SCyril Chemparathy #define ALARM_LDO1 BIT(0) 671394fd28SCyril Chemparathy #define ALARM_DCDC1 BIT(1) 681394fd28SCyril Chemparathy #define ALARM_DCDC2 BIT(2) 691394fd28SCyril Chemparathy #define ALARM_DCDC3 BIT(3) 701394fd28SCyril Chemparathy #define ALARM_LDO2 BIT(4) 711394fd28SCyril Chemparathy #define ALARM_USB_WARN BIT(5) 721394fd28SCyril Chemparathy #define ALARM_USB_ALARM BIT(6) 731394fd28SCyril Chemparathy #define ALARM_LCD BIT(9) 741394fd28SCyril Chemparathy #define ALARM_TEMP_WARM BIT(10) 751394fd28SCyril Chemparathy #define ALARM_TEMP_HOT BIT(11) 761394fd28SCyril Chemparathy #define ALARM_NRST BIT(14) 771394fd28SCyril Chemparathy #define ALARM_POWERUP BIT(15) 781394fd28SCyril Chemparathy 791394fd28SCyril Chemparathy #define REG_INT_ENABLE 0x6 801394fd28SCyril Chemparathy #define INT_LDO1 BIT(0) 811394fd28SCyril Chemparathy #define INT_DCDC1 BIT(1) 821394fd28SCyril Chemparathy #define INT_DCDC2 BIT(2) 831394fd28SCyril Chemparathy #define INT_DCDC3 BIT(3) 841394fd28SCyril Chemparathy #define INT_LDO2 BIT(4) 851394fd28SCyril Chemparathy #define INT_USB_WARN BIT(5) 861394fd28SCyril Chemparathy #define INT_USB_ALARM BIT(6) 871394fd28SCyril Chemparathy #define INT_LCD BIT(9) 881394fd28SCyril Chemparathy #define INT_TEMP_WARM BIT(10) 891394fd28SCyril Chemparathy #define INT_TEMP_HOT BIT(11) 901394fd28SCyril Chemparathy #define INT_GLOBAL_EN BIT(15) 911394fd28SCyril Chemparathy 921394fd28SCyril Chemparathy #define REG_INT_STATUS 0x7 931394fd28SCyril Chemparathy #define STATUS_LDO1 BIT(0) 941394fd28SCyril Chemparathy #define STATUS_DCDC1 BIT(1) 951394fd28SCyril Chemparathy #define STATUS_DCDC2 BIT(2) 961394fd28SCyril Chemparathy #define STATUS_DCDC3 BIT(3) 971394fd28SCyril Chemparathy #define STATUS_LDO2 BIT(4) 981394fd28SCyril Chemparathy #define STATUS_USB_WARN BIT(5) 991394fd28SCyril Chemparathy #define STATUS_USB_ALARM BIT(6) 1001394fd28SCyril Chemparathy #define STATUS_LCD BIT(9) 1011394fd28SCyril Chemparathy #define STATUS_TEMP_WARM BIT(10) 1021394fd28SCyril Chemparathy #define STATUS_TEMP_HOT BIT(11) 1031394fd28SCyril Chemparathy 1041394fd28SCyril Chemparathy #define REG_SOFTWARE_RESET 0xb 1051394fd28SCyril Chemparathy #define REG_WRITE_ENABLE 0xd 1061394fd28SCyril Chemparathy #define REG_REV_ID 0xf 1071394fd28SCyril Chemparathy 1081394fd28SCyril Chemparathy #define N_DCDC 3 1091394fd28SCyril Chemparathy #define N_LDO 2 1101394fd28SCyril Chemparathy #define N_SWITCH 2 1114d984d1cSAxel Lin #define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH) 1121394fd28SCyril Chemparathy 1131394fd28SCyril Chemparathy #define CMD_READ(reg) ((reg) << 6) 1141394fd28SCyril Chemparathy #define CMD_WRITE(reg) (BIT(5) | (reg) << 6) 1151394fd28SCyril Chemparathy #define STAT_CLK BIT(3) 1161394fd28SCyril Chemparathy #define STAT_WRITE BIT(2) 1171394fd28SCyril Chemparathy #define STAT_INVALID BIT(1) 1181394fd28SCyril Chemparathy #define STAT_WP BIT(0) 1191394fd28SCyril Chemparathy 1201394fd28SCyril Chemparathy struct field { 1211394fd28SCyril Chemparathy int reg; 1221394fd28SCyril Chemparathy int shift; 1231394fd28SCyril Chemparathy int mask; 1241394fd28SCyril Chemparathy }; 1251394fd28SCyril Chemparathy 1261394fd28SCyril Chemparathy struct supply_info { 1271394fd28SCyril Chemparathy const char *name; 1281394fd28SCyril Chemparathy int n_voltages; 129cac87fd3SAxel Lin const unsigned int *voltages; 1301394fd28SCyril Chemparathy int n_ilimsels; 1311e12dfc9SAxel Lin const unsigned int *ilimsels; 1321394fd28SCyril Chemparathy struct field enable, voltage, ilimsel; 1331394fd28SCyril Chemparathy }; 1341394fd28SCyril Chemparathy 1351394fd28SCyril Chemparathy struct tps6524x { 1361394fd28SCyril Chemparathy struct device *dev; 1371394fd28SCyril Chemparathy struct spi_device *spi; 1381394fd28SCyril Chemparathy struct mutex lock; 1391394fd28SCyril Chemparathy struct regulator_desc desc[N_REGULATORS]; 1401394fd28SCyril Chemparathy struct regulator_dev *rdev[N_REGULATORS]; 1411394fd28SCyril Chemparathy }; 1421394fd28SCyril Chemparathy 1431394fd28SCyril Chemparathy static int __read_reg(struct tps6524x *hw, int reg) 1441394fd28SCyril Chemparathy { 1451394fd28SCyril Chemparathy int error = 0; 1461394fd28SCyril Chemparathy u16 cmd = CMD_READ(reg), in; 1471394fd28SCyril Chemparathy u8 status; 1481394fd28SCyril Chemparathy struct spi_message m; 1491394fd28SCyril Chemparathy struct spi_transfer t[3]; 1501394fd28SCyril Chemparathy 1511394fd28SCyril Chemparathy spi_message_init(&m); 1521394fd28SCyril Chemparathy memset(t, 0, sizeof(t)); 1531394fd28SCyril Chemparathy 1541394fd28SCyril Chemparathy t[0].tx_buf = &cmd; 1551394fd28SCyril Chemparathy t[0].len = 2; 1561394fd28SCyril Chemparathy t[0].bits_per_word = 12; 1571394fd28SCyril Chemparathy spi_message_add_tail(&t[0], &m); 1581394fd28SCyril Chemparathy 1591394fd28SCyril Chemparathy t[1].rx_buf = ∈ 1601394fd28SCyril Chemparathy t[1].len = 2; 1611394fd28SCyril Chemparathy t[1].bits_per_word = 16; 1621394fd28SCyril Chemparathy spi_message_add_tail(&t[1], &m); 1631394fd28SCyril Chemparathy 1641394fd28SCyril Chemparathy t[2].rx_buf = &status; 1651394fd28SCyril Chemparathy t[2].len = 1; 1661394fd28SCyril Chemparathy t[2].bits_per_word = 4; 1671394fd28SCyril Chemparathy spi_message_add_tail(&t[2], &m); 1681394fd28SCyril Chemparathy 1691394fd28SCyril Chemparathy error = spi_sync(hw->spi, &m); 1701394fd28SCyril Chemparathy if (error < 0) 1711394fd28SCyril Chemparathy return error; 1721394fd28SCyril Chemparathy 1731394fd28SCyril Chemparathy dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", 1741394fd28SCyril Chemparathy reg, in, status); 1751394fd28SCyril Chemparathy 1761394fd28SCyril Chemparathy if (!(status & STAT_CLK) || (status & STAT_WRITE)) 1771394fd28SCyril Chemparathy return -EIO; 1781394fd28SCyril Chemparathy 1791394fd28SCyril Chemparathy if (status & STAT_INVALID) 1801394fd28SCyril Chemparathy return -EINVAL; 1811394fd28SCyril Chemparathy 1821394fd28SCyril Chemparathy return in; 1831394fd28SCyril Chemparathy } 1841394fd28SCyril Chemparathy 1851394fd28SCyril Chemparathy static int read_reg(struct tps6524x *hw, int reg) 1861394fd28SCyril Chemparathy { 1871394fd28SCyril Chemparathy int ret; 1881394fd28SCyril Chemparathy 1891394fd28SCyril Chemparathy mutex_lock(&hw->lock); 1901394fd28SCyril Chemparathy ret = __read_reg(hw, reg); 1911394fd28SCyril Chemparathy mutex_unlock(&hw->lock); 1921394fd28SCyril Chemparathy 1931394fd28SCyril Chemparathy return ret; 1941394fd28SCyril Chemparathy } 1951394fd28SCyril Chemparathy 1961394fd28SCyril Chemparathy static int __write_reg(struct tps6524x *hw, int reg, int val) 1971394fd28SCyril Chemparathy { 1981394fd28SCyril Chemparathy int error = 0; 1991394fd28SCyril Chemparathy u16 cmd = CMD_WRITE(reg), out = val; 2001394fd28SCyril Chemparathy u8 status; 2011394fd28SCyril Chemparathy struct spi_message m; 2021394fd28SCyril Chemparathy struct spi_transfer t[3]; 2031394fd28SCyril Chemparathy 2041394fd28SCyril Chemparathy spi_message_init(&m); 2051394fd28SCyril Chemparathy memset(t, 0, sizeof(t)); 2061394fd28SCyril Chemparathy 2071394fd28SCyril Chemparathy t[0].tx_buf = &cmd; 2081394fd28SCyril Chemparathy t[0].len = 2; 2091394fd28SCyril Chemparathy t[0].bits_per_word = 12; 2101394fd28SCyril Chemparathy spi_message_add_tail(&t[0], &m); 2111394fd28SCyril Chemparathy 2121394fd28SCyril Chemparathy t[1].tx_buf = &out; 2131394fd28SCyril Chemparathy t[1].len = 2; 2141394fd28SCyril Chemparathy t[1].bits_per_word = 16; 2151394fd28SCyril Chemparathy spi_message_add_tail(&t[1], &m); 2161394fd28SCyril Chemparathy 2171394fd28SCyril Chemparathy t[2].rx_buf = &status; 2181394fd28SCyril Chemparathy t[2].len = 1; 2191394fd28SCyril Chemparathy t[2].bits_per_word = 4; 2201394fd28SCyril Chemparathy spi_message_add_tail(&t[2], &m); 2211394fd28SCyril Chemparathy 2221394fd28SCyril Chemparathy error = spi_sync(hw->spi, &m); 2231394fd28SCyril Chemparathy if (error < 0) 2241394fd28SCyril Chemparathy return error; 2251394fd28SCyril Chemparathy 2261394fd28SCyril Chemparathy dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", 2271394fd28SCyril Chemparathy reg, out, status); 2281394fd28SCyril Chemparathy 2291394fd28SCyril Chemparathy if (!(status & STAT_CLK) || !(status & STAT_WRITE)) 2301394fd28SCyril Chemparathy return -EIO; 2311394fd28SCyril Chemparathy 2321394fd28SCyril Chemparathy if (status & (STAT_INVALID | STAT_WP)) 2331394fd28SCyril Chemparathy return -EINVAL; 2341394fd28SCyril Chemparathy 2351394fd28SCyril Chemparathy return error; 2361394fd28SCyril Chemparathy } 2371394fd28SCyril Chemparathy 2381394fd28SCyril Chemparathy static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) 2391394fd28SCyril Chemparathy { 2401394fd28SCyril Chemparathy int ret; 2411394fd28SCyril Chemparathy 2421394fd28SCyril Chemparathy ret = __read_reg(hw, reg); 2431394fd28SCyril Chemparathy if (ret < 0) 2441394fd28SCyril Chemparathy return ret; 2451394fd28SCyril Chemparathy 2461394fd28SCyril Chemparathy ret &= ~mask; 2471394fd28SCyril Chemparathy ret |= val; 2481394fd28SCyril Chemparathy 2491394fd28SCyril Chemparathy ret = __write_reg(hw, reg, ret); 2501394fd28SCyril Chemparathy 2511394fd28SCyril Chemparathy return (ret < 0) ? ret : 0; 2521394fd28SCyril Chemparathy } 2531394fd28SCyril Chemparathy 2541394fd28SCyril Chemparathy static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) 2551394fd28SCyril Chemparathy { 2561394fd28SCyril Chemparathy int ret; 2571394fd28SCyril Chemparathy 2581394fd28SCyril Chemparathy mutex_lock(&hw->lock); 2591394fd28SCyril Chemparathy 2601394fd28SCyril Chemparathy ret = __write_reg(hw, REG_WRITE_ENABLE, 1); 2611394fd28SCyril Chemparathy if (ret) { 2621394fd28SCyril Chemparathy dev_err(hw->dev, "failed to set write enable\n"); 2631394fd28SCyril Chemparathy goto error; 2641394fd28SCyril Chemparathy } 2651394fd28SCyril Chemparathy 2661394fd28SCyril Chemparathy ret = __rmw_reg(hw, reg, mask, val); 2671394fd28SCyril Chemparathy if (ret) 2681394fd28SCyril Chemparathy dev_err(hw->dev, "failed to rmw register %d\n", reg); 2691394fd28SCyril Chemparathy 2701394fd28SCyril Chemparathy ret = __write_reg(hw, REG_WRITE_ENABLE, 0); 2711394fd28SCyril Chemparathy if (ret) { 2721394fd28SCyril Chemparathy dev_err(hw->dev, "failed to clear write enable\n"); 2731394fd28SCyril Chemparathy goto error; 2741394fd28SCyril Chemparathy } 2751394fd28SCyril Chemparathy 2761394fd28SCyril Chemparathy error: 2771394fd28SCyril Chemparathy mutex_unlock(&hw->lock); 2781394fd28SCyril Chemparathy 2791394fd28SCyril Chemparathy return ret; 2801394fd28SCyril Chemparathy } 2811394fd28SCyril Chemparathy 2821394fd28SCyril Chemparathy static int read_field(struct tps6524x *hw, const struct field *field) 2831394fd28SCyril Chemparathy { 2841394fd28SCyril Chemparathy int tmp; 2851394fd28SCyril Chemparathy 2861394fd28SCyril Chemparathy tmp = read_reg(hw, field->reg); 2871394fd28SCyril Chemparathy if (tmp < 0) 2881394fd28SCyril Chemparathy return tmp; 2891394fd28SCyril Chemparathy 2901394fd28SCyril Chemparathy return (tmp >> field->shift) & field->mask; 2911394fd28SCyril Chemparathy } 2921394fd28SCyril Chemparathy 2931394fd28SCyril Chemparathy static int write_field(struct tps6524x *hw, const struct field *field, 2941394fd28SCyril Chemparathy int val) 2951394fd28SCyril Chemparathy { 2961394fd28SCyril Chemparathy if (val & ~field->mask) 2971394fd28SCyril Chemparathy return -EOVERFLOW; 2981394fd28SCyril Chemparathy 2991394fd28SCyril Chemparathy return rmw_protect(hw, field->reg, 3001394fd28SCyril Chemparathy field->mask << field->shift, 3011394fd28SCyril Chemparathy val << field->shift); 3021394fd28SCyril Chemparathy } 3031394fd28SCyril Chemparathy 304cac87fd3SAxel Lin static const unsigned int dcdc1_voltages[] = { 3051394fd28SCyril Chemparathy 800000, 825000, 850000, 875000, 3061394fd28SCyril Chemparathy 900000, 925000, 950000, 975000, 3071394fd28SCyril Chemparathy 1000000, 1025000, 1050000, 1075000, 3081394fd28SCyril Chemparathy 1100000, 1125000, 1150000, 1175000, 3091394fd28SCyril Chemparathy 1200000, 1225000, 1250000, 1275000, 3101394fd28SCyril Chemparathy 1300000, 1325000, 1350000, 1375000, 3111394fd28SCyril Chemparathy 1400000, 1425000, 1450000, 1475000, 3121394fd28SCyril Chemparathy 1500000, 1525000, 1550000, 1575000, 3131394fd28SCyril Chemparathy }; 3141394fd28SCyril Chemparathy 315cac87fd3SAxel Lin static const unsigned int dcdc2_voltages[] = { 3161394fd28SCyril Chemparathy 1400000, 1450000, 1500000, 1550000, 3171394fd28SCyril Chemparathy 1600000, 1650000, 1700000, 1750000, 3181394fd28SCyril Chemparathy 1800000, 1850000, 1900000, 1950000, 3191394fd28SCyril Chemparathy 2000000, 2050000, 2100000, 2150000, 3201394fd28SCyril Chemparathy 2200000, 2250000, 2300000, 2350000, 3211394fd28SCyril Chemparathy 2400000, 2450000, 2500000, 2550000, 3221394fd28SCyril Chemparathy 2600000, 2650000, 2700000, 2750000, 3231394fd28SCyril Chemparathy 2800000, 2850000, 2900000, 2950000, 3241394fd28SCyril Chemparathy }; 3251394fd28SCyril Chemparathy 326cac87fd3SAxel Lin static const unsigned int dcdc3_voltages[] = { 3271394fd28SCyril Chemparathy 2400000, 2450000, 2500000, 2550000, 2600000, 3281394fd28SCyril Chemparathy 2650000, 2700000, 2750000, 2800000, 2850000, 3291394fd28SCyril Chemparathy 2900000, 2950000, 3000000, 3050000, 3100000, 3301394fd28SCyril Chemparathy 3150000, 3200000, 3250000, 3300000, 3350000, 3311394fd28SCyril Chemparathy 3400000, 3450000, 3500000, 3550000, 3600000, 3321394fd28SCyril Chemparathy }; 3331394fd28SCyril Chemparathy 334cac87fd3SAxel Lin static const unsigned int ldo1_voltages[] = { 3351394fd28SCyril Chemparathy 4300000, 4350000, 4400000, 4450000, 3361394fd28SCyril Chemparathy 4500000, 4550000, 4600000, 4650000, 3371394fd28SCyril Chemparathy 4700000, 4750000, 4800000, 4850000, 3381394fd28SCyril Chemparathy 4900000, 4950000, 5000000, 5050000, 3391394fd28SCyril Chemparathy }; 3401394fd28SCyril Chemparathy 341cac87fd3SAxel Lin static const unsigned int ldo2_voltages[] = { 3421394fd28SCyril Chemparathy 1100000, 1150000, 1200000, 1250000, 3431394fd28SCyril Chemparathy 1300000, 1700000, 1750000, 1800000, 3441394fd28SCyril Chemparathy 1850000, 1900000, 3150000, 3200000, 3451394fd28SCyril Chemparathy 3250000, 3300000, 3350000, 3400000, 3461394fd28SCyril Chemparathy }; 3471394fd28SCyril Chemparathy 348cac87fd3SAxel Lin static const unsigned int fixed_5000000_voltage[] = { 349cac87fd3SAxel Lin 5000000 350cac87fd3SAxel Lin }; 351cac87fd3SAxel Lin 3521e12dfc9SAxel Lin static const unsigned int ldo_ilimsel[] = { 3531394fd28SCyril Chemparathy 400000, 1500000 3541394fd28SCyril Chemparathy }; 3551394fd28SCyril Chemparathy 3561e12dfc9SAxel Lin static const unsigned int usb_ilimsel[] = { 3571394fd28SCyril Chemparathy 200000, 400000, 800000, 1000000 3581394fd28SCyril Chemparathy }; 3591394fd28SCyril Chemparathy 3601e12dfc9SAxel Lin static const unsigned int fixed_2400000_ilimsel[] = { 3611e12dfc9SAxel Lin 2400000 3621e12dfc9SAxel Lin }; 3631e12dfc9SAxel Lin 3641e12dfc9SAxel Lin static const unsigned int fixed_1200000_ilimsel[] = { 3651e12dfc9SAxel Lin 1200000 3661e12dfc9SAxel Lin }; 3671e12dfc9SAxel Lin 3681e12dfc9SAxel Lin static const unsigned int fixed_400000_ilimsel[] = { 3691e12dfc9SAxel Lin 400000 3701e12dfc9SAxel Lin }; 3711e12dfc9SAxel Lin 3721394fd28SCyril Chemparathy #define __MK_FIELD(_reg, _mask, _shift) \ 3731394fd28SCyril Chemparathy { .reg = (_reg), .mask = (_mask), .shift = (_shift), } 3741394fd28SCyril Chemparathy 3751394fd28SCyril Chemparathy static const struct supply_info supply_info[N_REGULATORS] = { 3761394fd28SCyril Chemparathy { 3771394fd28SCyril Chemparathy .name = "DCDC1", 3781394fd28SCyril Chemparathy .n_voltages = ARRAY_SIZE(dcdc1_voltages), 3791394fd28SCyril Chemparathy .voltages = dcdc1_voltages, 3801e12dfc9SAxel Lin .n_ilimsels = ARRAY_SIZE(fixed_2400000_ilimsel), 3811e12dfc9SAxel Lin .ilimsels = fixed_2400000_ilimsel, 3821394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, 3831394fd28SCyril Chemparathy DCDCDCDC1_EN_SHIFT), 3841394fd28SCyril Chemparathy .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, 3851394fd28SCyril Chemparathy DCDC_VDCDC1_SHIFT), 3861394fd28SCyril Chemparathy }, 3871394fd28SCyril Chemparathy { 3881394fd28SCyril Chemparathy .name = "DCDC2", 3891394fd28SCyril Chemparathy .n_voltages = ARRAY_SIZE(dcdc2_voltages), 3901394fd28SCyril Chemparathy .voltages = dcdc2_voltages, 3911e12dfc9SAxel Lin .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), 3921e12dfc9SAxel Lin .ilimsels = fixed_1200000_ilimsel, 3931394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, 3941394fd28SCyril Chemparathy DCDCDCDC2_EN_SHIFT), 3951394fd28SCyril Chemparathy .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, 3961394fd28SCyril Chemparathy DCDC_VDCDC2_SHIFT), 3971394fd28SCyril Chemparathy }, 3981394fd28SCyril Chemparathy { 3991394fd28SCyril Chemparathy .name = "DCDC3", 4001394fd28SCyril Chemparathy .n_voltages = ARRAY_SIZE(dcdc3_voltages), 4011394fd28SCyril Chemparathy .voltages = dcdc3_voltages, 4021e12dfc9SAxel Lin .n_ilimsels = ARRAY_SIZE(fixed_1200000_ilimsel), 4031e12dfc9SAxel Lin .ilimsels = fixed_1200000_ilimsel, 4041394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, 4051394fd28SCyril Chemparathy DCDCDCDC3_EN_SHIFT), 4061394fd28SCyril Chemparathy .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, 4071394fd28SCyril Chemparathy DCDC_VDCDC3_SHIFT), 4081394fd28SCyril Chemparathy }, 4091394fd28SCyril Chemparathy { 4101394fd28SCyril Chemparathy .name = "LDO1", 4111394fd28SCyril Chemparathy .n_voltages = ARRAY_SIZE(ldo1_voltages), 4121394fd28SCyril Chemparathy .voltages = ldo1_voltages, 4131394fd28SCyril Chemparathy .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), 4141394fd28SCyril Chemparathy .ilimsels = ldo_ilimsel, 4151394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, 4161394fd28SCyril Chemparathy BLOCK_LDO1_SHIFT), 4171394fd28SCyril Chemparathy .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, 4181394fd28SCyril Chemparathy LDO1_VSEL_SHIFT), 4191394fd28SCyril Chemparathy .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, 4201394fd28SCyril Chemparathy LDO1_ILIM_SHIFT), 4211394fd28SCyril Chemparathy }, 4221394fd28SCyril Chemparathy { 4231394fd28SCyril Chemparathy .name = "LDO2", 4241394fd28SCyril Chemparathy .n_voltages = ARRAY_SIZE(ldo2_voltages), 4251394fd28SCyril Chemparathy .voltages = ldo2_voltages, 4261394fd28SCyril Chemparathy .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), 4271394fd28SCyril Chemparathy .ilimsels = ldo_ilimsel, 4281394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, 4291394fd28SCyril Chemparathy BLOCK_LDO2_SHIFT), 4301394fd28SCyril Chemparathy .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, 4311394fd28SCyril Chemparathy LDO2_VSEL_SHIFT), 4321394fd28SCyril Chemparathy .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, 4331394fd28SCyril Chemparathy LDO2_ILIM_SHIFT), 4341394fd28SCyril Chemparathy }, 4351394fd28SCyril Chemparathy { 4361394fd28SCyril Chemparathy .name = "USB", 437cac87fd3SAxel Lin .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), 438cac87fd3SAxel Lin .voltages = fixed_5000000_voltage, 4391394fd28SCyril Chemparathy .n_ilimsels = ARRAY_SIZE(usb_ilimsel), 4401394fd28SCyril Chemparathy .ilimsels = usb_ilimsel, 4411394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, 4421394fd28SCyril Chemparathy BLOCK_USB_SHIFT), 4431394fd28SCyril Chemparathy .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, 4441394fd28SCyril Chemparathy USB_ILIM_SHIFT), 4451394fd28SCyril Chemparathy }, 4461394fd28SCyril Chemparathy { 4471394fd28SCyril Chemparathy .name = "LCD", 448cac87fd3SAxel Lin .n_voltages = ARRAY_SIZE(fixed_5000000_voltage), 449cac87fd3SAxel Lin .voltages = fixed_5000000_voltage, 4501e12dfc9SAxel Lin .n_ilimsels = ARRAY_SIZE(fixed_400000_ilimsel), 4511e12dfc9SAxel Lin .ilimsels = fixed_400000_ilimsel, 4521394fd28SCyril Chemparathy .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, 4531394fd28SCyril Chemparathy BLOCK_LCD_SHIFT), 4541394fd28SCyril Chemparathy }, 4551394fd28SCyril Chemparathy }; 4561394fd28SCyril Chemparathy 457f8ee3393SAxel Lin static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) 4581394fd28SCyril Chemparathy { 4591394fd28SCyril Chemparathy const struct supply_info *info; 4601394fd28SCyril Chemparathy struct tps6524x *hw; 4611394fd28SCyril Chemparathy 4621394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 4631394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 4641394fd28SCyril Chemparathy 465cac87fd3SAxel Lin if (rdev->desc->n_voltages == 1) 4661394fd28SCyril Chemparathy return -EINVAL; 4671394fd28SCyril Chemparathy 468f8ee3393SAxel Lin return write_field(hw, &info->voltage, selector); 4691394fd28SCyril Chemparathy } 4701394fd28SCyril Chemparathy 4714af7c1d3SAxel Lin static int get_voltage_sel(struct regulator_dev *rdev) 4721394fd28SCyril Chemparathy { 4731394fd28SCyril Chemparathy const struct supply_info *info; 4741394fd28SCyril Chemparathy struct tps6524x *hw; 4751394fd28SCyril Chemparathy int ret; 4761394fd28SCyril Chemparathy 4771394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 4781394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 4791394fd28SCyril Chemparathy 480cac87fd3SAxel Lin if (rdev->desc->n_voltages == 1) 4818386a00fSAxel Lin return 0; 4821394fd28SCyril Chemparathy 4831394fd28SCyril Chemparathy ret = read_field(hw, &info->voltage); 4841394fd28SCyril Chemparathy if (ret < 0) 4851394fd28SCyril Chemparathy return ret; 4861394fd28SCyril Chemparathy if (WARN_ON(ret >= info->n_voltages)) 4871394fd28SCyril Chemparathy return -EIO; 4881394fd28SCyril Chemparathy 4894af7c1d3SAxel Lin return ret; 4901394fd28SCyril Chemparathy } 4911394fd28SCyril Chemparathy 4921394fd28SCyril Chemparathy static int set_current_limit(struct regulator_dev *rdev, int min_uA, 4931394fd28SCyril Chemparathy int max_uA) 4941394fd28SCyril Chemparathy { 4951394fd28SCyril Chemparathy const struct supply_info *info; 4961394fd28SCyril Chemparathy struct tps6524x *hw; 4971394fd28SCyril Chemparathy int i; 4981394fd28SCyril Chemparathy 4991394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 5001394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 5011394fd28SCyril Chemparathy 5021e12dfc9SAxel Lin if (info->n_ilimsels == 1) 5031394fd28SCyril Chemparathy return -EINVAL; 5041394fd28SCyril Chemparathy 50573f4f3d3SAxel Lin for (i = info->n_ilimsels - 1; i >= 0; i--) { 5061394fd28SCyril Chemparathy if (min_uA <= info->ilimsels[i] && 5071394fd28SCyril Chemparathy max_uA >= info->ilimsels[i]) 5081394fd28SCyril Chemparathy return write_field(hw, &info->ilimsel, i); 5091394fd28SCyril Chemparathy } 5101394fd28SCyril Chemparathy 51173f4f3d3SAxel Lin return -EINVAL; 51273f4f3d3SAxel Lin } 51373f4f3d3SAxel Lin 5141394fd28SCyril Chemparathy static int get_current_limit(struct regulator_dev *rdev) 5151394fd28SCyril Chemparathy { 5161394fd28SCyril Chemparathy const struct supply_info *info; 5171394fd28SCyril Chemparathy struct tps6524x *hw; 5181394fd28SCyril Chemparathy int ret; 5191394fd28SCyril Chemparathy 5201394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 5211394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 5221394fd28SCyril Chemparathy 5231e12dfc9SAxel Lin if (info->n_ilimsels == 1) 5241e12dfc9SAxel Lin return info->ilimsels[0]; 5251394fd28SCyril Chemparathy 5261394fd28SCyril Chemparathy ret = read_field(hw, &info->ilimsel); 5271394fd28SCyril Chemparathy if (ret < 0) 5281394fd28SCyril Chemparathy return ret; 5291394fd28SCyril Chemparathy if (WARN_ON(ret >= info->n_ilimsels)) 5301394fd28SCyril Chemparathy return -EIO; 5311394fd28SCyril Chemparathy 5321394fd28SCyril Chemparathy return info->ilimsels[ret]; 5331394fd28SCyril Chemparathy } 5341394fd28SCyril Chemparathy 5351394fd28SCyril Chemparathy static int enable_supply(struct regulator_dev *rdev) 5361394fd28SCyril Chemparathy { 5371394fd28SCyril Chemparathy const struct supply_info *info; 5381394fd28SCyril Chemparathy struct tps6524x *hw; 5391394fd28SCyril Chemparathy 5401394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 5411394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 5421394fd28SCyril Chemparathy 5431394fd28SCyril Chemparathy return write_field(hw, &info->enable, 1); 5441394fd28SCyril Chemparathy } 5451394fd28SCyril Chemparathy 5461394fd28SCyril Chemparathy static int disable_supply(struct regulator_dev *rdev) 5471394fd28SCyril Chemparathy { 5481394fd28SCyril Chemparathy const struct supply_info *info; 5491394fd28SCyril Chemparathy struct tps6524x *hw; 5501394fd28SCyril Chemparathy 5511394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 5521394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 5531394fd28SCyril Chemparathy 5541394fd28SCyril Chemparathy return write_field(hw, &info->enable, 0); 5551394fd28SCyril Chemparathy } 5561394fd28SCyril Chemparathy 5571394fd28SCyril Chemparathy static int is_supply_enabled(struct regulator_dev *rdev) 5581394fd28SCyril Chemparathy { 5591394fd28SCyril Chemparathy const struct supply_info *info; 5601394fd28SCyril Chemparathy struct tps6524x *hw; 5611394fd28SCyril Chemparathy 5621394fd28SCyril Chemparathy hw = rdev_get_drvdata(rdev); 5631394fd28SCyril Chemparathy info = &supply_info[rdev_get_id(rdev)]; 5641394fd28SCyril Chemparathy 5651394fd28SCyril Chemparathy return read_field(hw, &info->enable); 5661394fd28SCyril Chemparathy } 5671394fd28SCyril Chemparathy 568357db027SAxel Lin static const struct regulator_ops regulator_ops = { 5691394fd28SCyril Chemparathy .is_enabled = is_supply_enabled, 5701394fd28SCyril Chemparathy .enable = enable_supply, 5711394fd28SCyril Chemparathy .disable = disable_supply, 5724af7c1d3SAxel Lin .get_voltage_sel = get_voltage_sel, 573f8ee3393SAxel Lin .set_voltage_sel = set_voltage_sel, 574cac87fd3SAxel Lin .list_voltage = regulator_list_voltage_table, 575b92f567dSAxel Lin .map_voltage = regulator_map_voltage_ascend, 5761394fd28SCyril Chemparathy .set_current_limit = set_current_limit, 5771394fd28SCyril Chemparathy .get_current_limit = get_current_limit, 5781394fd28SCyril Chemparathy }; 5791394fd28SCyril Chemparathy 580a5023574SBill Pemberton static int pmic_probe(struct spi_device *spi) 5811394fd28SCyril Chemparathy { 5821394fd28SCyril Chemparathy struct tps6524x *hw; 5831394fd28SCyril Chemparathy struct device *dev = &spi->dev; 5841394fd28SCyril Chemparathy const struct supply_info *info = supply_info; 5851394fd28SCyril Chemparathy struct regulator_init_data *init_data; 586c172708dSMark Brown struct regulator_config config = { }; 5875e085575SJingoo Han int i; 5881394fd28SCyril Chemparathy 589dff91d0bSJingoo Han init_data = dev_get_platdata(dev); 5901394fd28SCyril Chemparathy if (!init_data) { 5911394fd28SCyril Chemparathy dev_err(dev, "could not find regulator platform data\n"); 5921394fd28SCyril Chemparathy return -EINVAL; 5931394fd28SCyril Chemparathy } 5941394fd28SCyril Chemparathy 5959eb0c421SAxel Lin hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); 596516add1dSSachin Kamat if (!hw) 5971394fd28SCyril Chemparathy return -ENOMEM; 598516add1dSSachin Kamat 5991394fd28SCyril Chemparathy spi_set_drvdata(spi, hw); 6001394fd28SCyril Chemparathy 6011394fd28SCyril Chemparathy memset(hw, 0, sizeof(struct tps6524x)); 6021394fd28SCyril Chemparathy hw->dev = dev; 603ae714c3bSMark Brown hw->spi = spi; 6041394fd28SCyril Chemparathy mutex_init(&hw->lock); 6051394fd28SCyril Chemparathy 6061394fd28SCyril Chemparathy for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { 6071394fd28SCyril Chemparathy hw->desc[i].name = info->name; 6081394fd28SCyril Chemparathy hw->desc[i].id = i; 6091394fd28SCyril Chemparathy hw->desc[i].n_voltages = info->n_voltages; 610cac87fd3SAxel Lin hw->desc[i].volt_table = info->voltages; 6111394fd28SCyril Chemparathy hw->desc[i].ops = ®ulator_ops; 6121394fd28SCyril Chemparathy hw->desc[i].type = REGULATOR_VOLTAGE; 6131394fd28SCyril Chemparathy hw->desc[i].owner = THIS_MODULE; 6141394fd28SCyril Chemparathy 615c172708dSMark Brown config.dev = dev; 616c172708dSMark Brown config.init_data = init_data; 617c172708dSMark Brown config.driver_data = hw; 618c172708dSMark Brown 6195e085575SJingoo Han hw->rdev[i] = devm_regulator_register(dev, &hw->desc[i], 6205e085575SJingoo Han &config); 6215e085575SJingoo Han if (IS_ERR(hw->rdev[i])) 6225e085575SJingoo Han return PTR_ERR(hw->rdev[i]); 6231394fd28SCyril Chemparathy } 6241394fd28SCyril Chemparathy 6251394fd28SCyril Chemparathy return 0; 6261394fd28SCyril Chemparathy } 6271394fd28SCyril Chemparathy 6281394fd28SCyril Chemparathy static struct spi_driver pmic_driver = { 6291394fd28SCyril Chemparathy .probe = pmic_probe, 6301394fd28SCyril Chemparathy .driver = { 6311394fd28SCyril Chemparathy .name = "tps6524x", 6321394fd28SCyril Chemparathy }, 6331394fd28SCyril Chemparathy }; 6341394fd28SCyril Chemparathy 635173f24d1SMark Brown module_spi_driver(pmic_driver); 6361394fd28SCyril Chemparathy 6371394fd28SCyril Chemparathy MODULE_DESCRIPTION("TPS6524X PMIC Driver"); 6381394fd28SCyril Chemparathy MODULE_AUTHOR("Cyril Chemparathy"); 6391394fd28SCyril Chemparathy MODULE_LICENSE("GPL"); 6401394fd28SCyril Chemparathy MODULE_ALIAS("spi:tps6524x"); 641