tps65023-regulator.c revision 90923351d480fffd0d24646db83f6f8315eed0d9
130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* 230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps65023-regulator.c 330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Supports TPS65023 Regulator 530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/ 730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * This program is free software; you can redistribute it and/or 930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * modify it under the terms of the GNU General Public License as 1030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * published by the Free Software Foundation version 2. 1130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 1230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, 1330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * whether express or implied; without even the implied warranty of 1430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * General Public License for more details. 1630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */ 1730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/kernel.h> 1930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/module.h> 2030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/init.h> 2130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/err.h> 2230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/platform_device.h> 2330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/regulator/driver.h> 2430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/regulator/machine.h> 2530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/i2c.h> 2630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/delay.h> 275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2890923351d480fffd0d24646db83f6f8315eed0d9Mark Brown#include <linux/regmap.h> 2930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 3030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Register definitions */ 3130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_VERSION 0 3230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_PGOODZ 1 3330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_MASK 2 3430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_REG_CTRL 3 3530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CON_CTRL 4 3630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CON_CTRL2 5 3730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_DEF_CORE 6 3830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_DEFSLEW 7 3930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_LDO_CTRL 8 4030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 4130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* PGOODZ bitfields */ 4230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_PWRFAILZ BIT(7) 4330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_LOWBATTZ BIT(6) 4430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_VDCDC1 BIT(5) 4530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_VDCDC2 BIT(4) 4630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_VDCDC3 BIT(3) 4730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_LDO2 BIT(2) 4830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_PGOODZ_LDO1 BIT(1) 4930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 5030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* MASK bitfields */ 5130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_PWRFAILZ BIT(7) 5230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_LOWBATTZ BIT(6) 5330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_VDCDC1 BIT(5) 5430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_VDCDC2 BIT(4) 5530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_VDCDC3 BIT(3) 5630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_LDO2 BIT(2) 5730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MASK_LDO1 BIT(1) 5830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 5930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* REG_CTRL bitfields */ 6030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5) 6130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4) 6230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3) 6330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_LDO2_EN BIT(2) 6430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_LDO1_EN BIT(1) 6530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 6630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* LDO_CTRL bitfields */ 6730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) 6830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4)) 6930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 7030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of step-down converters available */ 7130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_DCDC 3 7230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of LDO voltage regulators available */ 7330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_LDO 2 7430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of total regulators available */ 7530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO) 7630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 7730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* DCDCs */ 7830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_1 0 7930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_2 1 8030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_3 2 8130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* LDOs */ 8230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_1 3 8330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_2 4 8430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 8530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MAX_REG_ID TPS65023_LDO_2 8630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 8730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Supported voltage values for regulators */ 8830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 VDCDC1_VSEL_table[] = { 8930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 800, 825, 850, 875, 9030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 900, 925, 950, 975, 9130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1000, 1025, 1050, 1075, 9230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1100, 1125, 1150, 1175, 9330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1200, 1225, 1250, 1275, 9430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1300, 1325, 1350, 1375, 9530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1400, 1425, 1450, 1475, 9630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1500, 1525, 1550, 1600, 9730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 9830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 9930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 LDO1_VSEL_table[] = { 10030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1000, 1100, 1300, 1800, 10130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 2200, 2600, 2800, 3150, 10230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 10330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 10430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 LDO2_VSEL_table[] = { 10530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 1050, 1200, 1300, 1800, 10630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 2500, 2800, 3000, 3300, 10730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 10830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 10930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic unsigned int num_voltages[] = {ARRAY_SIZE(VDCDC1_VSEL_table), 11030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 0, 0, ARRAY_SIZE(LDO1_VSEL_table), 11130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal ARRAY_SIZE(LDO2_VSEL_table)}; 11230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 11330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Regulator specific details */ 11430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstruct tps_info { 11530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal const char *name; 11630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal unsigned min_uV; 11730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal unsigned max_uV; 11830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal bool fixed; 11930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 table_len; 12030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal const u16 *table; 12130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 12230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 12330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* PMIC details */ 12430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstruct tps_pmic { 12530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct regulator_desc desc[TPS65023_NUM_REGULATOR]; 12630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct i2c_client *client; 12730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; 12830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal const struct tps_info *info[TPS65023_NUM_REGULATOR]; 12990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown struct regmap *regmap; 13030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 13130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 13230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) 13330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 13490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown return regmap_update_bits(tps->regmap, reg, mask, mask); 13530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 13630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 13730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) 13830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 13990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown return regmap_update_bits(tps->regmap, reg, mask, 0); 14030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 14130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 14230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_reg_read(struct tps_pmic *tps, u8 reg) 14330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 14490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown unsigned int val; 14590923351d480fffd0d24646db83f6f8315eed0d9Mark Brown int ret; 14630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 14790923351d480fffd0d24646db83f6f8315eed0d9Mark Brown ret = regmap_read(tps->regmap, reg, &val); 14830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 14990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown if (ret != 0) 15090923351d480fffd0d24646db83f6f8315eed0d9Mark Brown return ret; 15190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown else 15290923351d480fffd0d24646db83f6f8315eed0d9Mark Brown return val; 15330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 15430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 15530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val) 15630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 15790923351d480fffd0d24646db83f6f8315eed0d9Mark Brown return regmap_write(tps->regmap, reg, val); 15830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 15930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 16030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_is_enabled(struct regulator_dev *dev) 16130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 16230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 16330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int data, dcdc = rdev_get_id(dev); 16430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 16530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 16630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) 16730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 16830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 16930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = TPS65023_NUM_REGULATOR - dcdc; 17030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); 17130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 17230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (data < 0) 17330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return data; 17430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal else 17530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return (data & 1<<shift) ? 1 : 0; 17630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 17730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 17830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_is_enabled(struct regulator_dev *dev) 17930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 18030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 18130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int data, ldo = rdev_get_id(dev); 18230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 18330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 18430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 18530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 18630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 18730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = (ldo == TPS65023_LDO_1 ? 1 : 2); 18830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); 18930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 19030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (data < 0) 19130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return data; 19230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal else 19330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return (data & 1<<shift) ? 1 : 0; 19430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 19530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 19630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_enable(struct regulator_dev *dev) 19730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 19830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 19930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int dcdc = rdev_get_id(dev); 20030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 20130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 20230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) 20330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 20430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 20530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = TPS65023_NUM_REGULATOR - dcdc; 20630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); 20730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 20830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 20930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_disable(struct regulator_dev *dev) 21030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 21130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 21230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int dcdc = rdev_get_id(dev); 21330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 21430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 21530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) 21630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 21730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 21830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = TPS65023_NUM_REGULATOR - dcdc; 21930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); 22030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 22130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 22230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_enable(struct regulator_dev *dev) 22330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 22430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 22530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int ldo = rdev_get_id(dev); 22630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 22730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 22830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 22930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 23030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 23130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = (ldo == TPS65023_LDO_1 ? 1 : 2); 23230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); 23330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 23430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 23530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_disable(struct regulator_dev *dev) 23630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 23730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 23830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int ldo = rdev_get_id(dev); 23930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal u8 shift; 24030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 24130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 24230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 24330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 24430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal shift = (ldo == TPS65023_LDO_1 ? 1 : 2); 24530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); 24630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 24730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 24830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_get_voltage(struct regulator_dev *dev) 24930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 25030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 25130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int data, dcdc = rdev_get_id(dev); 25230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 25330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) 25430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 25530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 25630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc == TPS65023_DCDC_1) { 25730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE); 25830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (data < 0) 25930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return data; 26030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data &= (tps->info[dcdc]->table_len - 1); 26130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[dcdc]->table[data] * 1000; 26230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } else 26330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[dcdc]->min_uV; 26430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 26530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 26630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_set_voltage(struct regulator_dev *dev, 2673a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown int min_uV, int max_uV, 2683a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown unsigned *selector) 26930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 27030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 27130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int dcdc = rdev_get_id(dev); 27230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int vsel; 27330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 27430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc != TPS65023_DCDC_1) 27530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 27630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 27730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (min_uV < tps->info[dcdc]->min_uV 27830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal || min_uV > tps->info[dcdc]->max_uV) 27930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 28030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (max_uV < tps->info[dcdc]->min_uV 28130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal || max_uV > tps->info[dcdc]->max_uV) 28230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 28330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 28430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) { 28530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int mV = tps->info[dcdc]->table[vsel]; 28630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int uV = mV * 1000; 28730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 28830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* Break at the first in-range value */ 28930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (min_uV <= uV && uV <= max_uV) 29030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal break; 29130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } 29230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 2933a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown *selector = vsel; 2943a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown 29530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* write to the register in case we found a match */ 29630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (vsel == tps->info[dcdc]->table_len) 29730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 29830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal else 29930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel); 30030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 30130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 30230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_get_voltage(struct regulator_dev *dev) 30330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 30430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 30530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int data, ldo = rdev_get_id(dev); 30630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 30730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 30830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 30930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 31030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); 31130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (data < 0) 31230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return data; 31330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 31430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)); 31530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data &= (tps->info[ldo]->table_len - 1); 31630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[ldo]->table[data] * 1000; 31730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 31830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 31930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_set_voltage(struct regulator_dev *dev, 3203a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown int min_uV, int max_uV, unsigned *selector) 32130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 32230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 32330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int data, vsel, ldo = rdev_get_id(dev); 32430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 32530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 32630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 32730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 32830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV) 32930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 33030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV) 33130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 33230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 33330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) { 33430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int mV = tps->info[ldo]->table[vsel]; 33530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int uV = mV * 1000; 33630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 33730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* Break at the first in-range value */ 33830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (min_uV <= uV && uV <= max_uV) 33930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal break; 34030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } 34130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 34230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (vsel == tps->info[ldo]->table_len) 34330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 34430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 3453a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown *selector = vsel; 3463a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown 34730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); 34830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (data < 0) 34930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return data; 35030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 35130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1); 35230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1))); 35330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps_65023_reg_write(tps, TPS65023_REG_LDO_CTRL, data); 35430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 35530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 35630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_list_voltage(struct regulator_dev *dev, 35730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal unsigned selector) 35830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 35930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 36030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int dcdc = rdev_get_id(dev); 36130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 36230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) 36330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 36430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 36530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (dcdc == TPS65023_DCDC_1) { 36630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (selector >= tps->info[dcdc]->table_len) 36730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 36830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal else 36930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[dcdc]->table[selector] * 1000; 37030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } else 37130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[dcdc]->min_uV; 37230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 37330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 37430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_list_voltage(struct regulator_dev *dev, 37530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal unsigned selector) 37630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 37730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = rdev_get_drvdata(dev); 37830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int ldo = rdev_get_id(dev); 37930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 38030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) 38130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 38230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 38330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (selector >= tps->info[ldo]->table_len) 38430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EINVAL; 38530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal else 38630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return tps->info[ldo]->table[selector] * 1000; 38730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 38830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 38930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Operations permitted on VDCDCx */ 39030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct regulator_ops tps65023_dcdc_ops = { 39130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .is_enabled = tps65023_dcdc_is_enabled, 39230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .enable = tps65023_dcdc_enable, 39330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .disable = tps65023_dcdc_disable, 39430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .get_voltage = tps65023_dcdc_get_voltage, 39530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .set_voltage = tps65023_dcdc_set_voltage, 39630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .list_voltage = tps65023_dcdc_list_voltage, 39730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 39830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 39930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Operations permitted on LDOx */ 40030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct regulator_ops tps65023_ldo_ops = { 40130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .is_enabled = tps65023_ldo_is_enabled, 40230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .enable = tps65023_ldo_enable, 40330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .disable = tps65023_ldo_disable, 40430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .get_voltage = tps65023_ldo_get_voltage, 40530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .set_voltage = tps65023_ldo_set_voltage, 40630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .list_voltage = tps65023_ldo_list_voltage, 40730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 40830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 40990923351d480fffd0d24646db83f6f8315eed0d9Mark Brownstatic struct regmap_config tps65023_regmap_config = { 41090923351d480fffd0d24646db83f6f8315eed0d9Mark Brown .reg_bits = 8, 41190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown .val_bits = 8, 41290923351d480fffd0d24646db83f6f8315eed0d9Mark Brown}; 41390923351d480fffd0d24646db83f6f8315eed0d9Mark Brown 41454d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhovstatic int __devinit tps_65023_probe(struct i2c_client *client, 41554d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov const struct i2c_device_id *id) 41630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 41730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal const struct tps_info *info = (void *)id->driver_data; 41830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct regulator_init_data *init_data; 41930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct regulator_dev *rdev; 42030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps; 42130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int i; 42254d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov int error; 42330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 42430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 42530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EIO; 42630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 42730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /** 42830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * init_data points to array of regulator_init structures 42930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * coming from the board-evm file. 43030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */ 43130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal init_data = client->dev.platform_data; 43230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (!init_data) 43330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -EIO; 43430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 43530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps = kzalloc(sizeof(*tps), GFP_KERNEL); 43630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (!tps) 43730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return -ENOMEM; 43830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 43990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config); 44090923351d480fffd0d24646db83f6f8315eed0d9Mark Brown if (IS_ERR(tps->regmap)) { 44190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown error = PTR_ERR(tps->regmap); 44290923351d480fffd0d24646db83f6f8315eed0d9Mark Brown dev_err(&client->dev, "Failed to allocate register map: %d\n", 44390923351d480fffd0d24646db83f6f8315eed0d9Mark Brown error); 44490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown goto fail_alloc; 44590923351d480fffd0d24646db83f6f8315eed0d9Mark Brown } 44630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 44730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* common for all regulators */ 44830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->client = client; 44930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 45030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) { 45130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* Store regulator specific information */ 45230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->info[i] = info; 45330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 45430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->desc[i].name = info->name; 45577fa44d0e10711e899788c58fe53f8f7b18c7f67Axel Lin tps->desc[i].id = i; 45630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->desc[i].n_voltages = num_voltages[i]; 45730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->desc[i].ops = (i > TPS65023_DCDC_3 ? 45830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal &tps65023_ldo_ops : &tps65023_dcdc_ops); 45930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->desc[i].type = REGULATOR_VOLTAGE; 46030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->desc[i].owner = THIS_MODULE; 46130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 46230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* Register the regulators */ 46330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal rdev = regulator_register(&tps->desc[i], &client->dev, 46454d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov init_data, tps); 46530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal if (IS_ERR(rdev)) { 46630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal dev_err(&client->dev, "failed to register %s\n", 46730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal id->name); 46854d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov error = PTR_ERR(rdev); 46954d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov goto fail; 47030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } 47130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 47230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal /* Save regulator for cleanup */ 47330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal tps->rdev[i] = rdev; 47430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal } 47530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 47630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal i2c_set_clientdata(client, tps); 47730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 47830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return 0; 47954d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov 48054d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov fail: 48154d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov while (--i >= 0) 48254d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov regulator_unregister(tps->rdev[i]); 48354d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov 48490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown regmap_exit(tps->regmap); 48590923351d480fffd0d24646db83f6f8315eed0d9Mark Brown fail_alloc: 48654d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov kfree(tps); 48754d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov return error; 48830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 48930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 49030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/** 49130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_remove - TPS65023 driver i2c remove handler 49230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * @client: i2c driver client device structure 49330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 49430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Unregister TPS driver as an i2c client device driver 49530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */ 49630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int __devexit tps_65023_remove(struct i2c_client *client) 49730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 49830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal struct tps_pmic *tps = i2c_get_clientdata(client); 49930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal int i; 50030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 50130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal for (i = 0; i < TPS65023_NUM_REGULATOR; i++) 50230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal regulator_unregister(tps->rdev[i]); 50330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 50490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown regmap_exit(tps->regmap); 50530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal kfree(tps); 50630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 50730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return 0; 50830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 50930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 51030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const struct tps_info tps65023_regs[] = { 51130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal { 51230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "VDCDC1", 51330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .min_uV = 800000, 51430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .max_uV = 1600000, 51530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table_len = ARRAY_SIZE(VDCDC1_VSEL_table), 51630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table = VDCDC1_VSEL_table, 51730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 51830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal { 51930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "VDCDC2", 52030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .min_uV = 3300000, 52130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .max_uV = 3300000, 52230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .fixed = 1, 52330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 52430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal { 52530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "VDCDC3", 52630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .min_uV = 1800000, 52730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .max_uV = 1800000, 52830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .fixed = 1, 52930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 53030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal { 53130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "LDO1", 53230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .min_uV = 1000000, 53330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .max_uV = 3150000, 53430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table_len = ARRAY_SIZE(LDO1_VSEL_table), 53530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table = LDO1_VSEL_table, 53630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 53730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal { 53830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "LDO2", 53930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .min_uV = 1050000, 54030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .max_uV = 3300000, 54130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table_len = ARRAY_SIZE(LDO2_VSEL_table), 54230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .table = LDO2_VSEL_table, 54330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 54430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 54530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 5469e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwoodstatic const struct i2c_device_id tps_65023_id[] = { 5479e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood {.name = "tps65023", 5489e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood .driver_data = (unsigned long) tps65023_regs,}, 5491880a2fc59d2afabc142a311497cf7c320d64506Marek Vasut {.name = "tps65021", 5501880a2fc59d2afabc142a311497cf7c320d64506Marek Vasut .driver_data = (unsigned long) tps65023_regs,}, 5519e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood { }, 55230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 55330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 55430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_DEVICE_TABLE(i2c, tps_65023_id); 55530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 55630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct i2c_driver tps_65023_i2c_driver = { 55730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .driver = { 55830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .name = "tps65023", 55930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .owner = THIS_MODULE, 56030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal }, 56130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .probe = tps_65023_probe, 56230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal .remove = __devexit_p(tps_65023_remove), 5639e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood .id_table = tps_65023_id, 56430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}; 56530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 56630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/** 56730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_init 56830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 56930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Module init function 57030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */ 57130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int __init tps_65023_init(void) 57230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 57330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal return i2c_add_driver(&tps_65023_i2c_driver); 57430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 57530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalsubsys_initcall(tps_65023_init); 57630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 57730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/** 57830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_cleanup 57930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * 58030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Module exit function 58130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */ 58230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic void __exit tps_65023_cleanup(void) 58330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{ 58430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal i2c_del_driver(&tps_65023_i2c_driver); 58530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal} 58630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalmodule_exit(tps_65023_cleanup); 58730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal 58830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_AUTHOR("Texas Instruments"); 58930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_DESCRIPTION("TPS65023 voltage regulator driver"); 5909e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam GirdwoodMODULE_LICENSE("GPL v2"); 591