1518fb721SGraeme Gregory /* 2518fb721SGraeme Gregory * tps65910.c -- TI tps65910 3518fb721SGraeme Gregory * 4518fb721SGraeme Gregory * Copyright 2010 Texas Instruments Inc. 5518fb721SGraeme Gregory * 6518fb721SGraeme Gregory * Author: Graeme Gregory <gg@slimlogic.co.uk> 7518fb721SGraeme Gregory * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 8518fb721SGraeme Gregory * 9518fb721SGraeme Gregory * This program is free software; you can redistribute it and/or modify it 10518fb721SGraeme Gregory * under the terms of the GNU General Public License as published by the 11518fb721SGraeme Gregory * Free Software Foundation; either version 2 of the License, or (at your 12518fb721SGraeme Gregory * option) any later version. 13518fb721SGraeme Gregory * 14518fb721SGraeme Gregory */ 15518fb721SGraeme Gregory 16518fb721SGraeme Gregory #include <linux/kernel.h> 17518fb721SGraeme Gregory #include <linux/module.h> 18518fb721SGraeme Gregory #include <linux/init.h> 19518fb721SGraeme Gregory #include <linux/err.h> 20518fb721SGraeme Gregory #include <linux/platform_device.h> 21518fb721SGraeme Gregory #include <linux/regulator/driver.h> 22518fb721SGraeme Gregory #include <linux/regulator/machine.h> 23518fb721SGraeme Gregory #include <linux/slab.h> 24518fb721SGraeme Gregory #include <linux/gpio.h> 25518fb721SGraeme Gregory #include <linux/mfd/tps65910.h> 266790178fSRhyland Klein #include <linux/regulator/of_regulator.h> 27518fb721SGraeme Gregory 28518fb721SGraeme Gregory #define TPS65910_SUPPLY_STATE_ENABLED 0x1 291e0c66f4SLaxman Dewangan #define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ 301e0c66f4SLaxman Dewangan TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \ 31f30b0716SLaxman Dewangan TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \ 32f30b0716SLaxman Dewangan TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) 33518fb721SGraeme Gregory 34d9fe28f9SAxel Lin /* supported VIO voltages in microvolts */ 35d9fe28f9SAxel Lin static const unsigned int VIO_VSEL_table[] = { 36d9fe28f9SAxel Lin 1500000, 1800000, 2500000, 3300000, 37518fb721SGraeme Gregory }; 38518fb721SGraeme Gregory 39a320e3c3SJorge Eduardo Candelaria /* VSEL tables for TPS65910 specific LDOs and dcdc's */ 40a320e3c3SJorge Eduardo Candelaria 41d9fe28f9SAxel Lin /* supported VDD3 voltages in microvolts */ 42d9fe28f9SAxel Lin static const unsigned int VDD3_VSEL_table[] = { 43d9fe28f9SAxel Lin 5000000, 44518fb721SGraeme Gregory }; 45518fb721SGraeme Gregory 46d9fe28f9SAxel Lin /* supported VDIG1 voltages in microvolts */ 47d9fe28f9SAxel Lin static const unsigned int VDIG1_VSEL_table[] = { 48d9fe28f9SAxel Lin 1200000, 1500000, 1800000, 2700000, 49518fb721SGraeme Gregory }; 50518fb721SGraeme Gregory 51d9fe28f9SAxel Lin /* supported VDIG2 voltages in microvolts */ 52d9fe28f9SAxel Lin static const unsigned int VDIG2_VSEL_table[] = { 53d9fe28f9SAxel Lin 1000000, 1100000, 1200000, 1800000, 54518fb721SGraeme Gregory }; 55518fb721SGraeme Gregory 56d9fe28f9SAxel Lin /* supported VPLL voltages in microvolts */ 57d9fe28f9SAxel Lin static const unsigned int VPLL_VSEL_table[] = { 58d9fe28f9SAxel Lin 1000000, 1100000, 1800000, 2500000, 59518fb721SGraeme Gregory }; 60518fb721SGraeme Gregory 61d9fe28f9SAxel Lin /* supported VDAC voltages in microvolts */ 62d9fe28f9SAxel Lin static const unsigned int VDAC_VSEL_table[] = { 63d9fe28f9SAxel Lin 1800000, 2600000, 2800000, 2850000, 64518fb721SGraeme Gregory }; 65518fb721SGraeme Gregory 66d9fe28f9SAxel Lin /* supported VAUX1 voltages in microvolts */ 67d9fe28f9SAxel Lin static const unsigned int VAUX1_VSEL_table[] = { 68d9fe28f9SAxel Lin 1800000, 2500000, 2800000, 2850000, 69518fb721SGraeme Gregory }; 70518fb721SGraeme Gregory 71d9fe28f9SAxel Lin /* supported VAUX2 voltages in microvolts */ 72d9fe28f9SAxel Lin static const unsigned int VAUX2_VSEL_table[] = { 73d9fe28f9SAxel Lin 1800000, 2800000, 2900000, 3300000, 74518fb721SGraeme Gregory }; 75518fb721SGraeme Gregory 76d9fe28f9SAxel Lin /* supported VAUX33 voltages in microvolts */ 77d9fe28f9SAxel Lin static const unsigned int VAUX33_VSEL_table[] = { 78d9fe28f9SAxel Lin 1800000, 2000000, 2800000, 3300000, 79518fb721SGraeme Gregory }; 80518fb721SGraeme Gregory 81d9fe28f9SAxel Lin /* supported VMMC voltages in microvolts */ 82d9fe28f9SAxel Lin static const unsigned int VMMC_VSEL_table[] = { 83d9fe28f9SAxel Lin 1800000, 2800000, 3000000, 3300000, 84518fb721SGraeme Gregory }; 85518fb721SGraeme Gregory 86518fb721SGraeme Gregory struct tps_info { 87518fb721SGraeme Gregory const char *name; 8819228a6aSLaxman Dewangan const char *vin_name; 897d38a3cbSLaxman Dewangan u8 n_voltages; 90d9fe28f9SAxel Lin const unsigned int *voltage_table; 910651eed5SLaxman Dewangan int enable_time_us; 92518fb721SGraeme Gregory }; 93518fb721SGraeme Gregory 94518fb721SGraeme Gregory static struct tps_info tps65910_regs[] = { 95518fb721SGraeme Gregory { 9633a6943dSLaxman Dewangan .name = "vrtc", 9719228a6aSLaxman Dewangan .vin_name = "vcc7", 980651eed5SLaxman Dewangan .enable_time_us = 2200, 99518fb721SGraeme Gregory }, 100518fb721SGraeme Gregory { 10133a6943dSLaxman Dewangan .name = "vio", 10219228a6aSLaxman Dewangan .vin_name = "vccio", 1037d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VIO_VSEL_table), 1047d38a3cbSLaxman Dewangan .voltage_table = VIO_VSEL_table, 1050651eed5SLaxman Dewangan .enable_time_us = 350, 106518fb721SGraeme Gregory }, 107518fb721SGraeme Gregory { 10833a6943dSLaxman Dewangan .name = "vdd1", 10919228a6aSLaxman Dewangan .vin_name = "vcc1", 1100651eed5SLaxman Dewangan .enable_time_us = 350, 111518fb721SGraeme Gregory }, 112518fb721SGraeme Gregory { 11333a6943dSLaxman Dewangan .name = "vdd2", 11419228a6aSLaxman Dewangan .vin_name = "vcc2", 1150651eed5SLaxman Dewangan .enable_time_us = 350, 116518fb721SGraeme Gregory }, 117518fb721SGraeme Gregory { 11833a6943dSLaxman Dewangan .name = "vdd3", 1197d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), 1207d38a3cbSLaxman Dewangan .voltage_table = VDD3_VSEL_table, 1210651eed5SLaxman Dewangan .enable_time_us = 200, 122518fb721SGraeme Gregory }, 123518fb721SGraeme Gregory { 12433a6943dSLaxman Dewangan .name = "vdig1", 12519228a6aSLaxman Dewangan .vin_name = "vcc6", 1267d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), 1277d38a3cbSLaxman Dewangan .voltage_table = VDIG1_VSEL_table, 1280651eed5SLaxman Dewangan .enable_time_us = 100, 129518fb721SGraeme Gregory }, 130518fb721SGraeme Gregory { 13133a6943dSLaxman Dewangan .name = "vdig2", 13219228a6aSLaxman Dewangan .vin_name = "vcc6", 1337d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), 1347d38a3cbSLaxman Dewangan .voltage_table = VDIG2_VSEL_table, 1350651eed5SLaxman Dewangan .enable_time_us = 100, 136518fb721SGraeme Gregory }, 137518fb721SGraeme Gregory { 13833a6943dSLaxman Dewangan .name = "vpll", 13919228a6aSLaxman Dewangan .vin_name = "vcc5", 1407d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), 1417d38a3cbSLaxman Dewangan .voltage_table = VPLL_VSEL_table, 1420651eed5SLaxman Dewangan .enable_time_us = 100, 143518fb721SGraeme Gregory }, 144518fb721SGraeme Gregory { 14533a6943dSLaxman Dewangan .name = "vdac", 14619228a6aSLaxman Dewangan .vin_name = "vcc5", 1477d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), 1487d38a3cbSLaxman Dewangan .voltage_table = VDAC_VSEL_table, 1490651eed5SLaxman Dewangan .enable_time_us = 100, 150518fb721SGraeme Gregory }, 151518fb721SGraeme Gregory { 15233a6943dSLaxman Dewangan .name = "vaux1", 15319228a6aSLaxman Dewangan .vin_name = "vcc4", 1547d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), 1557d38a3cbSLaxman Dewangan .voltage_table = VAUX1_VSEL_table, 1560651eed5SLaxman Dewangan .enable_time_us = 100, 157518fb721SGraeme Gregory }, 158518fb721SGraeme Gregory { 15933a6943dSLaxman Dewangan .name = "vaux2", 16019228a6aSLaxman Dewangan .vin_name = "vcc4", 1617d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), 1627d38a3cbSLaxman Dewangan .voltage_table = VAUX2_VSEL_table, 1630651eed5SLaxman Dewangan .enable_time_us = 100, 164518fb721SGraeme Gregory }, 165518fb721SGraeme Gregory { 16633a6943dSLaxman Dewangan .name = "vaux33", 16719228a6aSLaxman Dewangan .vin_name = "vcc3", 1687d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), 1697d38a3cbSLaxman Dewangan .voltage_table = VAUX33_VSEL_table, 1700651eed5SLaxman Dewangan .enable_time_us = 100, 171518fb721SGraeme Gregory }, 172518fb721SGraeme Gregory { 17333a6943dSLaxman Dewangan .name = "vmmc", 17419228a6aSLaxman Dewangan .vin_name = "vcc3", 1757d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), 1767d38a3cbSLaxman Dewangan .voltage_table = VMMC_VSEL_table, 1770651eed5SLaxman Dewangan .enable_time_us = 100, 178518fb721SGraeme Gregory }, 179518fb721SGraeme Gregory }; 180518fb721SGraeme Gregory 181a320e3c3SJorge Eduardo Candelaria static struct tps_info tps65911_regs[] = { 182a320e3c3SJorge Eduardo Candelaria { 18333a6943dSLaxman Dewangan .name = "vrtc", 18419228a6aSLaxman Dewangan .vin_name = "vcc7", 1850651eed5SLaxman Dewangan .enable_time_us = 2200, 186c2f8efd7SLaxman Dewangan }, 187c2f8efd7SLaxman Dewangan { 18833a6943dSLaxman Dewangan .name = "vio", 18919228a6aSLaxman Dewangan .vin_name = "vccio", 1907d38a3cbSLaxman Dewangan .n_voltages = ARRAY_SIZE(VIO_VSEL_table), 1917d38a3cbSLaxman Dewangan .voltage_table = VIO_VSEL_table, 1920651eed5SLaxman Dewangan .enable_time_us = 350, 193a320e3c3SJorge Eduardo Candelaria }, 194a320e3c3SJorge Eduardo Candelaria { 19533a6943dSLaxman Dewangan .name = "vdd1", 19619228a6aSLaxman Dewangan .vin_name = "vcc1", 1977d38a3cbSLaxman Dewangan .n_voltages = 73, 1980651eed5SLaxman Dewangan .enable_time_us = 350, 199a320e3c3SJorge Eduardo Candelaria }, 200a320e3c3SJorge Eduardo Candelaria { 20133a6943dSLaxman Dewangan .name = "vdd2", 20219228a6aSLaxman Dewangan .vin_name = "vcc2", 2037d38a3cbSLaxman Dewangan .n_voltages = 73, 2040651eed5SLaxman Dewangan .enable_time_us = 350, 205a320e3c3SJorge Eduardo Candelaria }, 206a320e3c3SJorge Eduardo Candelaria { 20733a6943dSLaxman Dewangan .name = "vddctrl", 2087d38a3cbSLaxman Dewangan .n_voltages = 65, 2090651eed5SLaxman Dewangan .enable_time_us = 900, 210a320e3c3SJorge Eduardo Candelaria }, 211a320e3c3SJorge Eduardo Candelaria { 21233a6943dSLaxman Dewangan .name = "ldo1", 21319228a6aSLaxman Dewangan .vin_name = "vcc6", 2147d38a3cbSLaxman Dewangan .n_voltages = 47, 2150651eed5SLaxman Dewangan .enable_time_us = 420, 216a320e3c3SJorge Eduardo Candelaria }, 217a320e3c3SJorge Eduardo Candelaria { 21833a6943dSLaxman Dewangan .name = "ldo2", 21919228a6aSLaxman Dewangan .vin_name = "vcc6", 2207d38a3cbSLaxman Dewangan .n_voltages = 47, 2210651eed5SLaxman Dewangan .enable_time_us = 420, 222a320e3c3SJorge Eduardo Candelaria }, 223a320e3c3SJorge Eduardo Candelaria { 22433a6943dSLaxman Dewangan .name = "ldo3", 22519228a6aSLaxman Dewangan .vin_name = "vcc5", 2267d38a3cbSLaxman Dewangan .n_voltages = 24, 2270651eed5SLaxman Dewangan .enable_time_us = 230, 228a320e3c3SJorge Eduardo Candelaria }, 229a320e3c3SJorge Eduardo Candelaria { 23033a6943dSLaxman Dewangan .name = "ldo4", 23119228a6aSLaxman Dewangan .vin_name = "vcc5", 2327d38a3cbSLaxman Dewangan .n_voltages = 47, 2330651eed5SLaxman Dewangan .enable_time_us = 230, 234a320e3c3SJorge Eduardo Candelaria }, 235a320e3c3SJorge Eduardo Candelaria { 23633a6943dSLaxman Dewangan .name = "ldo5", 23719228a6aSLaxman Dewangan .vin_name = "vcc4", 2387d38a3cbSLaxman Dewangan .n_voltages = 24, 2390651eed5SLaxman Dewangan .enable_time_us = 230, 240a320e3c3SJorge Eduardo Candelaria }, 241a320e3c3SJorge Eduardo Candelaria { 24233a6943dSLaxman Dewangan .name = "ldo6", 24319228a6aSLaxman Dewangan .vin_name = "vcc3", 2447d38a3cbSLaxman Dewangan .n_voltages = 24, 2450651eed5SLaxman Dewangan .enable_time_us = 230, 246a320e3c3SJorge Eduardo Candelaria }, 247a320e3c3SJorge Eduardo Candelaria { 24833a6943dSLaxman Dewangan .name = "ldo7", 24919228a6aSLaxman Dewangan .vin_name = "vcc3", 2507d38a3cbSLaxman Dewangan .n_voltages = 24, 2510651eed5SLaxman Dewangan .enable_time_us = 230, 252a320e3c3SJorge Eduardo Candelaria }, 253a320e3c3SJorge Eduardo Candelaria { 25433a6943dSLaxman Dewangan .name = "ldo8", 25519228a6aSLaxman Dewangan .vin_name = "vcc3", 2567d38a3cbSLaxman Dewangan .n_voltages = 24, 2570651eed5SLaxman Dewangan .enable_time_us = 230, 258a320e3c3SJorge Eduardo Candelaria }, 259a320e3c3SJorge Eduardo Candelaria }; 260a320e3c3SJorge Eduardo Candelaria 2611e0c66f4SLaxman Dewangan #define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits)) 2621e0c66f4SLaxman Dewangan static unsigned int tps65910_ext_sleep_control[] = { 2631e0c66f4SLaxman Dewangan 0, 2641e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VIO, 1, 0), 2651e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDD1, 1, 1), 2661e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDD2, 1, 2), 2671e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDD3, 1, 3), 2681e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDIG1, 0, 1), 2691e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDIG2, 0, 2), 2701e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VPLL, 0, 6), 2711e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDAC, 0, 7), 2721e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VAUX1, 0, 3), 2731e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VAUX2, 0, 4), 2741e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VAUX33, 0, 5), 2751e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VMMC, 0, 0), 2761e0c66f4SLaxman Dewangan }; 2771e0c66f4SLaxman Dewangan 2781e0c66f4SLaxman Dewangan static unsigned int tps65911_ext_sleep_control[] = { 2791e0c66f4SLaxman Dewangan 0, 2801e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VIO, 1, 0), 2811e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDD1, 1, 1), 2821e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDD2, 1, 2), 2831e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3), 2841e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO1, 0, 1), 2851e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO2, 0, 2), 2861e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO3, 0, 7), 2871e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO4, 0, 6), 2881e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO5, 0, 3), 2891e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO6, 0, 0), 2901e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO7, 0, 5), 2911e0c66f4SLaxman Dewangan EXT_CONTROL_REG_BITS(LDO8, 0, 4), 2921e0c66f4SLaxman Dewangan }; 2931e0c66f4SLaxman Dewangan 294518fb721SGraeme Gregory struct tps65910_reg { 29539aa9b6eSAxel Lin struct regulator_desc *desc; 296518fb721SGraeme Gregory struct tps65910 *mfd; 29739aa9b6eSAxel Lin struct regulator_dev **rdev; 29839aa9b6eSAxel Lin struct tps_info **info; 299518fb721SGraeme Gregory struct mutex mutex; 30039aa9b6eSAxel Lin int num_regulators; 301518fb721SGraeme Gregory int mode; 302a320e3c3SJorge Eduardo Candelaria int (*get_ctrl_reg)(int); 3031e0c66f4SLaxman Dewangan unsigned int *ext_sleep_control; 3041e0c66f4SLaxman Dewangan unsigned int board_ext_control[TPS65910_NUM_REGS]; 305518fb721SGraeme Gregory }; 306518fb721SGraeme Gregory 307518fb721SGraeme Gregory static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) 308518fb721SGraeme Gregory { 3093f7e8275SRhyland Klein unsigned int val; 310518fb721SGraeme Gregory int err; 311518fb721SGraeme Gregory 3123f7e8275SRhyland Klein err = tps65910_reg_read(pmic->mfd, reg, &val); 313518fb721SGraeme Gregory if (err) 314518fb721SGraeme Gregory return err; 315518fb721SGraeme Gregory 316518fb721SGraeme Gregory return val; 317518fb721SGraeme Gregory } 318518fb721SGraeme Gregory 319518fb721SGraeme Gregory static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, 320518fb721SGraeme Gregory u8 set_mask, u8 clear_mask) 321518fb721SGraeme Gregory { 322518fb721SGraeme Gregory int err, data; 323518fb721SGraeme Gregory 324518fb721SGraeme Gregory mutex_lock(&pmic->mutex); 325518fb721SGraeme Gregory 326518fb721SGraeme Gregory data = tps65910_read(pmic, reg); 327518fb721SGraeme Gregory if (data < 0) { 328518fb721SGraeme Gregory dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); 329518fb721SGraeme Gregory err = data; 330518fb721SGraeme Gregory goto out; 331518fb721SGraeme Gregory } 332518fb721SGraeme Gregory 333518fb721SGraeme Gregory data &= ~clear_mask; 334518fb721SGraeme Gregory data |= set_mask; 3353f7e8275SRhyland Klein err = tps65910_reg_write(pmic->mfd, reg, data); 336518fb721SGraeme Gregory if (err) 337518fb721SGraeme Gregory dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); 338518fb721SGraeme Gregory 339518fb721SGraeme Gregory out: 340518fb721SGraeme Gregory mutex_unlock(&pmic->mutex); 341518fb721SGraeme Gregory return err; 342518fb721SGraeme Gregory } 343518fb721SGraeme Gregory 3443f7e8275SRhyland Klein static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg) 345518fb721SGraeme Gregory { 346518fb721SGraeme Gregory int data; 347518fb721SGraeme Gregory 348518fb721SGraeme Gregory mutex_lock(&pmic->mutex); 349518fb721SGraeme Gregory 350518fb721SGraeme Gregory data = tps65910_read(pmic, reg); 351518fb721SGraeme Gregory if (data < 0) 352518fb721SGraeme Gregory dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); 353518fb721SGraeme Gregory 354518fb721SGraeme Gregory mutex_unlock(&pmic->mutex); 355518fb721SGraeme Gregory return data; 356518fb721SGraeme Gregory } 357518fb721SGraeme Gregory 3583f7e8275SRhyland Klein static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val) 359518fb721SGraeme Gregory { 360518fb721SGraeme Gregory int err; 361518fb721SGraeme Gregory 362518fb721SGraeme Gregory mutex_lock(&pmic->mutex); 363518fb721SGraeme Gregory 3643f7e8275SRhyland Klein err = tps65910_reg_write(pmic->mfd, reg, val); 365518fb721SGraeme Gregory if (err < 0) 366518fb721SGraeme Gregory dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); 367518fb721SGraeme Gregory 368518fb721SGraeme Gregory mutex_unlock(&pmic->mutex); 369518fb721SGraeme Gregory return err; 370518fb721SGraeme Gregory } 371518fb721SGraeme Gregory 372518fb721SGraeme Gregory static int tps65910_get_ctrl_register(int id) 373518fb721SGraeme Gregory { 374518fb721SGraeme Gregory switch (id) { 375518fb721SGraeme Gregory case TPS65910_REG_VRTC: 376518fb721SGraeme Gregory return TPS65910_VRTC; 377518fb721SGraeme Gregory case TPS65910_REG_VIO: 378518fb721SGraeme Gregory return TPS65910_VIO; 379518fb721SGraeme Gregory case TPS65910_REG_VDD1: 380518fb721SGraeme Gregory return TPS65910_VDD1; 381518fb721SGraeme Gregory case TPS65910_REG_VDD2: 382518fb721SGraeme Gregory return TPS65910_VDD2; 383518fb721SGraeme Gregory case TPS65910_REG_VDD3: 384518fb721SGraeme Gregory return TPS65910_VDD3; 385518fb721SGraeme Gregory case TPS65910_REG_VDIG1: 386518fb721SGraeme Gregory return TPS65910_VDIG1; 387518fb721SGraeme Gregory case TPS65910_REG_VDIG2: 388518fb721SGraeme Gregory return TPS65910_VDIG2; 389518fb721SGraeme Gregory case TPS65910_REG_VPLL: 390518fb721SGraeme Gregory return TPS65910_VPLL; 391518fb721SGraeme Gregory case TPS65910_REG_VDAC: 392518fb721SGraeme Gregory return TPS65910_VDAC; 393518fb721SGraeme Gregory case TPS65910_REG_VAUX1: 394518fb721SGraeme Gregory return TPS65910_VAUX1; 395518fb721SGraeme Gregory case TPS65910_REG_VAUX2: 396518fb721SGraeme Gregory return TPS65910_VAUX2; 397518fb721SGraeme Gregory case TPS65910_REG_VAUX33: 398518fb721SGraeme Gregory return TPS65910_VAUX33; 399518fb721SGraeme Gregory case TPS65910_REG_VMMC: 400518fb721SGraeme Gregory return TPS65910_VMMC; 401518fb721SGraeme Gregory default: 402518fb721SGraeme Gregory return -EINVAL; 403518fb721SGraeme Gregory } 404518fb721SGraeme Gregory } 405518fb721SGraeme Gregory 406a320e3c3SJorge Eduardo Candelaria static int tps65911_get_ctrl_register(int id) 407a320e3c3SJorge Eduardo Candelaria { 408a320e3c3SJorge Eduardo Candelaria switch (id) { 409a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VRTC: 410a320e3c3SJorge Eduardo Candelaria return TPS65910_VRTC; 411a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VIO: 412a320e3c3SJorge Eduardo Candelaria return TPS65910_VIO; 413a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD1: 414a320e3c3SJorge Eduardo Candelaria return TPS65910_VDD1; 415a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD2: 416a320e3c3SJorge Eduardo Candelaria return TPS65910_VDD2; 417a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_VDDCTRL: 418a320e3c3SJorge Eduardo Candelaria return TPS65911_VDDCTRL; 419a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO1: 420a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO1; 421a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO2: 422a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO2; 423a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO3: 424a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO3; 425a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO4: 426a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO4; 427a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO5: 428a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO5; 429a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO6: 430a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO6; 431a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO7: 432a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO7; 433a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO8: 434a320e3c3SJorge Eduardo Candelaria return TPS65911_LDO8; 435a320e3c3SJorge Eduardo Candelaria default: 436a320e3c3SJorge Eduardo Candelaria return -EINVAL; 437a320e3c3SJorge Eduardo Candelaria } 438a320e3c3SJorge Eduardo Candelaria } 439a320e3c3SJorge Eduardo Candelaria 440518fb721SGraeme Gregory static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) 441518fb721SGraeme Gregory { 442518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 443518fb721SGraeme Gregory struct tps65910 *mfd = pmic->mfd; 444518fb721SGraeme Gregory int reg, value, id = rdev_get_id(dev); 445a320e3c3SJorge Eduardo Candelaria 446a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 447518fb721SGraeme Gregory if (reg < 0) 448518fb721SGraeme Gregory return reg; 449518fb721SGraeme Gregory 450518fb721SGraeme Gregory switch (mode) { 451518fb721SGraeme Gregory case REGULATOR_MODE_NORMAL: 452518fb721SGraeme Gregory return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT, 453518fb721SGraeme Gregory LDO_ST_MODE_BIT); 454518fb721SGraeme Gregory case REGULATOR_MODE_IDLE: 455518fb721SGraeme Gregory value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; 4563f7e8275SRhyland Klein return tps65910_reg_set_bits(mfd, reg, value); 457518fb721SGraeme Gregory case REGULATOR_MODE_STANDBY: 4583f7e8275SRhyland Klein return tps65910_reg_clear_bits(mfd, reg, LDO_ST_ON_BIT); 459518fb721SGraeme Gregory } 460518fb721SGraeme Gregory 461518fb721SGraeme Gregory return -EINVAL; 462518fb721SGraeme Gregory } 463518fb721SGraeme Gregory 464518fb721SGraeme Gregory static unsigned int tps65910_get_mode(struct regulator_dev *dev) 465518fb721SGraeme Gregory { 466518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 467518fb721SGraeme Gregory int reg, value, id = rdev_get_id(dev); 468518fb721SGraeme Gregory 469a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 470518fb721SGraeme Gregory if (reg < 0) 471518fb721SGraeme Gregory return reg; 472518fb721SGraeme Gregory 4733f7e8275SRhyland Klein value = tps65910_reg_read_locked(pmic, reg); 474518fb721SGraeme Gregory if (value < 0) 475518fb721SGraeme Gregory return value; 476518fb721SGraeme Gregory 47758599393SAxel Lin if (!(value & LDO_ST_ON_BIT)) 478518fb721SGraeme Gregory return REGULATOR_MODE_STANDBY; 479518fb721SGraeme Gregory else if (value & LDO_ST_MODE_BIT) 480518fb721SGraeme Gregory return REGULATOR_MODE_IDLE; 481518fb721SGraeme Gregory else 482518fb721SGraeme Gregory return REGULATOR_MODE_NORMAL; 483518fb721SGraeme Gregory } 484518fb721SGraeme Gregory 48518039e0fSLaxman Dewangan static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) 486518fb721SGraeme Gregory { 487518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 48818039e0fSLaxman Dewangan int id = rdev_get_id(dev); 489a320e3c3SJorge Eduardo Candelaria int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0; 490518fb721SGraeme Gregory 491518fb721SGraeme Gregory switch (id) { 492518fb721SGraeme Gregory case TPS65910_REG_VDD1: 4933f7e8275SRhyland Klein opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP); 4943f7e8275SRhyland Klein mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1); 495518fb721SGraeme Gregory mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; 4963f7e8275SRhyland Klein srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR); 497518fb721SGraeme Gregory sr = opvsel & VDD1_OP_CMD_MASK; 498518fb721SGraeme Gregory opvsel &= VDD1_OP_SEL_MASK; 499518fb721SGraeme Gregory srvsel &= VDD1_SR_SEL_MASK; 500a320e3c3SJorge Eduardo Candelaria vselmax = 75; 501518fb721SGraeme Gregory break; 502518fb721SGraeme Gregory case TPS65910_REG_VDD2: 5033f7e8275SRhyland Klein opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP); 5043f7e8275SRhyland Klein mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2); 505518fb721SGraeme Gregory mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; 5063f7e8275SRhyland Klein srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR); 507518fb721SGraeme Gregory sr = opvsel & VDD2_OP_CMD_MASK; 508518fb721SGraeme Gregory opvsel &= VDD2_OP_SEL_MASK; 509518fb721SGraeme Gregory srvsel &= VDD2_SR_SEL_MASK; 510a320e3c3SJorge Eduardo Candelaria vselmax = 75; 511a320e3c3SJorge Eduardo Candelaria break; 512a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_VDDCTRL: 5133f7e8275SRhyland Klein opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP); 5143f7e8275SRhyland Klein srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR); 515a320e3c3SJorge Eduardo Candelaria sr = opvsel & VDDCTRL_OP_CMD_MASK; 516a320e3c3SJorge Eduardo Candelaria opvsel &= VDDCTRL_OP_SEL_MASK; 517a320e3c3SJorge Eduardo Candelaria srvsel &= VDDCTRL_SR_SEL_MASK; 518a320e3c3SJorge Eduardo Candelaria vselmax = 64; 519518fb721SGraeme Gregory break; 520518fb721SGraeme Gregory } 521518fb721SGraeme Gregory 522518fb721SGraeme Gregory /* multiplier 0 == 1 but 2,3 normal */ 523518fb721SGraeme Gregory if (!mult) 524518fb721SGraeme Gregory mult=1; 525518fb721SGraeme Gregory 526518fb721SGraeme Gregory if (sr) { 527a320e3c3SJorge Eduardo Candelaria /* normalise to valid range */ 528a320e3c3SJorge Eduardo Candelaria if (srvsel < 3) 529a320e3c3SJorge Eduardo Candelaria srvsel = 3; 530a320e3c3SJorge Eduardo Candelaria if (srvsel > vselmax) 531a320e3c3SJorge Eduardo Candelaria srvsel = vselmax; 53218039e0fSLaxman Dewangan return srvsel - 3; 533518fb721SGraeme Gregory } else { 534518fb721SGraeme Gregory 535a320e3c3SJorge Eduardo Candelaria /* normalise to valid range*/ 536a320e3c3SJorge Eduardo Candelaria if (opvsel < 3) 537a320e3c3SJorge Eduardo Candelaria opvsel = 3; 538a320e3c3SJorge Eduardo Candelaria if (opvsel > vselmax) 539a320e3c3SJorge Eduardo Candelaria opvsel = vselmax; 54018039e0fSLaxman Dewangan return opvsel - 3; 541518fb721SGraeme Gregory } 54218039e0fSLaxman Dewangan return -EINVAL; 543518fb721SGraeme Gregory } 544518fb721SGraeme Gregory 5451f904fd1SAxel Lin static int tps65910_get_voltage_sel(struct regulator_dev *dev) 546518fb721SGraeme Gregory { 547518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 5481f904fd1SAxel Lin int reg, value, id = rdev_get_id(dev); 549518fb721SGraeme Gregory 550a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 551518fb721SGraeme Gregory if (reg < 0) 552518fb721SGraeme Gregory return reg; 553518fb721SGraeme Gregory 5543f7e8275SRhyland Klein value = tps65910_reg_read_locked(pmic, reg); 555518fb721SGraeme Gregory if (value < 0) 556518fb721SGraeme Gregory return value; 557518fb721SGraeme Gregory 558518fb721SGraeme Gregory switch (id) { 559518fb721SGraeme Gregory case TPS65910_REG_VIO: 560518fb721SGraeme Gregory case TPS65910_REG_VDIG1: 561518fb721SGraeme Gregory case TPS65910_REG_VDIG2: 562518fb721SGraeme Gregory case TPS65910_REG_VPLL: 563518fb721SGraeme Gregory case TPS65910_REG_VDAC: 564518fb721SGraeme Gregory case TPS65910_REG_VAUX1: 565518fb721SGraeme Gregory case TPS65910_REG_VAUX2: 566518fb721SGraeme Gregory case TPS65910_REG_VAUX33: 567518fb721SGraeme Gregory case TPS65910_REG_VMMC: 568518fb721SGraeme Gregory value &= LDO_SEL_MASK; 569518fb721SGraeme Gregory value >>= LDO_SEL_SHIFT; 570518fb721SGraeme Gregory break; 571518fb721SGraeme Gregory default: 572518fb721SGraeme Gregory return -EINVAL; 573518fb721SGraeme Gregory } 574518fb721SGraeme Gregory 5751f904fd1SAxel Lin return value; 576518fb721SGraeme Gregory } 577518fb721SGraeme Gregory 578518fb721SGraeme Gregory static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) 579518fb721SGraeme Gregory { 580d9fe28f9SAxel Lin return dev->desc->volt_table[0]; 581518fb721SGraeme Gregory } 582518fb721SGraeme Gregory 5831f904fd1SAxel Lin static int tps65911_get_voltage_sel(struct regulator_dev *dev) 584a320e3c3SJorge Eduardo Candelaria { 585a320e3c3SJorge Eduardo Candelaria struct tps65910_reg *pmic = rdev_get_drvdata(dev); 5861f904fd1SAxel Lin int id = rdev_get_id(dev); 587a320e3c3SJorge Eduardo Candelaria u8 value, reg; 588a320e3c3SJorge Eduardo Candelaria 589a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 590a320e3c3SJorge Eduardo Candelaria 5913f7e8275SRhyland Klein value = tps65910_reg_read_locked(pmic, reg); 592a320e3c3SJorge Eduardo Candelaria 593a320e3c3SJorge Eduardo Candelaria switch (id) { 594a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO1: 595a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO2: 596a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO4: 597a320e3c3SJorge Eduardo Candelaria value &= LDO1_SEL_MASK; 598a320e3c3SJorge Eduardo Candelaria value >>= LDO_SEL_SHIFT; 599a320e3c3SJorge Eduardo Candelaria break; 600a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO3: 601a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO5: 602a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO6: 603a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO7: 604a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO8: 605a320e3c3SJorge Eduardo Candelaria value &= LDO3_SEL_MASK; 606a320e3c3SJorge Eduardo Candelaria value >>= LDO_SEL_SHIFT; 607a320e3c3SJorge Eduardo Candelaria break; 608a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VIO: 609e882eae8SLaxman Dewangan value &= LDO_SEL_MASK; 610e882eae8SLaxman Dewangan value >>= LDO_SEL_SHIFT; 6111f904fd1SAxel Lin break; 612a320e3c3SJorge Eduardo Candelaria default: 613a320e3c3SJorge Eduardo Candelaria return -EINVAL; 614a320e3c3SJorge Eduardo Candelaria } 615a320e3c3SJorge Eduardo Candelaria 6161f904fd1SAxel Lin return value; 617a320e3c3SJorge Eduardo Candelaria } 618a320e3c3SJorge Eduardo Candelaria 61994732b97SAxel Lin static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, 620518fb721SGraeme Gregory unsigned selector) 621518fb721SGraeme Gregory { 622518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 623518fb721SGraeme Gregory int id = rdev_get_id(dev), vsel; 624a320e3c3SJorge Eduardo Candelaria int dcdc_mult = 0; 625518fb721SGraeme Gregory 626a320e3c3SJorge Eduardo Candelaria switch (id) { 627a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD1: 628780dc9baSAfzal Mohammed dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; 629a320e3c3SJorge Eduardo Candelaria if (dcdc_mult == 1) 630a320e3c3SJorge Eduardo Candelaria dcdc_mult--; 631780dc9baSAfzal Mohammed vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; 632518fb721SGraeme Gregory 633518fb721SGraeme Gregory tps65910_modify_bits(pmic, TPS65910_VDD1, 634518fb721SGraeme Gregory (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), 635518fb721SGraeme Gregory VDD1_VGAIN_SEL_MASK); 6363f7e8275SRhyland Klein tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel); 637a320e3c3SJorge Eduardo Candelaria break; 638a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD2: 639780dc9baSAfzal Mohammed dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; 640a320e3c3SJorge Eduardo Candelaria if (dcdc_mult == 1) 641a320e3c3SJorge Eduardo Candelaria dcdc_mult--; 642780dc9baSAfzal Mohammed vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; 643a320e3c3SJorge Eduardo Candelaria 644518fb721SGraeme Gregory tps65910_modify_bits(pmic, TPS65910_VDD2, 645518fb721SGraeme Gregory (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), 646518fb721SGraeme Gregory VDD1_VGAIN_SEL_MASK); 6473f7e8275SRhyland Klein tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel); 648a320e3c3SJorge Eduardo Candelaria break; 649a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_VDDCTRL: 650c4632aedSLaxman Dewangan vsel = selector + 3; 6513f7e8275SRhyland Klein tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel); 652518fb721SGraeme Gregory } 653518fb721SGraeme Gregory 654518fb721SGraeme Gregory return 0; 655518fb721SGraeme Gregory } 656518fb721SGraeme Gregory 65794732b97SAxel Lin static int tps65910_set_voltage_sel(struct regulator_dev *dev, 65894732b97SAxel Lin unsigned selector) 659518fb721SGraeme Gregory { 660518fb721SGraeme Gregory struct tps65910_reg *pmic = rdev_get_drvdata(dev); 661518fb721SGraeme Gregory int reg, id = rdev_get_id(dev); 662518fb721SGraeme Gregory 663a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 664518fb721SGraeme Gregory if (reg < 0) 665518fb721SGraeme Gregory return reg; 666518fb721SGraeme Gregory 667518fb721SGraeme Gregory switch (id) { 668518fb721SGraeme Gregory case TPS65910_REG_VIO: 669518fb721SGraeme Gregory case TPS65910_REG_VDIG1: 670518fb721SGraeme Gregory case TPS65910_REG_VDIG2: 671518fb721SGraeme Gregory case TPS65910_REG_VPLL: 672518fb721SGraeme Gregory case TPS65910_REG_VDAC: 673518fb721SGraeme Gregory case TPS65910_REG_VAUX1: 674518fb721SGraeme Gregory case TPS65910_REG_VAUX2: 675518fb721SGraeme Gregory case TPS65910_REG_VAUX33: 676518fb721SGraeme Gregory case TPS65910_REG_VMMC: 677518fb721SGraeme Gregory return tps65910_modify_bits(pmic, reg, 678518fb721SGraeme Gregory (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); 679518fb721SGraeme Gregory } 680518fb721SGraeme Gregory 681518fb721SGraeme Gregory return -EINVAL; 682518fb721SGraeme Gregory } 683518fb721SGraeme Gregory 68494732b97SAxel Lin static int tps65911_set_voltage_sel(struct regulator_dev *dev, 68594732b97SAxel Lin unsigned selector) 686a320e3c3SJorge Eduardo Candelaria { 687a320e3c3SJorge Eduardo Candelaria struct tps65910_reg *pmic = rdev_get_drvdata(dev); 688a320e3c3SJorge Eduardo Candelaria int reg, id = rdev_get_id(dev); 689a320e3c3SJorge Eduardo Candelaria 690a320e3c3SJorge Eduardo Candelaria reg = pmic->get_ctrl_reg(id); 691a320e3c3SJorge Eduardo Candelaria if (reg < 0) 692a320e3c3SJorge Eduardo Candelaria return reg; 693a320e3c3SJorge Eduardo Candelaria 694a320e3c3SJorge Eduardo Candelaria switch (id) { 695a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO1: 696a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO2: 697a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO4: 698a320e3c3SJorge Eduardo Candelaria return tps65910_modify_bits(pmic, reg, 699a320e3c3SJorge Eduardo Candelaria (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK); 700a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO3: 701a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO5: 702a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO6: 703a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO7: 704a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO8: 705a320e3c3SJorge Eduardo Candelaria return tps65910_modify_bits(pmic, reg, 706a320e3c3SJorge Eduardo Candelaria (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK); 707e882eae8SLaxman Dewangan case TPS65910_REG_VIO: 708e882eae8SLaxman Dewangan return tps65910_modify_bits(pmic, reg, 709e882eae8SLaxman Dewangan (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); 710a320e3c3SJorge Eduardo Candelaria } 711a320e3c3SJorge Eduardo Candelaria 712a320e3c3SJorge Eduardo Candelaria return -EINVAL; 713a320e3c3SJorge Eduardo Candelaria } 714a320e3c3SJorge Eduardo Candelaria 715a320e3c3SJorge Eduardo Candelaria 716518fb721SGraeme Gregory static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, 717518fb721SGraeme Gregory unsigned selector) 718518fb721SGraeme Gregory { 719a320e3c3SJorge Eduardo Candelaria int volt, mult = 1, id = rdev_get_id(dev); 720518fb721SGraeme Gregory 721a320e3c3SJorge Eduardo Candelaria switch (id) { 722a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD1: 723a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VDD2: 724780dc9baSAfzal Mohammed mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; 725a320e3c3SJorge Eduardo Candelaria volt = VDD1_2_MIN_VOLT + 726780dc9baSAfzal Mohammed (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; 727d04156bcSAxel Lin break; 728a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_VDDCTRL: 729a320e3c3SJorge Eduardo Candelaria volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); 730d04156bcSAxel Lin break; 731d04156bcSAxel Lin default: 732d04156bcSAxel Lin BUG(); 733d04156bcSAxel Lin return -EINVAL; 734a320e3c3SJorge Eduardo Candelaria } 735518fb721SGraeme Gregory 736518fb721SGraeme Gregory return volt * 100 * mult; 737518fb721SGraeme Gregory } 738518fb721SGraeme Gregory 739a320e3c3SJorge Eduardo Candelaria static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) 740a320e3c3SJorge Eduardo Candelaria { 741a320e3c3SJorge Eduardo Candelaria struct tps65910_reg *pmic = rdev_get_drvdata(dev); 742a320e3c3SJorge Eduardo Candelaria int step_mv = 0, id = rdev_get_id(dev); 743a320e3c3SJorge Eduardo Candelaria 744a320e3c3SJorge Eduardo Candelaria switch(id) { 745a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO1: 746a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO2: 747a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO4: 748a320e3c3SJorge Eduardo Candelaria /* The first 5 values of the selector correspond to 1V */ 749a320e3c3SJorge Eduardo Candelaria if (selector < 5) 750a320e3c3SJorge Eduardo Candelaria selector = 0; 751a320e3c3SJorge Eduardo Candelaria else 752a320e3c3SJorge Eduardo Candelaria selector -= 4; 753a320e3c3SJorge Eduardo Candelaria 754a320e3c3SJorge Eduardo Candelaria step_mv = 50; 755a320e3c3SJorge Eduardo Candelaria break; 756a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO3: 757a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO5: 758a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO6: 759a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO7: 760a320e3c3SJorge Eduardo Candelaria case TPS65911_REG_LDO8: 761a320e3c3SJorge Eduardo Candelaria /* The first 3 values of the selector correspond to 1V */ 762a320e3c3SJorge Eduardo Candelaria if (selector < 3) 763a320e3c3SJorge Eduardo Candelaria selector = 0; 764a320e3c3SJorge Eduardo Candelaria else 765a320e3c3SJorge Eduardo Candelaria selector -= 2; 766a320e3c3SJorge Eduardo Candelaria 767a320e3c3SJorge Eduardo Candelaria step_mv = 100; 768a320e3c3SJorge Eduardo Candelaria break; 769a320e3c3SJorge Eduardo Candelaria case TPS65910_REG_VIO: 770d9fe28f9SAxel Lin return pmic->info[id]->voltage_table[selector]; 771a320e3c3SJorge Eduardo Candelaria default: 772a320e3c3SJorge Eduardo Candelaria return -EINVAL; 773a320e3c3SJorge Eduardo Candelaria } 774a320e3c3SJorge Eduardo Candelaria 775a320e3c3SJorge Eduardo Candelaria return (LDO_MIN_VOLT + selector * step_mv) * 1000; 776a320e3c3SJorge Eduardo Candelaria } 777a320e3c3SJorge Eduardo Candelaria 778518fb721SGraeme Gregory /* Regulator ops (except VRTC) */ 779518fb721SGraeme Gregory static struct regulator_ops tps65910_ops_dcdc = { 780a40a9c43SAxel Lin .is_enabled = regulator_is_enabled_regmap, 781a40a9c43SAxel Lin .enable = regulator_enable_regmap, 782a40a9c43SAxel Lin .disable = regulator_disable_regmap, 783518fb721SGraeme Gregory .set_mode = tps65910_set_mode, 784518fb721SGraeme Gregory .get_mode = tps65910_get_mode, 78518039e0fSLaxman Dewangan .get_voltage_sel = tps65910_get_voltage_dcdc_sel, 78694732b97SAxel Lin .set_voltage_sel = tps65910_set_voltage_dcdc_sel, 78701bc3a14SAxel Lin .set_voltage_time_sel = regulator_set_voltage_time_sel, 788518fb721SGraeme Gregory .list_voltage = tps65910_list_voltage_dcdc, 789518fb721SGraeme Gregory }; 790518fb721SGraeme Gregory 791518fb721SGraeme Gregory static struct regulator_ops tps65910_ops_vdd3 = { 792a40a9c43SAxel Lin .is_enabled = regulator_is_enabled_regmap, 793a40a9c43SAxel Lin .enable = regulator_enable_regmap, 794a40a9c43SAxel Lin .disable = regulator_disable_regmap, 795518fb721SGraeme Gregory .set_mode = tps65910_set_mode, 796518fb721SGraeme Gregory .get_mode = tps65910_get_mode, 797518fb721SGraeme Gregory .get_voltage = tps65910_get_voltage_vdd3, 798d9fe28f9SAxel Lin .list_voltage = regulator_list_voltage_table, 799518fb721SGraeme Gregory }; 800518fb721SGraeme Gregory 801518fb721SGraeme Gregory static struct regulator_ops tps65910_ops = { 802a40a9c43SAxel Lin .is_enabled = regulator_is_enabled_regmap, 803a40a9c43SAxel Lin .enable = regulator_enable_regmap, 804a40a9c43SAxel Lin .disable = regulator_disable_regmap, 805518fb721SGraeme Gregory .set_mode = tps65910_set_mode, 806518fb721SGraeme Gregory .get_mode = tps65910_get_mode, 8071f904fd1SAxel Lin .get_voltage_sel = tps65910_get_voltage_sel, 80894732b97SAxel Lin .set_voltage_sel = tps65910_set_voltage_sel, 809d9fe28f9SAxel Lin .list_voltage = regulator_list_voltage_table, 810518fb721SGraeme Gregory }; 811518fb721SGraeme Gregory 812a320e3c3SJorge Eduardo Candelaria static struct regulator_ops tps65911_ops = { 813a40a9c43SAxel Lin .is_enabled = regulator_is_enabled_regmap, 814a40a9c43SAxel Lin .enable = regulator_enable_regmap, 815a40a9c43SAxel Lin .disable = regulator_disable_regmap, 816a320e3c3SJorge Eduardo Candelaria .set_mode = tps65910_set_mode, 817a320e3c3SJorge Eduardo Candelaria .get_mode = tps65910_get_mode, 8181f904fd1SAxel Lin .get_voltage_sel = tps65911_get_voltage_sel, 81994732b97SAxel Lin .set_voltage_sel = tps65911_set_voltage_sel, 820a320e3c3SJorge Eduardo Candelaria .list_voltage = tps65911_list_voltage, 821a320e3c3SJorge Eduardo Candelaria }; 822a320e3c3SJorge Eduardo Candelaria 8231e0c66f4SLaxman Dewangan static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, 8241e0c66f4SLaxman Dewangan int id, int ext_sleep_config) 8251e0c66f4SLaxman Dewangan { 8261e0c66f4SLaxman Dewangan struct tps65910 *mfd = pmic->mfd; 8271e0c66f4SLaxman Dewangan u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF; 8281e0c66f4SLaxman Dewangan u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF); 8291e0c66f4SLaxman Dewangan int ret; 8301e0c66f4SLaxman Dewangan 8311e0c66f4SLaxman Dewangan /* 8321e0c66f4SLaxman Dewangan * Regulator can not be control from multiple external input EN1, EN2 8331e0c66f4SLaxman Dewangan * and EN3 together. 8341e0c66f4SLaxman Dewangan */ 8351e0c66f4SLaxman Dewangan if (ext_sleep_config & EXT_SLEEP_CONTROL) { 8361e0c66f4SLaxman Dewangan int en_count; 8371e0c66f4SLaxman Dewangan en_count = ((ext_sleep_config & 8381e0c66f4SLaxman Dewangan TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0); 8391e0c66f4SLaxman Dewangan en_count += ((ext_sleep_config & 8401e0c66f4SLaxman Dewangan TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0); 8411e0c66f4SLaxman Dewangan en_count += ((ext_sleep_config & 8421e0c66f4SLaxman Dewangan TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0); 843f30b0716SLaxman Dewangan en_count += ((ext_sleep_config & 844f30b0716SLaxman Dewangan TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0); 8451e0c66f4SLaxman Dewangan if (en_count > 1) { 8461e0c66f4SLaxman Dewangan dev_err(mfd->dev, 8471e0c66f4SLaxman Dewangan "External sleep control flag is not proper\n"); 8481e0c66f4SLaxman Dewangan return -EINVAL; 8491e0c66f4SLaxman Dewangan } 8501e0c66f4SLaxman Dewangan } 8511e0c66f4SLaxman Dewangan 8521e0c66f4SLaxman Dewangan pmic->board_ext_control[id] = ext_sleep_config; 8531e0c66f4SLaxman Dewangan 8541e0c66f4SLaxman Dewangan /* External EN1 control */ 8551e0c66f4SLaxman Dewangan if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) 8563f7e8275SRhyland Klein ret = tps65910_reg_set_bits(mfd, 8571e0c66f4SLaxman Dewangan TPS65910_EN1_LDO_ASS + regoffs, bit_pos); 8581e0c66f4SLaxman Dewangan else 8593f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 8601e0c66f4SLaxman Dewangan TPS65910_EN1_LDO_ASS + regoffs, bit_pos); 8611e0c66f4SLaxman Dewangan if (ret < 0) { 8621e0c66f4SLaxman Dewangan dev_err(mfd->dev, 8631e0c66f4SLaxman Dewangan "Error in configuring external control EN1\n"); 8641e0c66f4SLaxman Dewangan return ret; 8651e0c66f4SLaxman Dewangan } 8661e0c66f4SLaxman Dewangan 8671e0c66f4SLaxman Dewangan /* External EN2 control */ 8681e0c66f4SLaxman Dewangan if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) 8693f7e8275SRhyland Klein ret = tps65910_reg_set_bits(mfd, 8701e0c66f4SLaxman Dewangan TPS65910_EN2_LDO_ASS + regoffs, bit_pos); 8711e0c66f4SLaxman Dewangan else 8723f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 8731e0c66f4SLaxman Dewangan TPS65910_EN2_LDO_ASS + regoffs, bit_pos); 8741e0c66f4SLaxman Dewangan if (ret < 0) { 8751e0c66f4SLaxman Dewangan dev_err(mfd->dev, 8761e0c66f4SLaxman Dewangan "Error in configuring external control EN2\n"); 8771e0c66f4SLaxman Dewangan return ret; 8781e0c66f4SLaxman Dewangan } 8791e0c66f4SLaxman Dewangan 8801e0c66f4SLaxman Dewangan /* External EN3 control for TPS65910 LDO only */ 8811e0c66f4SLaxman Dewangan if ((tps65910_chip_id(mfd) == TPS65910) && 8821e0c66f4SLaxman Dewangan (id >= TPS65910_REG_VDIG1)) { 8831e0c66f4SLaxman Dewangan if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) 8843f7e8275SRhyland Klein ret = tps65910_reg_set_bits(mfd, 8851e0c66f4SLaxman Dewangan TPS65910_EN3_LDO_ASS + regoffs, bit_pos); 8861e0c66f4SLaxman Dewangan else 8873f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 8881e0c66f4SLaxman Dewangan TPS65910_EN3_LDO_ASS + regoffs, bit_pos); 8891e0c66f4SLaxman Dewangan if (ret < 0) { 8901e0c66f4SLaxman Dewangan dev_err(mfd->dev, 8911e0c66f4SLaxman Dewangan "Error in configuring external control EN3\n"); 8921e0c66f4SLaxman Dewangan return ret; 8931e0c66f4SLaxman Dewangan } 8941e0c66f4SLaxman Dewangan } 8951e0c66f4SLaxman Dewangan 8961e0c66f4SLaxman Dewangan /* Return if no external control is selected */ 8971e0c66f4SLaxman Dewangan if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { 8981e0c66f4SLaxman Dewangan /* Clear all sleep controls */ 8993f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 9001e0c66f4SLaxman Dewangan TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); 9011e0c66f4SLaxman Dewangan if (!ret) 9023f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 9031e0c66f4SLaxman Dewangan TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); 9041e0c66f4SLaxman Dewangan if (ret < 0) 9051e0c66f4SLaxman Dewangan dev_err(mfd->dev, 9061e0c66f4SLaxman Dewangan "Error in configuring SLEEP register\n"); 9071e0c66f4SLaxman Dewangan return ret; 9081e0c66f4SLaxman Dewangan } 9091e0c66f4SLaxman Dewangan 9101e0c66f4SLaxman Dewangan /* 9111e0c66f4SLaxman Dewangan * For regulator that has separate operational and sleep register make 9121e0c66f4SLaxman Dewangan * sure that operational is used and clear sleep register to turn 9131e0c66f4SLaxman Dewangan * regulator off when external control is inactive 9141e0c66f4SLaxman Dewangan */ 9151e0c66f4SLaxman Dewangan if ((id == TPS65910_REG_VDD1) || 9161e0c66f4SLaxman Dewangan (id == TPS65910_REG_VDD2) || 9171e0c66f4SLaxman Dewangan ((id == TPS65911_REG_VDDCTRL) && 9181e0c66f4SLaxman Dewangan (tps65910_chip_id(mfd) == TPS65911))) { 9191e0c66f4SLaxman Dewangan int op_reg_add = pmic->get_ctrl_reg(id) + 1; 9201e0c66f4SLaxman Dewangan int sr_reg_add = pmic->get_ctrl_reg(id) + 2; 9213f7e8275SRhyland Klein int opvsel = tps65910_reg_read_locked(pmic, op_reg_add); 9223f7e8275SRhyland Klein int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add); 9231e0c66f4SLaxman Dewangan if (opvsel & VDD1_OP_CMD_MASK) { 9241e0c66f4SLaxman Dewangan u8 reg_val = srvsel & VDD1_OP_SEL_MASK; 9253f7e8275SRhyland Klein ret = tps65910_reg_write_locked(pmic, op_reg_add, 9263f7e8275SRhyland Klein reg_val); 9271e0c66f4SLaxman Dewangan if (ret < 0) { 9281e0c66f4SLaxman Dewangan dev_err(mfd->dev, 9291e0c66f4SLaxman Dewangan "Error in configuring op register\n"); 9301e0c66f4SLaxman Dewangan return ret; 9311e0c66f4SLaxman Dewangan } 9321e0c66f4SLaxman Dewangan } 9333f7e8275SRhyland Klein ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0); 9341e0c66f4SLaxman Dewangan if (ret < 0) { 9351e0c66f4SLaxman Dewangan dev_err(mfd->dev, "Error in settting sr register\n"); 9361e0c66f4SLaxman Dewangan return ret; 9371e0c66f4SLaxman Dewangan } 9381e0c66f4SLaxman Dewangan } 9391e0c66f4SLaxman Dewangan 9403f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 9411e0c66f4SLaxman Dewangan TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); 942f30b0716SLaxman Dewangan if (!ret) { 943f30b0716SLaxman Dewangan if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) 9443f7e8275SRhyland Klein ret = tps65910_reg_set_bits(mfd, 9451e0c66f4SLaxman Dewangan TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); 946f30b0716SLaxman Dewangan else 9473f7e8275SRhyland Klein ret = tps65910_reg_clear_bits(mfd, 948f30b0716SLaxman Dewangan TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); 949f30b0716SLaxman Dewangan } 9501e0c66f4SLaxman Dewangan if (ret < 0) 9511e0c66f4SLaxman Dewangan dev_err(mfd->dev, 9521e0c66f4SLaxman Dewangan "Error in configuring SLEEP register\n"); 953f30b0716SLaxman Dewangan 9541e0c66f4SLaxman Dewangan return ret; 9551e0c66f4SLaxman Dewangan } 9561e0c66f4SLaxman Dewangan 9576790178fSRhyland Klein #ifdef CONFIG_OF 9586790178fSRhyland Klein 9596790178fSRhyland Klein static struct of_regulator_match tps65910_matches[] = { 96033a6943dSLaxman Dewangan { .name = "vrtc", .driver_data = (void *) &tps65910_regs[0] }, 96133a6943dSLaxman Dewangan { .name = "vio", .driver_data = (void *) &tps65910_regs[1] }, 96233a6943dSLaxman Dewangan { .name = "vdd1", .driver_data = (void *) &tps65910_regs[2] }, 96333a6943dSLaxman Dewangan { .name = "vdd2", .driver_data = (void *) &tps65910_regs[3] }, 96433a6943dSLaxman Dewangan { .name = "vdd3", .driver_data = (void *) &tps65910_regs[4] }, 96533a6943dSLaxman Dewangan { .name = "vdig1", .driver_data = (void *) &tps65910_regs[5] }, 96633a6943dSLaxman Dewangan { .name = "vdig2", .driver_data = (void *) &tps65910_regs[6] }, 96733a6943dSLaxman Dewangan { .name = "vpll", .driver_data = (void *) &tps65910_regs[7] }, 96833a6943dSLaxman Dewangan { .name = "vdac", .driver_data = (void *) &tps65910_regs[8] }, 96933a6943dSLaxman Dewangan { .name = "vaux1", .driver_data = (void *) &tps65910_regs[9] }, 97033a6943dSLaxman Dewangan { .name = "vaux2", .driver_data = (void *) &tps65910_regs[10] }, 97133a6943dSLaxman Dewangan { .name = "vaux33", .driver_data = (void *) &tps65910_regs[11] }, 97233a6943dSLaxman Dewangan { .name = "vmmc", .driver_data = (void *) &tps65910_regs[12] }, 9736790178fSRhyland Klein }; 9746790178fSRhyland Klein 9756790178fSRhyland Klein static struct of_regulator_match tps65911_matches[] = { 97633a6943dSLaxman Dewangan { .name = "vrtc", .driver_data = (void *) &tps65911_regs[0] }, 97733a6943dSLaxman Dewangan { .name = "vio", .driver_data = (void *) &tps65911_regs[1] }, 97833a6943dSLaxman Dewangan { .name = "vdd1", .driver_data = (void *) &tps65911_regs[2] }, 97933a6943dSLaxman Dewangan { .name = "vdd2", .driver_data = (void *) &tps65911_regs[3] }, 98033a6943dSLaxman Dewangan { .name = "vddctrl", .driver_data = (void *) &tps65911_regs[4] }, 98133a6943dSLaxman Dewangan { .name = "ldo1", .driver_data = (void *) &tps65911_regs[5] }, 98233a6943dSLaxman Dewangan { .name = "ldo2", .driver_data = (void *) &tps65911_regs[6] }, 98333a6943dSLaxman Dewangan { .name = "ldo3", .driver_data = (void *) &tps65911_regs[7] }, 98433a6943dSLaxman Dewangan { .name = "ldo4", .driver_data = (void *) &tps65911_regs[8] }, 98533a6943dSLaxman Dewangan { .name = "ldo5", .driver_data = (void *) &tps65911_regs[9] }, 98633a6943dSLaxman Dewangan { .name = "ldo6", .driver_data = (void *) &tps65911_regs[10] }, 98733a6943dSLaxman Dewangan { .name = "ldo7", .driver_data = (void *) &tps65911_regs[11] }, 98833a6943dSLaxman Dewangan { .name = "ldo8", .driver_data = (void *) &tps65911_regs[12] }, 9896790178fSRhyland Klein }; 9906790178fSRhyland Klein 9916790178fSRhyland Klein static struct tps65910_board *tps65910_parse_dt_reg_data( 99284df8c12SLaxman Dewangan struct platform_device *pdev, 99384df8c12SLaxman Dewangan struct of_regulator_match **tps65910_reg_matches) 9946790178fSRhyland Klein { 9956790178fSRhyland Klein struct tps65910_board *pmic_plat_data; 9966790178fSRhyland Klein struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 9976790178fSRhyland Klein struct device_node *np = pdev->dev.parent->of_node; 9986790178fSRhyland Klein struct device_node *regulators; 9996790178fSRhyland Klein struct of_regulator_match *matches; 10006790178fSRhyland Klein unsigned int prop; 10016790178fSRhyland Klein int idx = 0, ret, count; 10026790178fSRhyland Klein 10036790178fSRhyland Klein pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data), 10046790178fSRhyland Klein GFP_KERNEL); 10056790178fSRhyland Klein 10066790178fSRhyland Klein if (!pmic_plat_data) { 10076790178fSRhyland Klein dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); 10086790178fSRhyland Klein return NULL; 10096790178fSRhyland Klein } 10106790178fSRhyland Klein 10116790178fSRhyland Klein regulators = of_find_node_by_name(np, "regulators"); 101292ab953bSLaxman Dewangan if (!regulators) { 101392ab953bSLaxman Dewangan dev_err(&pdev->dev, "regulator node not found\n"); 101492ab953bSLaxman Dewangan return NULL; 101592ab953bSLaxman Dewangan } 10166790178fSRhyland Klein 10176790178fSRhyland Klein switch (tps65910_chip_id(tps65910)) { 10186790178fSRhyland Klein case TPS65910: 10196790178fSRhyland Klein count = ARRAY_SIZE(tps65910_matches); 10206790178fSRhyland Klein matches = tps65910_matches; 10216790178fSRhyland Klein break; 10226790178fSRhyland Klein case TPS65911: 10236790178fSRhyland Klein count = ARRAY_SIZE(tps65911_matches); 10246790178fSRhyland Klein matches = tps65911_matches; 10256790178fSRhyland Klein break; 10266790178fSRhyland Klein default: 10277e9a57e6SLaxman Dewangan dev_err(&pdev->dev, "Invalid tps chip version\n"); 10286790178fSRhyland Klein return NULL; 10296790178fSRhyland Klein } 10306790178fSRhyland Klein 10316790178fSRhyland Klein ret = of_regulator_match(pdev->dev.parent, regulators, matches, count); 10326790178fSRhyland Klein if (ret < 0) { 10336790178fSRhyland Klein dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", 10346790178fSRhyland Klein ret); 10356790178fSRhyland Klein return NULL; 10366790178fSRhyland Klein } 10376790178fSRhyland Klein 103884df8c12SLaxman Dewangan *tps65910_reg_matches = matches; 103984df8c12SLaxman Dewangan 10406790178fSRhyland Klein for (idx = 0; idx < count; idx++) { 104119228a6aSLaxman Dewangan struct tps_info *info = matches[idx].driver_data; 104219228a6aSLaxman Dewangan char in_supply[32]; /* 32 is max size of property name */ 104319228a6aSLaxman Dewangan 10446790178fSRhyland Klein if (!matches[idx].init_data || !matches[idx].of_node) 10456790178fSRhyland Klein continue; 10466790178fSRhyland Klein 10476790178fSRhyland Klein pmic_plat_data->tps65910_pmic_init_data[idx] = 10486790178fSRhyland Klein matches[idx].init_data; 10496790178fSRhyland Klein 10506790178fSRhyland Klein ret = of_property_read_u32(matches[idx].of_node, 10516790178fSRhyland Klein "ti,regulator-ext-sleep-control", &prop); 10526790178fSRhyland Klein if (!ret) 10536790178fSRhyland Klein pmic_plat_data->regulator_ext_sleep_control[idx] = prop; 105419228a6aSLaxman Dewangan 105519228a6aSLaxman Dewangan if (info->vin_name) { 105619228a6aSLaxman Dewangan snprintf(in_supply, 32, "%s-supply", info->vin_name); 105719228a6aSLaxman Dewangan if (of_find_property(np, in_supply, 0)) 105819228a6aSLaxman Dewangan pmic_plat_data->input_supply[idx] = 105919228a6aSLaxman Dewangan info->vin_name; 106019228a6aSLaxman Dewangan } 10616790178fSRhyland Klein } 10626790178fSRhyland Klein 10636790178fSRhyland Klein return pmic_plat_data; 10646790178fSRhyland Klein } 10656790178fSRhyland Klein #else 10666790178fSRhyland Klein static inline struct tps65910_board *tps65910_parse_dt_reg_data( 106784df8c12SLaxman Dewangan struct platform_device *pdev, 106884df8c12SLaxman Dewangan struct of_regulator_match **tps65910_reg_matches) 10696790178fSRhyland Klein { 107084df8c12SLaxman Dewangan *tps65910_reg_matches = NULL; 107174ea0e59SMark Brown return NULL; 10726790178fSRhyland Klein } 10736790178fSRhyland Klein #endif 10746790178fSRhyland Klein 1075518fb721SGraeme Gregory static __devinit int tps65910_probe(struct platform_device *pdev) 1076518fb721SGraeme Gregory { 1077518fb721SGraeme Gregory struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 1078c172708dSMark Brown struct regulator_config config = { }; 1079a320e3c3SJorge Eduardo Candelaria struct tps_info *info; 1080518fb721SGraeme Gregory struct regulator_init_data *reg_data; 1081518fb721SGraeme Gregory struct regulator_dev *rdev; 1082518fb721SGraeme Gregory struct tps65910_reg *pmic; 1083518fb721SGraeme Gregory struct tps65910_board *pmic_plat_data; 108484df8c12SLaxman Dewangan struct of_regulator_match *tps65910_reg_matches = NULL; 1085518fb721SGraeme Gregory int i, err; 1086518fb721SGraeme Gregory 1087518fb721SGraeme Gregory pmic_plat_data = dev_get_platdata(tps65910->dev); 10886790178fSRhyland Klein if (!pmic_plat_data && tps65910->dev->of_node) 108984df8c12SLaxman Dewangan pmic_plat_data = tps65910_parse_dt_reg_data(pdev, 109084df8c12SLaxman Dewangan &tps65910_reg_matches); 10916790178fSRhyland Klein 10927e9a57e6SLaxman Dewangan if (!pmic_plat_data) { 10937e9a57e6SLaxman Dewangan dev_err(&pdev->dev, "Platform data not found\n"); 1094518fb721SGraeme Gregory return -EINVAL; 10957e9a57e6SLaxman Dewangan } 1096518fb721SGraeme Gregory 10979eb0c421SAxel Lin pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); 10987e9a57e6SLaxman Dewangan if (!pmic) { 10997e9a57e6SLaxman Dewangan dev_err(&pdev->dev, "Memory allocation failed for pmic\n"); 1100518fb721SGraeme Gregory return -ENOMEM; 11017e9a57e6SLaxman Dewangan } 1102518fb721SGraeme Gregory 1103518fb721SGraeme Gregory mutex_init(&pmic->mutex); 1104518fb721SGraeme Gregory pmic->mfd = tps65910; 1105518fb721SGraeme Gregory platform_set_drvdata(pdev, pmic); 1106518fb721SGraeme Gregory 1107518fb721SGraeme Gregory /* Give control of all register to control port */ 11083f7e8275SRhyland Klein tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, 1109518fb721SGraeme Gregory DEVCTRL_SR_CTL_I2C_SEL_MASK); 1110518fb721SGraeme Gregory 1111a320e3c3SJorge Eduardo Candelaria switch(tps65910_chip_id(tps65910)) { 1112a320e3c3SJorge Eduardo Candelaria case TPS65910: 1113a320e3c3SJorge Eduardo Candelaria pmic->get_ctrl_reg = &tps65910_get_ctrl_register; 111439aa9b6eSAxel Lin pmic->num_regulators = ARRAY_SIZE(tps65910_regs); 11151e0c66f4SLaxman Dewangan pmic->ext_sleep_control = tps65910_ext_sleep_control; 1116a320e3c3SJorge Eduardo Candelaria info = tps65910_regs; 1117d04156bcSAxel Lin break; 1118a320e3c3SJorge Eduardo Candelaria case TPS65911: 1119a320e3c3SJorge Eduardo Candelaria pmic->get_ctrl_reg = &tps65911_get_ctrl_register; 112039aa9b6eSAxel Lin pmic->num_regulators = ARRAY_SIZE(tps65911_regs); 11211e0c66f4SLaxman Dewangan pmic->ext_sleep_control = tps65911_ext_sleep_control; 1122a320e3c3SJorge Eduardo Candelaria info = tps65911_regs; 1123d04156bcSAxel Lin break; 1124a320e3c3SJorge Eduardo Candelaria default: 11257e9a57e6SLaxman Dewangan dev_err(&pdev->dev, "Invalid tps chip version\n"); 1126a320e3c3SJorge Eduardo Candelaria return -ENODEV; 1127a320e3c3SJorge Eduardo Candelaria } 1128a320e3c3SJorge Eduardo Candelaria 112968d8c1cdSLaxman Dewangan pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators * 113039aa9b6eSAxel Lin sizeof(struct regulator_desc), GFP_KERNEL); 113139aa9b6eSAxel Lin if (!pmic->desc) { 113268d8c1cdSLaxman Dewangan dev_err(&pdev->dev, "Memory alloc fails for desc\n"); 113368d8c1cdSLaxman Dewangan return -ENOMEM; 113439aa9b6eSAxel Lin } 113539aa9b6eSAxel Lin 113668d8c1cdSLaxman Dewangan pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators * 113739aa9b6eSAxel Lin sizeof(struct tps_info *), GFP_KERNEL); 113839aa9b6eSAxel Lin if (!pmic->info) { 113968d8c1cdSLaxman Dewangan dev_err(&pdev->dev, "Memory alloc fails for info\n"); 114068d8c1cdSLaxman Dewangan return -ENOMEM; 114139aa9b6eSAxel Lin } 114239aa9b6eSAxel Lin 114368d8c1cdSLaxman Dewangan pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators * 114439aa9b6eSAxel Lin sizeof(struct regulator_dev *), GFP_KERNEL); 114539aa9b6eSAxel Lin if (!pmic->rdev) { 114668d8c1cdSLaxman Dewangan dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); 114768d8c1cdSLaxman Dewangan return -ENOMEM; 114839aa9b6eSAxel Lin } 114939aa9b6eSAxel Lin 1150c1fc1480SKyle Manna for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; 1151c1fc1480SKyle Manna i++, info++) { 1152c1fc1480SKyle Manna 1153c1fc1480SKyle Manna reg_data = pmic_plat_data->tps65910_pmic_init_data[i]; 1154c1fc1480SKyle Manna 1155c1fc1480SKyle Manna /* Regulator API handles empty constraints but not NULL 1156c1fc1480SKyle Manna * constraints */ 1157c1fc1480SKyle Manna if (!reg_data) 1158c1fc1480SKyle Manna continue; 1159c1fc1480SKyle Manna 1160518fb721SGraeme Gregory /* Register the regulators */ 1161518fb721SGraeme Gregory pmic->info[i] = info; 1162518fb721SGraeme Gregory 1163518fb721SGraeme Gregory pmic->desc[i].name = info->name; 116419228a6aSLaxman Dewangan pmic->desc[i].supply_name = pmic_plat_data->input_supply[i]; 116577fa44d0SAxel Lin pmic->desc[i].id = i; 11667d38a3cbSLaxman Dewangan pmic->desc[i].n_voltages = info->n_voltages; 116794f48ab3SAxel Lin pmic->desc[i].enable_time = info->enable_time_us; 1168518fb721SGraeme Gregory 1169a320e3c3SJorge Eduardo Candelaria if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { 1170518fb721SGraeme Gregory pmic->desc[i].ops = &tps65910_ops_dcdc; 1171780dc9baSAfzal Mohammed pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE * 1172780dc9baSAfzal Mohammed VDD1_2_NUM_VOLT_COARSE; 117301bc3a14SAxel Lin pmic->desc[i].ramp_delay = 12500; 1174a320e3c3SJorge Eduardo Candelaria } else if (i == TPS65910_REG_VDD3) { 117501bc3a14SAxel Lin if (tps65910_chip_id(tps65910) == TPS65910) { 1176518fb721SGraeme Gregory pmic->desc[i].ops = &tps65910_ops_vdd3; 1177d9fe28f9SAxel Lin pmic->desc[i].volt_table = info->voltage_table; 117801bc3a14SAxel Lin } else { 1179a320e3c3SJorge Eduardo Candelaria pmic->desc[i].ops = &tps65910_ops_dcdc; 118001bc3a14SAxel Lin pmic->desc[i].ramp_delay = 5000; 118101bc3a14SAxel Lin } 1182a320e3c3SJorge Eduardo Candelaria } else { 1183d9fe28f9SAxel Lin if (tps65910_chip_id(tps65910) == TPS65910) { 1184518fb721SGraeme Gregory pmic->desc[i].ops = &tps65910_ops; 1185d9fe28f9SAxel Lin pmic->desc[i].volt_table = info->voltage_table; 1186d9fe28f9SAxel Lin } else { 1187a320e3c3SJorge Eduardo Candelaria pmic->desc[i].ops = &tps65911_ops; 1188a320e3c3SJorge Eduardo Candelaria } 1189d9fe28f9SAxel Lin } 1190518fb721SGraeme Gregory 11911e0c66f4SLaxman Dewangan err = tps65910_set_ext_sleep_config(pmic, i, 11921e0c66f4SLaxman Dewangan pmic_plat_data->regulator_ext_sleep_control[i]); 11931e0c66f4SLaxman Dewangan /* 11941e0c66f4SLaxman Dewangan * Failing on regulator for configuring externally control 11951e0c66f4SLaxman Dewangan * is not a serious issue, just throw warning. 11961e0c66f4SLaxman Dewangan */ 11971e0c66f4SLaxman Dewangan if (err < 0) 11981e0c66f4SLaxman Dewangan dev_warn(tps65910->dev, 11991e0c66f4SLaxman Dewangan "Failed to initialise ext control config\n"); 12001e0c66f4SLaxman Dewangan 1201518fb721SGraeme Gregory pmic->desc[i].type = REGULATOR_VOLTAGE; 1202518fb721SGraeme Gregory pmic->desc[i].owner = THIS_MODULE; 1203a40a9c43SAxel Lin pmic->desc[i].enable_reg = pmic->get_ctrl_reg(i); 1204a40a9c43SAxel Lin pmic->desc[i].enable_mask = TPS65910_SUPPLY_STATE_ENABLED; 1205518fb721SGraeme Gregory 1206c172708dSMark Brown config.dev = tps65910->dev; 1207c172708dSMark Brown config.init_data = reg_data; 1208c172708dSMark Brown config.driver_data = pmic; 1209a40a9c43SAxel Lin config.regmap = tps65910->regmap; 1210c172708dSMark Brown 121184df8c12SLaxman Dewangan if (tps65910_reg_matches) 121284df8c12SLaxman Dewangan config.of_node = tps65910_reg_matches[i].of_node; 12136790178fSRhyland Klein 1214c172708dSMark Brown rdev = regulator_register(&pmic->desc[i], &config); 1215518fb721SGraeme Gregory if (IS_ERR(rdev)) { 1216518fb721SGraeme Gregory dev_err(tps65910->dev, 1217518fb721SGraeme Gregory "failed to register %s regulator\n", 1218518fb721SGraeme Gregory pdev->name); 1219518fb721SGraeme Gregory err = PTR_ERR(rdev); 122039aa9b6eSAxel Lin goto err_unregister_regulator; 1221518fb721SGraeme Gregory } 1222518fb721SGraeme Gregory 1223518fb721SGraeme Gregory /* Save regulator for cleanup */ 1224518fb721SGraeme Gregory pmic->rdev[i] = rdev; 1225518fb721SGraeme Gregory } 1226518fb721SGraeme Gregory return 0; 1227518fb721SGraeme Gregory 122839aa9b6eSAxel Lin err_unregister_regulator: 1229518fb721SGraeme Gregory while (--i >= 0) 1230518fb721SGraeme Gregory regulator_unregister(pmic->rdev[i]); 1231518fb721SGraeme Gregory return err; 1232518fb721SGraeme Gregory } 1233518fb721SGraeme Gregory 1234518fb721SGraeme Gregory static int __devexit tps65910_remove(struct platform_device *pdev) 1235518fb721SGraeme Gregory { 123639aa9b6eSAxel Lin struct tps65910_reg *pmic = platform_get_drvdata(pdev); 1237518fb721SGraeme Gregory int i; 1238518fb721SGraeme Gregory 123939aa9b6eSAxel Lin for (i = 0; i < pmic->num_regulators; i++) 124039aa9b6eSAxel Lin regulator_unregister(pmic->rdev[i]); 1241518fb721SGraeme Gregory 1242518fb721SGraeme Gregory return 0; 1243518fb721SGraeme Gregory } 1244518fb721SGraeme Gregory 12451e0c66f4SLaxman Dewangan static void tps65910_shutdown(struct platform_device *pdev) 12461e0c66f4SLaxman Dewangan { 12471e0c66f4SLaxman Dewangan struct tps65910_reg *pmic = platform_get_drvdata(pdev); 12481e0c66f4SLaxman Dewangan int i; 12491e0c66f4SLaxman Dewangan 12501e0c66f4SLaxman Dewangan /* 12511e0c66f4SLaxman Dewangan * Before bootloader jumps to kernel, it makes sure that required 12521e0c66f4SLaxman Dewangan * external control signals are in desired state so that given rails 12531e0c66f4SLaxman Dewangan * can be configure accordingly. 12541e0c66f4SLaxman Dewangan * If rails are configured to be controlled from external control 12551e0c66f4SLaxman Dewangan * then before shutting down/rebooting the system, the external 12561e0c66f4SLaxman Dewangan * control configuration need to be remove from the rails so that 12571e0c66f4SLaxman Dewangan * its output will be available as per register programming even 12581e0c66f4SLaxman Dewangan * if external controls are removed. This is require when the POR 12591e0c66f4SLaxman Dewangan * value of the control signals are not in active state and before 12601e0c66f4SLaxman Dewangan * bootloader initializes it, the system requires the rail output 12611e0c66f4SLaxman Dewangan * to be active for booting. 12621e0c66f4SLaxman Dewangan */ 12631e0c66f4SLaxman Dewangan for (i = 0; i < pmic->num_regulators; i++) { 12641e0c66f4SLaxman Dewangan int err; 12651e0c66f4SLaxman Dewangan if (!pmic->rdev[i]) 12661e0c66f4SLaxman Dewangan continue; 12671e0c66f4SLaxman Dewangan 12681e0c66f4SLaxman Dewangan err = tps65910_set_ext_sleep_config(pmic, i, 0); 12691e0c66f4SLaxman Dewangan if (err < 0) 12701e0c66f4SLaxman Dewangan dev_err(&pdev->dev, 12711e0c66f4SLaxman Dewangan "Error in clearing external control\n"); 12721e0c66f4SLaxman Dewangan } 12731e0c66f4SLaxman Dewangan } 12741e0c66f4SLaxman Dewangan 1275518fb721SGraeme Gregory static struct platform_driver tps65910_driver = { 1276518fb721SGraeme Gregory .driver = { 1277518fb721SGraeme Gregory .name = "tps65910-pmic", 1278518fb721SGraeme Gregory .owner = THIS_MODULE, 1279518fb721SGraeme Gregory }, 1280518fb721SGraeme Gregory .probe = tps65910_probe, 1281518fb721SGraeme Gregory .remove = __devexit_p(tps65910_remove), 12821e0c66f4SLaxman Dewangan .shutdown = tps65910_shutdown, 1283518fb721SGraeme Gregory }; 1284518fb721SGraeme Gregory 1285518fb721SGraeme Gregory static int __init tps65910_init(void) 1286518fb721SGraeme Gregory { 1287518fb721SGraeme Gregory return platform_driver_register(&tps65910_driver); 1288518fb721SGraeme Gregory } 1289518fb721SGraeme Gregory subsys_initcall(tps65910_init); 1290518fb721SGraeme Gregory 1291518fb721SGraeme Gregory static void __exit tps65910_cleanup(void) 1292518fb721SGraeme Gregory { 1293518fb721SGraeme Gregory platform_driver_unregister(&tps65910_driver); 1294518fb721SGraeme Gregory } 1295518fb721SGraeme Gregory module_exit(tps65910_cleanup); 1296518fb721SGraeme Gregory 1297518fb721SGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 1298ae0e6544SAxel Lin MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver"); 1299518fb721SGraeme Gregory MODULE_LICENSE("GPL v2"); 1300518fb721SGraeme Gregory MODULE_ALIAS("platform:tps65910-pmic"); 1301