2012-05-18 23:53:57 +08:00
|
|
|
/*
|
|
|
|
* Driver for Regulator part of Palmas PMIC Chips
|
|
|
|
*
|
2013-03-07 21:17:48 +08:00
|
|
|
* Copyright 2011-2013 Texas Instruments Inc.
|
2012-05-18 23:53:57 +08:00
|
|
|
*
|
|
|
|
* Author: Graeme Gregory <gg@slimlogic.co.uk>
|
2013-02-24 00:35:40 +08:00
|
|
|
* Author: Ian Lartey <ian@slimlogic.co.uk>
|
2012-05-18 23:53:57 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/regulator/driver.h>
|
|
|
|
#include <linux/regulator/machine.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/regmap.h>
|
|
|
|
#include <linux/mfd/palmas.h>
|
2012-08-28 19:47:40 +08:00
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_platform.h>
|
|
|
|
#include <linux/regulator/of_regulator.h>
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-05-22 17:18:29 +08:00
|
|
|
static const struct regulator_linear_range smps_low_ranges[] = {
|
regulator: palmas: Fix SMPS list for 0V
get_voltage_sel reads from SMPS register - if the read selector value
is 0, the SMPS is actually disabled - So, this is in addition to the
ctrl_register that may also be used to enable/disable the SMPS.
The original logic(prior to commit dbabd624d4eec50b6) used to be:
static int palmas_map_voltage_smps(struct regulator_dev *rdev,
int min_uV, int max_uV)
<snip>
if (min_uV == 0)
return 0;
To handle this scenario, with the transition to regulator_list
implementation, we seem to have missed the data necessary to mark as
one of the valid entries as "0" 'disabled regulator' which results in
0 volts - So, stick with pre-existing logic.
Without this added to the list, palmas regulator driver,
on probe, attempts to setup constraints and in the case of
OMAP5uEVM, SMPS9 (which is mapped for 2v1 audio supply) fails in
regulator_list_voltage_linear_range mapping of '0', and as a fall back
of constraints not being applied, the entire regulator list is not
enumerated due to assumption that something system wide has gone bad
on with the PMIC.
Fixes: dbabd624d4eec50b6 ("regulator: palmas: Reemove open coded functions with helper functions")
Reported-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
2014-06-05 03:34:31 +08:00
|
|
|
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
|
2014-05-22 17:18:29 +08:00
|
|
|
REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0),
|
|
|
|
REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000),
|
|
|
|
REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct regulator_linear_range smps_high_ranges[] = {
|
regulator: palmas: Fix SMPS list for 0V
get_voltage_sel reads from SMPS register - if the read selector value
is 0, the SMPS is actually disabled - So, this is in addition to the
ctrl_register that may also be used to enable/disable the SMPS.
The original logic(prior to commit dbabd624d4eec50b6) used to be:
static int palmas_map_voltage_smps(struct regulator_dev *rdev,
int min_uV, int max_uV)
<snip>
if (min_uV == 0)
return 0;
To handle this scenario, with the transition to regulator_list
implementation, we seem to have missed the data necessary to mark as
one of the valid entries as "0" 'disabled regulator' which results in
0 volts - So, stick with pre-existing logic.
Without this added to the list, palmas regulator driver,
on probe, attempts to setup constraints and in the case of
OMAP5uEVM, SMPS9 (which is mapped for 2v1 audio supply) fails in
regulator_list_voltage_linear_range mapping of '0', and as a fall back
of constraints not being applied, the entire regulator list is not
enumerated due to assumption that something system wide has gone bad
on with the PMIC.
Fixes: dbabd624d4eec50b6 ("regulator: palmas: Reemove open coded functions with helper functions")
Reported-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
2014-06-05 03:34:31 +08:00
|
|
|
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
|
2014-05-22 17:18:29 +08:00
|
|
|
REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0),
|
|
|
|
REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000),
|
|
|
|
REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0),
|
|
|
|
};
|
|
|
|
|
2014-06-30 23:57:37 +08:00
|
|
|
static struct palmas_regs_info palmas_generic_regs_info[] = {
|
2012-05-18 23:53:57 +08:00
|
|
|
{
|
|
|
|
.name = "SMPS12",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps1-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS12_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS12_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS12_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS123",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps1-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS12_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS12_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS12_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS3",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps3-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS3_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS3_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS3,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS45",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps4-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS45_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS45_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS45_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS457",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps4-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS45_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS45_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS45_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS6",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps6-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS6_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS6_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS6_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS6,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS7",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps7-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS7_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS7_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS7,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS8",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps8-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS8_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS8_CTRL,
|
|
|
|
.tstep_addr = PALMAS_SMPS8_TSTEP,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS8,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS9",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps9-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_SMPS9_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_SMPS9_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS9,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
2013-08-12 16:51:14 +08:00
|
|
|
.name = "SMPS10_OUT2",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "smps10-in",
|
2013-04-19 20:33:45 +08:00
|
|
|
.ctrl_addr = PALMAS_SMPS10_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
2013-08-12 16:51:14 +08:00
|
|
|
{
|
|
|
|
.name = "SMPS10_OUT1",
|
|
|
|
.sname = "smps10-out2",
|
|
|
|
.ctrl_addr = PALMAS_SMPS10_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10,
|
2013-08-12 16:51:14 +08:00
|
|
|
},
|
2012-05-18 23:53:57 +08:00
|
|
|
{
|
|
|
|
.name = "LDO1",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo1-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO1_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO1_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO1,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO2",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo2-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO2_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO2_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO2,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO3",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo3-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO3_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO3_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO3,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO4",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo4-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO4_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO4_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO4,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO5",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo5-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO5_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO5_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO5,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO6",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo6-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO6_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO6_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO6,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO7",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo7-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO7_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO7_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO7,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO8",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo8-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO8_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO8_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO8,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO9",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldo9-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDO9_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDO9_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO9,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDOLN",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldoln-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDOLN_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDOLN_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOLN,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDOUSB",
|
2013-03-20 21:56:37 +08:00
|
|
|
.sname = "ldousb-in",
|
2012-05-18 23:53:57 +08:00
|
|
|
.vsel_addr = PALMAS_LDOUSB_VOLTAGE,
|
|
|
|
.ctrl_addr = PALMAS_LDOUSB_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOUSB,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
2013-04-17 17:43:12 +08:00
|
|
|
{
|
|
|
|
.name = "REGEN1",
|
|
|
|
.ctrl_addr = PALMAS_REGEN1_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN1,
|
2013-04-17 17:43:12 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "REGEN2",
|
|
|
|
.ctrl_addr = PALMAS_REGEN2_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN2,
|
2013-04-17 17:43:12 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "REGEN3",
|
|
|
|
.ctrl_addr = PALMAS_REGEN3_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN3,
|
2013-04-17 17:43:12 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SYSEN1",
|
|
|
|
.ctrl_addr = PALMAS_SYSEN1_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN1,
|
2013-04-17 17:43:12 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SYSEN2",
|
|
|
|
.ctrl_addr = PALMAS_SYSEN2_CTRL,
|
2013-08-21 18:48:16 +08:00
|
|
|
.sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN2,
|
2013-04-17 17:43:12 +08:00
|
|
|
},
|
2012-05-18 23:53:57 +08:00
|
|
|
};
|
|
|
|
|
2014-06-30 23:57:35 +08:00
|
|
|
static struct palmas_regs_info tps65917_regs_info[] = {
|
2014-06-18 17:59:00 +08:00
|
|
|
{
|
|
|
|
.name = "SMPS1",
|
|
|
|
.sname = "smps1-in",
|
|
|
|
.vsel_addr = TPS65917_SMPS1_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_SMPS1_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS2",
|
|
|
|
.sname = "smps2-in",
|
|
|
|
.vsel_addr = TPS65917_SMPS2_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_SMPS2_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS3",
|
|
|
|
.sname = "smps3-in",
|
|
|
|
.vsel_addr = TPS65917_SMPS3_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_SMPS3_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS3,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS4",
|
|
|
|
.sname = "smps4-in",
|
|
|
|
.vsel_addr = TPS65917_SMPS4_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_SMPS4_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "SMPS5",
|
|
|
|
.sname = "smps5-in",
|
|
|
|
.vsel_addr = TPS65917_SMPS5_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_SMPS5_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_SMPS5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO1",
|
|
|
|
.sname = "ldo1-in",
|
|
|
|
.vsel_addr = TPS65917_LDO1_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_LDO1_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO2",
|
|
|
|
.sname = "ldo2-in",
|
|
|
|
.vsel_addr = TPS65917_LDO2_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_LDO2_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO3",
|
|
|
|
.sname = "ldo3-in",
|
|
|
|
.vsel_addr = TPS65917_LDO3_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_LDO3_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO3,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO4",
|
|
|
|
.sname = "ldo4-in",
|
|
|
|
.vsel_addr = TPS65917_LDO4_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_LDO4_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "LDO5",
|
|
|
|
.sname = "ldo5-in",
|
|
|
|
.vsel_addr = TPS65917_LDO5_VOLTAGE,
|
|
|
|
.ctrl_addr = TPS65917_LDO5_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_LDO5,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "REGEN1",
|
|
|
|
.ctrl_addr = TPS65917_REGEN1_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "REGEN2",
|
|
|
|
.ctrl_addr = TPS65917_REGEN2_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "REGEN3",
|
|
|
|
.ctrl_addr = TPS65917_REGEN3_CTRL,
|
|
|
|
.sleep_id = TPS65917_EXTERNAL_REQSTR_ID_REGEN3,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
#define EXTERNAL_REQUESTOR(_id, _offset, _pos) \
|
|
|
|
[PALMAS_EXTERNAL_REQSTR_ID_##_id] = { \
|
|
|
|
.id = PALMAS_EXTERNAL_REQSTR_ID_##_id, \
|
|
|
|
.reg_offset = _offset, \
|
|
|
|
.bit_pos = _pos, \
|
|
|
|
}
|
|
|
|
|
2014-06-30 23:57:34 +08:00
|
|
|
static struct palmas_sleep_requestor_info palma_sleep_req_info[] = {
|
2014-06-18 17:58:59 +08:00
|
|
|
EXTERNAL_REQUESTOR(REGEN1, 0, 0),
|
|
|
|
EXTERNAL_REQUESTOR(REGEN2, 0, 1),
|
|
|
|
EXTERNAL_REQUESTOR(SYSEN1, 0, 2),
|
|
|
|
EXTERNAL_REQUESTOR(SYSEN2, 0, 3),
|
|
|
|
EXTERNAL_REQUESTOR(CLK32KG, 0, 4),
|
|
|
|
EXTERNAL_REQUESTOR(CLK32KGAUDIO, 0, 5),
|
|
|
|
EXTERNAL_REQUESTOR(REGEN3, 0, 6),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS12, 1, 0),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS3, 1, 1),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS45, 1, 2),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS6, 1, 3),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS7, 1, 4),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS8, 1, 5),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS9, 1, 6),
|
|
|
|
EXTERNAL_REQUESTOR(SMPS10, 1, 7),
|
|
|
|
EXTERNAL_REQUESTOR(LDO1, 2, 0),
|
|
|
|
EXTERNAL_REQUESTOR(LDO2, 2, 1),
|
|
|
|
EXTERNAL_REQUESTOR(LDO3, 2, 2),
|
|
|
|
EXTERNAL_REQUESTOR(LDO4, 2, 3),
|
|
|
|
EXTERNAL_REQUESTOR(LDO5, 2, 4),
|
|
|
|
EXTERNAL_REQUESTOR(LDO6, 2, 5),
|
|
|
|
EXTERNAL_REQUESTOR(LDO7, 2, 6),
|
|
|
|
EXTERNAL_REQUESTOR(LDO8, 2, 7),
|
|
|
|
EXTERNAL_REQUESTOR(LDO9, 3, 0),
|
|
|
|
EXTERNAL_REQUESTOR(LDOLN, 3, 1),
|
|
|
|
EXTERNAL_REQUESTOR(LDOUSB, 3, 2),
|
|
|
|
};
|
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
#define EXTERNAL_REQUESTOR_TPS65917(_id, _offset, _pos) \
|
|
|
|
[TPS65917_EXTERNAL_REQSTR_ID_##_id] = { \
|
|
|
|
.id = TPS65917_EXTERNAL_REQSTR_ID_##_id, \
|
|
|
|
.reg_offset = _offset, \
|
|
|
|
.bit_pos = _pos, \
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct palmas_sleep_requestor_info tps65917_sleep_req_info[] = {
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(REGEN1, 0, 0),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(REGEN2, 0, 1),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(REGEN3, 0, 6),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(SMPS1, 1, 0),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(SMPS2, 1, 1),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(SMPS3, 1, 2),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(SMPS4, 1, 3),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(SMPS5, 1, 4),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(LDO1, 2, 0),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(LDO2, 2, 1),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(LDO3, 2, 2),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(LDO4, 2, 3),
|
|
|
|
EXTERNAL_REQUESTOR_TPS65917(LDO5, 2, 4),
|
|
|
|
};
|
|
|
|
|
2013-04-18 21:02:47 +08:00
|
|
|
static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
#define SMPS_CTRL_MODE_OFF 0x00
|
|
|
|
#define SMPS_CTRL_MODE_ON 0x01
|
|
|
|
#define SMPS_CTRL_MODE_ECO 0x02
|
|
|
|
#define SMPS_CTRL_MODE_PWM 0x03
|
|
|
|
|
2013-09-04 17:50:06 +08:00
|
|
|
#define PALMAS_SMPS_NUM_VOLTAGES 122
|
2012-05-18 23:53:57 +08:00
|
|
|
#define PALMAS_SMPS10_NUM_VOLTAGES 2
|
|
|
|
#define PALMAS_LDO_NUM_VOLTAGES 50
|
|
|
|
|
|
|
|
#define SMPS10_VSEL (1<<3)
|
|
|
|
#define SMPS10_BOOST_EN (1<<2)
|
|
|
|
#define SMPS10_BYPASS_EN (1<<1)
|
|
|
|
#define SMPS10_SWITCH_EN (1<<0)
|
|
|
|
|
|
|
|
#define REGULATOR_SLAVE 0
|
|
|
|
|
|
|
|
static int palmas_smps_read(struct palmas *palmas, unsigned int reg,
|
|
|
|
unsigned int *dest)
|
|
|
|
{
|
|
|
|
unsigned int addr;
|
|
|
|
|
|
|
|
addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg);
|
|
|
|
|
|
|
|
return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int palmas_smps_write(struct palmas *palmas, unsigned int reg,
|
|
|
|
unsigned int value)
|
|
|
|
{
|
|
|
|
unsigned int addr;
|
|
|
|
|
|
|
|
addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg);
|
|
|
|
|
|
|
|
return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int palmas_ldo_read(struct palmas *palmas, unsigned int reg,
|
|
|
|
unsigned int *dest)
|
|
|
|
{
|
|
|
|
unsigned int addr;
|
|
|
|
|
|
|
|
addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg);
|
|
|
|
|
|
|
|
return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
|
|
|
|
unsigned int value)
|
|
|
|
{
|
|
|
|
unsigned int addr;
|
|
|
|
|
|
|
|
addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg);
|
|
|
|
|
|
|
|
return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
|
|
|
|
{
|
2014-06-30 23:57:36 +08:00
|
|
|
int id = rdev_get_id(dev);
|
2012-05-18 23:53:57 +08:00
|
|
|
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2012-05-18 23:53:57 +08:00
|
|
|
unsigned int reg;
|
2013-04-18 21:02:48 +08:00
|
|
|
bool rail_enable = true;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®);
|
2014-06-18 17:58:59 +08:00
|
|
|
|
2012-06-07 17:08:21 +08:00
|
|
|
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2013-04-18 21:02:48 +08:00
|
|
|
if (reg == SMPS_CTRL_MODE_OFF)
|
|
|
|
rail_enable = false;
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
switch (mode) {
|
|
|
|
case REGULATOR_MODE_NORMAL:
|
|
|
|
reg |= SMPS_CTRL_MODE_ON;
|
|
|
|
break;
|
|
|
|
case REGULATOR_MODE_IDLE:
|
|
|
|
reg |= SMPS_CTRL_MODE_ECO;
|
|
|
|
break;
|
|
|
|
case REGULATOR_MODE_FAST:
|
|
|
|
reg |= SMPS_CTRL_MODE_PWM;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2013-04-18 21:02:48 +08:00
|
|
|
pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
|
|
|
if (rail_enable)
|
2014-06-30 23:57:36 +08:00
|
|
|
palmas_smps_write(pmic->palmas, rinfo->ctrl_addr, reg);
|
regulator: palmas: Fix SMPS enable/disable/is_enabled
We use regmap regulator ops to enable/disable and check if regulator
is enabled for various SMPS. However, these depend on valid
enable_reg, enable_mask and enable_value in regulator descriptor.
Currently we do not populate these for SMPS other than SMPS10, this
results in spurious results as regmap assumes that the values are
valid and ends up reading register 0x0 RTC:SECONDS_REG on Palmas
variants that do have RTC! To fix this, we update proper parameters
for the descriptor fields.
Further, we want to ensure the behavior consistent with logic
prior to commit dbabd624d4eec50b6, where, once you do a set_mode,
enable/disable ensure the logic remains consistent and configures
Palmas to the configuration that we set with set_mode (since the
configuration register is common). To do this, we can rely on the
regulator core's regulator_register behavior where the regulator
descriptor pointer provided by the regulator driver is stored. (no
reallocation and copy is done). This lets us update the enable_value
post registration, to remain consistent with the mode we configure as
part of set_mode.
Fixes: dbabd624d4eec50b6 ("regulator: palmas: Reemove open coded functions with helper functions")
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
2014-06-21 01:26:23 +08:00
|
|
|
|
|
|
|
/* Switch the enable value to ensure this is used for enable */
|
|
|
|
pmic->desc[id].enable_val = pmic->current_reg_mode[id];
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int palmas_get_mode_smps(struct regulator_dev *dev)
|
|
|
|
{
|
|
|
|
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
|
|
|
|
int id = rdev_get_id(dev);
|
|
|
|
unsigned int reg;
|
|
|
|
|
2013-04-18 21:02:48 +08:00
|
|
|
reg = pmic->current_reg_mode[id] & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
switch (reg) {
|
|
|
|
case SMPS_CTRL_MODE_ON:
|
|
|
|
return REGULATOR_MODE_NORMAL;
|
|
|
|
case SMPS_CTRL_MODE_ECO:
|
|
|
|
return REGULATOR_MODE_IDLE;
|
|
|
|
case SMPS_CTRL_MODE_PWM:
|
|
|
|
return REGULATOR_MODE_FAST;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-18 21:02:47 +08:00
|
|
|
static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
|
|
|
|
int ramp_delay)
|
|
|
|
{
|
2014-06-30 23:57:36 +08:00
|
|
|
int id = rdev_get_id(rdev);
|
2013-04-18 21:02:47 +08:00
|
|
|
struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2013-04-18 21:02:47 +08:00
|
|
|
unsigned int reg = 0;
|
|
|
|
int ret;
|
|
|
|
|
2013-04-19 14:18:48 +08:00
|
|
|
/* SMPS3 and SMPS7 do not have tstep_addr setting */
|
|
|
|
switch (id) {
|
|
|
|
case PALMAS_REG_SMPS3:
|
|
|
|
case PALMAS_REG_SMPS7:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-18 21:02:47 +08:00
|
|
|
if (ramp_delay <= 0)
|
|
|
|
reg = 0;
|
2013-04-22 18:22:49 +08:00
|
|
|
else if (ramp_delay <= 2500)
|
2013-04-18 21:02:47 +08:00
|
|
|
reg = 3;
|
2013-04-22 18:22:49 +08:00
|
|
|
else if (ramp_delay <= 5000)
|
2013-04-18 21:02:47 +08:00
|
|
|
reg = 2;
|
|
|
|
else
|
|
|
|
reg = 1;
|
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
ret = palmas_smps_write(pmic->palmas, rinfo->tstep_addr, reg);
|
2013-04-18 21:02:47 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
pmic->ramp_delay[id] = palmas_smps_ramp_delay[reg];
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
static struct regulator_ops palmas_ops_smps = {
|
2014-05-22 17:18:29 +08:00
|
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
2012-05-18 23:53:57 +08:00
|
|
|
.set_mode = palmas_set_mode_smps,
|
|
|
|
.get_mode = palmas_get_mode_smps,
|
2012-11-29 10:01:44 +08:00
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
2014-05-22 17:18:29 +08:00
|
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
2013-04-18 21:02:47 +08:00
|
|
|
.set_ramp_delay = palmas_smps_set_ramp_delay,
|
2012-05-18 23:53:57 +08:00
|
|
|
};
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
static struct regulator_ops palmas_ops_ext_control_smps = {
|
|
|
|
.set_mode = palmas_set_mode_smps,
|
|
|
|
.get_mode = palmas_get_mode_smps,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
2014-05-22 17:18:29 +08:00
|
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
2013-08-21 18:48:16 +08:00
|
|
|
.set_ramp_delay = palmas_smps_set_ramp_delay,
|
|
|
|
};
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
static struct regulator_ops palmas_ops_smps10 = {
|
|
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
2012-05-22 12:26:42 +08:00
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
2013-08-12 16:51:14 +08:00
|
|
|
.set_bypass = regulator_set_bypass_regmap,
|
|
|
|
.get_bypass = regulator_get_bypass_regmap,
|
2012-05-18 23:53:57 +08:00
|
|
|
};
|
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
static struct regulator_ops tps65917_ops_smps = {
|
|
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
.set_mode = palmas_set_mode_smps,
|
|
|
|
.get_mode = palmas_get_mode_smps,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct regulator_ops tps65917_ops_ext_control_smps = {
|
|
|
|
.set_mode = palmas_set_mode_smps,
|
|
|
|
.get_mode = palmas_get_mode_smps,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
|
|
};
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
static int palmas_is_enabled_ldo(struct regulator_dev *dev)
|
|
|
|
{
|
2014-06-30 23:57:36 +08:00
|
|
|
int id = rdev_get_id(dev);
|
2012-05-18 23:53:57 +08:00
|
|
|
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2012-05-18 23:53:57 +08:00
|
|
|
unsigned int reg;
|
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
palmas_ldo_read(pmic->palmas, rinfo->ctrl_addr, ®);
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
reg &= PALMAS_LDO1_CTRL_STATUS;
|
|
|
|
|
|
|
|
return !!(reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct regulator_ops palmas_ops_ldo = {
|
|
|
|
.is_enabled = palmas_is_enabled_ldo,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
2012-07-18 12:34:08 +08:00
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
2012-11-27 10:27:34 +08:00
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
2012-05-18 23:53:57 +08:00
|
|
|
};
|
|
|
|
|
2015-12-14 14:36:55 +08:00
|
|
|
static struct regulator_ops palmas_ops_ldo9 = {
|
|
|
|
.is_enabled = palmas_is_enabled_ldo,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
|
|
.set_bypass = regulator_set_bypass_regmap,
|
|
|
|
.get_bypass = regulator_get_bypass_regmap,
|
|
|
|
};
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
static struct regulator_ops palmas_ops_ext_control_ldo = {
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
|
|
};
|
|
|
|
|
2013-04-17 17:43:12 +08:00
|
|
|
static struct regulator_ops palmas_ops_extreg = {
|
|
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
};
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
static struct regulator_ops palmas_ops_ext_control_extreg = {
|
|
|
|
};
|
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
static struct regulator_ops tps65917_ops_ldo = {
|
|
|
|
.is_enabled = palmas_is_enabled_ldo,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
|
|
|
};
|
|
|
|
|
2015-12-14 14:36:55 +08:00
|
|
|
static struct regulator_ops tps65917_ops_ldo_1_2 = {
|
|
|
|
.is_enabled = palmas_is_enabled_ldo,
|
|
|
|
.enable = regulator_enable_regmap,
|
|
|
|
.disable = regulator_disable_regmap,
|
|
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
|
|
|
.set_bypass = regulator_set_bypass_regmap,
|
|
|
|
.get_bypass = regulator_get_bypass_regmap,
|
|
|
|
};
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
static int palmas_regulator_config_external(struct palmas *palmas, int id,
|
|
|
|
struct palmas_reg_init *reg_init)
|
|
|
|
{
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
|
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2013-08-21 18:48:16 +08:00
|
|
|
int ret;
|
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
ret = palmas_ext_control_req_config(palmas, rinfo->sleep_id,
|
|
|
|
reg_init->roof_floor, true);
|
2013-08-21 18:48:16 +08:00
|
|
|
if (ret < 0)
|
|
|
|
dev_err(palmas->dev,
|
|
|
|
"Ext control config for regulator %d failed %d\n",
|
|
|
|
id, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
/*
|
|
|
|
* setup the hardware based sleep configuration of the SMPS/LDO regulators
|
|
|
|
* from the platform data. This is different to the software based control
|
|
|
|
* supported by the regulator framework as it is controlled by toggling
|
|
|
|
* pins on the PMIC such as PREQ, SYSEN, ...
|
|
|
|
*/
|
|
|
|
static int palmas_smps_init(struct palmas *palmas, int id,
|
|
|
|
struct palmas_reg_init *reg_init)
|
|
|
|
{
|
|
|
|
unsigned int reg;
|
|
|
|
int ret;
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
|
|
|
unsigned int addr = rinfo->ctrl_addr;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
ret = palmas_smps_read(palmas, addr, ®);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2012-06-06 20:01:38 +08:00
|
|
|
switch (id) {
|
2013-08-12 16:51:14 +08:00
|
|
|
case PALMAS_REG_SMPS10_OUT1:
|
|
|
|
case PALMAS_REG_SMPS10_OUT2:
|
2013-04-17 17:43:11 +08:00
|
|
|
reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
|
|
|
|
if (reg_init->mode_sleep)
|
2012-06-06 20:01:38 +08:00
|
|
|
reg |= reg_init->mode_sleep <<
|
|
|
|
PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
|
|
|
|
break;
|
|
|
|
default:
|
2012-05-18 23:53:57 +08:00
|
|
|
if (reg_init->warm_reset)
|
|
|
|
reg |= PALMAS_SMPS12_CTRL_WR_S;
|
2013-04-17 17:43:11 +08:00
|
|
|
else
|
|
|
|
reg &= ~PALMAS_SMPS12_CTRL_WR_S;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
if (reg_init->roof_floor)
|
|
|
|
reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
|
2013-04-17 17:43:11 +08:00
|
|
|
else
|
|
|
|
reg &= ~PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2013-04-17 17:43:11 +08:00
|
|
|
reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
|
|
|
|
if (reg_init->mode_sleep)
|
2012-05-18 23:53:57 +08:00
|
|
|
reg |= reg_init->mode_sleep <<
|
|
|
|
PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
|
|
|
|
}
|
2012-06-06 20:01:38 +08:00
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
ret = palmas_smps_write(palmas, addr, reg);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
if (rinfo->vsel_addr && reg_init->vsel) {
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
reg = reg_init->vsel;
|
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
ret = palmas_smps_write(palmas, rinfo->vsel_addr, reg);
|
2012-05-18 23:53:57 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
if (reg_init->roof_floor && (id != PALMAS_REG_SMPS10_OUT1) &&
|
|
|
|
(id != PALMAS_REG_SMPS10_OUT2)) {
|
|
|
|
/* Enable externally controlled regulator */
|
|
|
|
ret = palmas_smps_read(palmas, addr, ®);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
if (!(reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK)) {
|
|
|
|
reg |= SMPS_CTRL_MODE_ON;
|
|
|
|
ret = palmas_smps_write(palmas, addr, reg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return palmas_regulator_config_external(palmas, id, reg_init);
|
|
|
|
}
|
2012-05-18 23:53:57 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int palmas_ldo_init(struct palmas *palmas, int id,
|
|
|
|
struct palmas_reg_init *reg_init)
|
|
|
|
{
|
|
|
|
unsigned int reg;
|
|
|
|
unsigned int addr;
|
|
|
|
int ret;
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2014-06-18 17:58:59 +08:00
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->ctrl_addr;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2012-07-18 12:31:59 +08:00
|
|
|
ret = palmas_ldo_read(palmas, addr, ®);
|
2012-05-18 23:53:57 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (reg_init->warm_reset)
|
|
|
|
reg |= PALMAS_LDO1_CTRL_WR_S;
|
2013-04-17 17:43:11 +08:00
|
|
|
else
|
|
|
|
reg &= ~PALMAS_LDO1_CTRL_WR_S;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
if (reg_init->mode_sleep)
|
|
|
|
reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
|
2013-04-17 17:43:11 +08:00
|
|
|
else
|
|
|
|
reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2012-07-18 12:31:59 +08:00
|
|
|
ret = palmas_ldo_write(palmas, addr, reg);
|
2012-05-18 23:53:57 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
if (reg_init->roof_floor) {
|
|
|
|
/* Enable externally controlled regulator */
|
|
|
|
ret = palmas_update_bits(palmas, PALMAS_LDO_BASE,
|
|
|
|
addr, PALMAS_LDO1_CTRL_MODE_ACTIVE,
|
|
|
|
PALMAS_LDO1_CTRL_MODE_ACTIVE);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(palmas->dev,
|
|
|
|
"LDO Register 0x%02x update failed %d\n",
|
|
|
|
addr, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return palmas_regulator_config_external(palmas, id, reg_init);
|
|
|
|
}
|
2012-05-18 23:53:57 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-17 17:43:12 +08:00
|
|
|
static int palmas_extreg_init(struct palmas *palmas, int id,
|
|
|
|
struct palmas_reg_init *reg_init)
|
|
|
|
{
|
|
|
|
unsigned int addr;
|
|
|
|
int ret;
|
|
|
|
unsigned int val = 0;
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
2014-06-18 17:58:59 +08:00
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->ctrl_addr;
|
2013-04-17 17:43:12 +08:00
|
|
|
|
|
|
|
if (reg_init->mode_sleep)
|
|
|
|
val = PALMAS_REGEN1_CTRL_MODE_SLEEP;
|
|
|
|
|
|
|
|
ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
|
|
|
|
addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
|
|
|
|
addr, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-08-21 18:48:16 +08:00
|
|
|
|
|
|
|
if (reg_init->roof_floor) {
|
|
|
|
/* Enable externally controlled regulator */
|
|
|
|
ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
|
|
|
|
addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE,
|
|
|
|
PALMAS_REGEN1_CTRL_MODE_ACTIVE);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(palmas->dev,
|
|
|
|
"Resource Register 0x%02x update failed %d\n",
|
|
|
|
addr, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return palmas_regulator_config_external(palmas, id, reg_init);
|
|
|
|
}
|
2013-04-17 17:43:12 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-17 17:43:13 +08:00
|
|
|
static void palmas_enable_ldo8_track(struct palmas *palmas)
|
|
|
|
{
|
|
|
|
unsigned int reg;
|
|
|
|
unsigned int addr;
|
|
|
|
int ret;
|
2014-06-18 17:58:59 +08:00
|
|
|
struct palmas_pmic_driver_data *ddata = palmas->pmic_ddata;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo;
|
2014-06-18 17:58:59 +08:00
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo = &ddata->palmas_regs_info[PALMAS_REG_LDO8];
|
|
|
|
addr = rinfo->ctrl_addr;
|
2013-04-17 17:43:13 +08:00
|
|
|
|
|
|
|
ret = palmas_ldo_read(palmas, addr, ®);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(palmas->dev, "Error in reading ldo8 control reg\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg |= PALMAS_LDO8_CTRL_LDO_TRACKING_EN;
|
|
|
|
ret = palmas_ldo_write(palmas, addr, reg);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(palmas->dev, "Error in enabling tracking mode\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* When SMPS45 is set to off and LDO8 tracking is enabled, the LDO8
|
|
|
|
* output is defined by the LDO8_VOLTAGE.VSEL register divided by two,
|
|
|
|
* and can be set from 0.45 to 1.65 V.
|
|
|
|
*/
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->vsel_addr;
|
2013-04-17 17:43:13 +08:00
|
|
|
ret = palmas_ldo_read(palmas, addr, ®);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg = (reg << 1) & PALMAS_LDO8_VOLTAGE_VSEL_MASK;
|
|
|
|
ret = palmas_ldo_write(palmas, addr, reg);
|
|
|
|
if (ret < 0)
|
|
|
|
dev_err(palmas->dev, "Error in setting ldo8 voltage reg\n");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
static int palmas_ldo_registration(struct palmas_pmic *pmic,
|
|
|
|
struct palmas_pmic_driver_data *ddata,
|
|
|
|
struct palmas_pmic_platform_data *pdata,
|
|
|
|
const char *pdev_name,
|
|
|
|
struct regulator_config config)
|
2012-08-28 19:47:40 +08:00
|
|
|
{
|
2014-06-18 17:58:59 +08:00
|
|
|
int id, ret;
|
|
|
|
struct regulator_dev *rdev;
|
|
|
|
struct palmas_reg_init *reg_init;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo;
|
2014-06-30 23:57:38 +08:00
|
|
|
struct regulator_desc *desc;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
for (id = ddata->ldo_begin; id < ddata->max_reg; id++) {
|
|
|
|
if (pdata && pdata->reg_init[id])
|
|
|
|
reg_init = pdata->reg_init[id];
|
|
|
|
else
|
|
|
|
reg_init = NULL;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo = &ddata->palmas_regs_info[id];
|
2014-06-18 17:58:59 +08:00
|
|
|
/* Miss out regulators which are not available due
|
|
|
|
* to alternate functions.
|
|
|
|
*/
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
/* Register the regulators */
|
2014-06-30 23:57:38 +08:00
|
|
|
desc = &pmic->desc[id];
|
|
|
|
desc->name = rinfo->name;
|
|
|
|
desc->id = id;
|
|
|
|
desc->type = REGULATOR_VOLTAGE;
|
|
|
|
desc->owner = THIS_MODULE;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
if (id < PALMAS_REG_REGEN1) {
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_voltages = PALMAS_LDO_NUM_VOLTAGES;
|
2014-06-18 17:58:59 +08:00
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ext_control_ldo;
|
2014-06-18 17:58:59 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ldo;
|
|
|
|
desc->min_uV = 900000;
|
|
|
|
desc->uV_step = 50000;
|
|
|
|
desc->linear_min_sel = 1;
|
|
|
|
desc->enable_time = 500;
|
|
|
|
desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
|
|
|
|
rinfo->vsel_addr);
|
|
|
|
desc->vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
|
|
|
|
desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
|
|
|
|
rinfo->ctrl_addr);
|
|
|
|
desc->enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
/* Check if LDO8 is in tracking mode or not */
|
|
|
|
if (pdata && (id == PALMAS_REG_LDO8) &&
|
|
|
|
pdata->enable_ldo8_tracking) {
|
|
|
|
palmas_enable_ldo8_track(pmic->palmas);
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->min_uV = 450000;
|
|
|
|
desc->uV_step = 25000;
|
2014-06-18 17:58:59 +08:00
|
|
|
}
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
/* LOD6 in vibrator mode will have enable time 2000us */
|
|
|
|
if (pdata && pdata->ldo6_vibrator &&
|
|
|
|
(id == PALMAS_REG_LDO6))
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_time = 2000;
|
2015-12-14 14:36:55 +08:00
|
|
|
|
|
|
|
if (id == PALMAS_REG_LDO9) {
|
|
|
|
desc->ops = &palmas_ops_ldo9;
|
|
|
|
desc->bypass_reg = desc->enable_reg;
|
2016-04-27 00:36:42 +08:00
|
|
|
desc->bypass_val_on =
|
|
|
|
PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
|
2015-12-14 14:36:55 +08:00
|
|
|
desc->bypass_mask =
|
|
|
|
PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
|
|
|
|
}
|
2014-06-18 17:58:59 +08:00
|
|
|
} else {
|
2015-03-17 18:26:05 +08:00
|
|
|
if (!ddata->has_regen3 && id == PALMAS_REG_REGEN3)
|
|
|
|
continue;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_voltages = 1;
|
2014-06-18 17:58:59 +08:00
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ext_control_extreg;
|
2014-06-18 17:58:59 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_extreg;
|
|
|
|
desc->enable_reg =
|
2014-06-18 17:58:59 +08:00
|
|
|
PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo->ctrl_addr);
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_mask = PALMAS_REGEN1_CTRL_MODE_ACTIVE;
|
2014-06-18 17:58:59 +08:00
|
|
|
}
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
if (pdata)
|
|
|
|
config.init_data = pdata->reg_data[id];
|
|
|
|
else
|
|
|
|
config.init_data = NULL;
|
2013-08-21 18:48:16 +08:00
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->supply_name = rinfo->sname;
|
2014-06-18 17:58:59 +08:00
|
|
|
config.of_node = ddata->palmas_matches[id].of_node;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
rdev = devm_regulator_register(pmic->dev, desc, &config);
|
2014-06-18 17:58:59 +08:00
|
|
|
if (IS_ERR(rdev)) {
|
|
|
|
dev_err(pmic->dev,
|
|
|
|
"failed to register %s regulator\n",
|
|
|
|
pdev_name);
|
|
|
|
return PTR_ERR(rdev);
|
|
|
|
}
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
/* Save regulator for cleanup */
|
|
|
|
pmic->rdev[id] = rdev;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
/* Initialise sleep/init values from platform data */
|
|
|
|
if (pdata) {
|
|
|
|
reg_init = pdata->reg_init[id];
|
|
|
|
if (reg_init) {
|
|
|
|
if (id <= ddata->ldo_end)
|
|
|
|
ret = palmas_ldo_init(pmic->palmas, id,
|
|
|
|
reg_init);
|
|
|
|
else
|
|
|
|
ret = palmas_extreg_init(pmic->palmas,
|
|
|
|
id, reg_init);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2012-08-28 19:47:40 +08:00
|
|
|
}
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
return 0;
|
2012-08-28 19:47:40 +08:00
|
|
|
}
|
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
static int tps65917_ldo_registration(struct palmas_pmic *pmic,
|
|
|
|
struct palmas_pmic_driver_data *ddata,
|
|
|
|
struct palmas_pmic_platform_data *pdata,
|
|
|
|
const char *pdev_name,
|
|
|
|
struct regulator_config config)
|
|
|
|
{
|
|
|
|
int id, ret;
|
|
|
|
struct regulator_dev *rdev;
|
|
|
|
struct palmas_reg_init *reg_init;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo;
|
2014-06-30 23:57:38 +08:00
|
|
|
struct regulator_desc *desc;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
for (id = ddata->ldo_begin; id < ddata->max_reg; id++) {
|
|
|
|
if (pdata && pdata->reg_init[id])
|
|
|
|
reg_init = pdata->reg_init[id];
|
|
|
|
else
|
|
|
|
reg_init = NULL;
|
|
|
|
|
|
|
|
/* Miss out regulators which are not available due
|
|
|
|
* to alternate functions.
|
|
|
|
*/
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo = &ddata->palmas_regs_info[id];
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
/* Register the regulators */
|
2014-06-30 23:57:38 +08:00
|
|
|
desc = &pmic->desc[id];
|
|
|
|
desc->name = rinfo->name;
|
|
|
|
desc->id = id;
|
|
|
|
desc->type = REGULATOR_VOLTAGE;
|
|
|
|
desc->owner = THIS_MODULE;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
if (id < TPS65917_REG_REGEN1) {
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_voltages = PALMAS_LDO_NUM_VOLTAGES;
|
2014-06-18 17:59:00 +08:00
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ext_control_ldo;
|
2014-06-18 17:59:00 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &tps65917_ops_ldo;
|
|
|
|
desc->min_uV = 900000;
|
|
|
|
desc->uV_step = 50000;
|
|
|
|
desc->linear_min_sel = 1;
|
|
|
|
desc->enable_time = 500;
|
|
|
|
desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
|
|
|
|
rinfo->vsel_addr);
|
|
|
|
desc->vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
|
|
|
|
desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
|
|
|
|
rinfo->ctrl_addr);
|
|
|
|
desc->enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
|
2014-06-18 17:59:00 +08:00
|
|
|
/*
|
|
|
|
* To be confirmed. Discussion on going with PMIC Team.
|
|
|
|
* It is of the order of ~60mV/uS.
|
|
|
|
*/
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ramp_delay = 2500;
|
2015-12-14 14:36:55 +08:00
|
|
|
if (id == TPS65917_REG_LDO1 ||
|
|
|
|
id == TPS65917_REG_LDO2) {
|
|
|
|
desc->ops = &tps65917_ops_ldo_1_2;
|
|
|
|
desc->bypass_reg = desc->enable_reg;
|
2016-04-27 00:36:42 +08:00
|
|
|
desc->bypass_val_on =
|
|
|
|
TPS65917_LDO1_CTRL_BYPASS_EN;
|
2015-12-14 14:36:55 +08:00
|
|
|
desc->bypass_mask =
|
|
|
|
TPS65917_LDO1_CTRL_BYPASS_EN;
|
|
|
|
}
|
2014-06-18 17:59:00 +08:00
|
|
|
} else {
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_voltages = 1;
|
2014-06-18 17:59:00 +08:00
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ext_control_extreg;
|
2014-06-18 17:59:00 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_extreg;
|
|
|
|
desc->enable_reg =
|
2014-06-18 17:59:00 +08:00
|
|
|
PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo->ctrl_addr);
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_mask = PALMAS_REGEN1_CTRL_MODE_ACTIVE;
|
2014-06-18 17:59:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pdata)
|
|
|
|
config.init_data = pdata->reg_data[id];
|
|
|
|
else
|
|
|
|
config.init_data = NULL;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->supply_name = rinfo->sname;
|
2014-06-18 17:59:00 +08:00
|
|
|
config.of_node = ddata->palmas_matches[id].of_node;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
rdev = devm_regulator_register(pmic->dev, desc, &config);
|
2014-06-18 17:59:00 +08:00
|
|
|
if (IS_ERR(rdev)) {
|
|
|
|
dev_err(pmic->dev,
|
|
|
|
"failed to register %s regulator\n",
|
|
|
|
pdev_name);
|
|
|
|
return PTR_ERR(rdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save regulator for cleanup */
|
|
|
|
pmic->rdev[id] = rdev;
|
|
|
|
|
|
|
|
/* Initialise sleep/init values from platform data */
|
|
|
|
if (pdata) {
|
|
|
|
reg_init = pdata->reg_init[id];
|
|
|
|
if (reg_init) {
|
|
|
|
if (id < TPS65917_REG_REGEN1)
|
|
|
|
ret = palmas_ldo_init(pmic->palmas,
|
|
|
|
id, reg_init);
|
|
|
|
else
|
|
|
|
ret = palmas_extreg_init(pmic->palmas,
|
|
|
|
id, reg_init);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
static int palmas_smps_registration(struct palmas_pmic *pmic,
|
|
|
|
struct palmas_pmic_driver_data *ddata,
|
|
|
|
struct palmas_pmic_platform_data *pdata,
|
|
|
|
const char *pdev_name,
|
|
|
|
struct regulator_config config)
|
2012-05-18 23:53:57 +08:00
|
|
|
{
|
2014-06-18 17:58:59 +08:00
|
|
|
int id, ret;
|
|
|
|
unsigned int addr, reg;
|
2012-05-18 23:53:57 +08:00
|
|
|
struct regulator_dev *rdev;
|
|
|
|
struct palmas_reg_init *reg_init;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo;
|
2014-06-30 23:57:38 +08:00
|
|
|
struct regulator_desc *desc;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
for (id = ddata->smps_start; id <= ddata->smps_end; id++) {
|
2013-04-18 21:02:47 +08:00
|
|
|
bool ramp_delay_support = false;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Miss out regulators which are not available due
|
|
|
|
* to slaving configurations.
|
|
|
|
*/
|
|
|
|
switch (id) {
|
|
|
|
case PALMAS_REG_SMPS12:
|
|
|
|
case PALMAS_REG_SMPS3:
|
|
|
|
if (pmic->smps123)
|
|
|
|
continue;
|
2013-04-18 21:02:47 +08:00
|
|
|
if (id == PALMAS_REG_SMPS12)
|
|
|
|
ramp_delay_support = true;
|
2012-05-18 23:53:57 +08:00
|
|
|
break;
|
|
|
|
case PALMAS_REG_SMPS123:
|
|
|
|
if (!pmic->smps123)
|
|
|
|
continue;
|
2013-04-18 21:02:47 +08:00
|
|
|
ramp_delay_support = true;
|
2012-05-18 23:53:57 +08:00
|
|
|
break;
|
|
|
|
case PALMAS_REG_SMPS45:
|
|
|
|
case PALMAS_REG_SMPS7:
|
|
|
|
if (pmic->smps457)
|
|
|
|
continue;
|
2013-04-18 21:02:47 +08:00
|
|
|
if (id == PALMAS_REG_SMPS45)
|
|
|
|
ramp_delay_support = true;
|
2012-05-18 23:53:57 +08:00
|
|
|
break;
|
|
|
|
case PALMAS_REG_SMPS457:
|
|
|
|
if (!pmic->smps457)
|
|
|
|
continue;
|
2013-04-18 21:02:47 +08:00
|
|
|
ramp_delay_support = true;
|
|
|
|
break;
|
2013-08-12 16:51:14 +08:00
|
|
|
case PALMAS_REG_SMPS10_OUT1:
|
|
|
|
case PALMAS_REG_SMPS10_OUT2:
|
2014-06-18 17:58:59 +08:00
|
|
|
if (!PALMAS_PMIC_HAS(pmic->palmas, SMPS10_BOOST))
|
2013-06-19 13:57:48 +08:00
|
|
|
continue;
|
2013-04-18 21:02:47 +08:00
|
|
|
}
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo = &ddata->palmas_regs_info[id];
|
2014-06-30 23:57:38 +08:00
|
|
|
desc = &pmic->desc[id];
|
2013-04-18 21:02:47 +08:00
|
|
|
|
2013-05-08 18:39:06 +08:00
|
|
|
if ((id == PALMAS_REG_SMPS6) || (id == PALMAS_REG_SMPS8))
|
2013-04-18 21:02:47 +08:00
|
|
|
ramp_delay_support = true;
|
|
|
|
|
|
|
|
if (ramp_delay_support) {
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->tstep_addr;
|
2013-04-18 21:02:47 +08:00
|
|
|
ret = palmas_smps_read(pmic->palmas, addr, ®);
|
|
|
|
if (ret < 0) {
|
2014-06-18 17:58:59 +08:00
|
|
|
dev_err(pmic->dev,
|
2013-04-18 21:02:47 +08:00
|
|
|
"reading TSTEP reg failed: %d\n", ret);
|
2013-09-04 14:31:01 +08:00
|
|
|
return ret;
|
2013-04-18 21:02:47 +08:00
|
|
|
}
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ramp_delay = palmas_smps_ramp_delay[reg & 0x3];
|
|
|
|
pmic->ramp_delay[id] = desc->ramp_delay;
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
|
|
|
|
2012-11-29 10:01:44 +08:00
|
|
|
/* Initialise sleep/init values from platform data */
|
|
|
|
if (pdata && pdata->reg_init[id]) {
|
|
|
|
reg_init = pdata->reg_init[id];
|
2014-06-18 17:58:59 +08:00
|
|
|
ret = palmas_smps_init(pmic->palmas, id, reg_init);
|
2012-11-29 10:01:44 +08:00
|
|
|
if (ret)
|
2013-09-04 14:31:01 +08:00
|
|
|
return ret;
|
2013-08-21 18:48:16 +08:00
|
|
|
} else {
|
|
|
|
reg_init = NULL;
|
2012-11-29 10:01:44 +08:00
|
|
|
}
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
/* Register the regulators */
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->name = rinfo->name;
|
|
|
|
desc->id = id;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2012-06-06 20:01:38 +08:00
|
|
|
switch (id) {
|
2013-08-12 16:51:14 +08:00
|
|
|
case PALMAS_REG_SMPS10_OUT1:
|
|
|
|
case PALMAS_REG_SMPS10_OUT2:
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
|
|
|
|
desc->ops = &palmas_ops_smps10;
|
|
|
|
desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
PALMAS_SMPS10_CTRL);
|
|
|
|
desc->vsel_mask = SMPS10_VSEL;
|
|
|
|
desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
PALMAS_SMPS10_CTRL);
|
2013-08-12 16:51:14 +08:00
|
|
|
if (id == PALMAS_REG_SMPS10_OUT1)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_mask = SMPS10_SWITCH_EN;
|
2013-08-12 16:51:14 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_mask = SMPS10_BOOST_EN;
|
|
|
|
desc->bypass_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
PALMAS_SMPS10_CTRL);
|
2016-04-27 00:36:42 +08:00
|
|
|
desc->bypass_val_on = SMPS10_BYPASS_EN;
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->bypass_mask = SMPS10_BYPASS_EN;
|
|
|
|
desc->min_uV = 3750000;
|
|
|
|
desc->uV_step = 1250000;
|
2012-06-06 20:01:38 +08:00
|
|
|
break;
|
|
|
|
default:
|
2012-11-29 10:01:44 +08:00
|
|
|
/*
|
|
|
|
* Read and store the RANGE bit for later use
|
|
|
|
* This must be done before regulator is probed,
|
2013-04-18 21:02:48 +08:00
|
|
|
* otherwise we error in probe with unsupportable
|
|
|
|
* ranges. Read the current smps mode for later use.
|
2012-11-29 10:01:44 +08:00
|
|
|
*/
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->vsel_addr;
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->n_linear_ranges = 3;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
|
|
|
ret = palmas_smps_read(pmic->palmas, addr, ®);
|
|
|
|
if (ret)
|
2013-09-04 14:31:01 +08:00
|
|
|
return ret;
|
2012-05-18 23:53:57 +08:00
|
|
|
if (reg & PALMAS_SMPS12_VOLTAGE_RANGE)
|
|
|
|
pmic->range[id] = 1;
|
2014-05-22 17:18:29 +08:00
|
|
|
if (pmic->range[id])
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->linear_ranges = smps_high_ranges;
|
2014-05-22 17:18:29 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->linear_ranges = smps_low_ranges;
|
2012-11-29 10:01:44 +08:00
|
|
|
|
2013-08-21 18:48:16 +08:00
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_ext_control_smps;
|
2013-08-21 18:48:16 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &palmas_ops_smps;
|
|
|
|
desc->n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
|
|
|
|
desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
rinfo->vsel_addr);
|
|
|
|
desc->vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK;
|
2013-04-18 21:02:48 +08:00
|
|
|
|
|
|
|
/* Read the smps mode for later use. */
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->ctrl_addr;
|
2013-04-18 21:02:48 +08:00
|
|
|
ret = palmas_smps_read(pmic->palmas, addr, ®);
|
|
|
|
if (ret)
|
2013-09-04 14:31:01 +08:00
|
|
|
return ret;
|
2013-04-18 21:02:48 +08:00
|
|
|
pmic->current_reg_mode[id] = reg &
|
|
|
|
PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
regulator: palmas: Fix SMPS enable/disable/is_enabled
We use regmap regulator ops to enable/disable and check if regulator
is enabled for various SMPS. However, these depend on valid
enable_reg, enable_mask and enable_value in regulator descriptor.
Currently we do not populate these for SMPS other than SMPS10, this
results in spurious results as regmap assumes that the values are
valid and ends up reading register 0x0 RTC:SECONDS_REG on Palmas
variants that do have RTC! To fix this, we update proper parameters
for the descriptor fields.
Further, we want to ensure the behavior consistent with logic
prior to commit dbabd624d4eec50b6, where, once you do a set_mode,
enable/disable ensure the logic remains consistent and configures
Palmas to the configuration that we set with set_mode (since the
configuration register is common). To do this, we can rely on the
regulator core's regulator_register behavior where the regulator
descriptor pointer provided by the regulator driver is stored. (no
reallocation and copy is done). This lets us update the enable_value
post registration, to remain consistent with the mode we configure as
part of set_mode.
Fixes: dbabd624d4eec50b6 ("regulator: palmas: Reemove open coded functions with helper functions")
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
2014-06-21 01:26:23 +08:00
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
rinfo->ctrl_addr);
|
|
|
|
desc->enable_mask = PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
regulator: palmas: Fix SMPS enable/disable/is_enabled
We use regmap regulator ops to enable/disable and check if regulator
is enabled for various SMPS. However, these depend on valid
enable_reg, enable_mask and enable_value in regulator descriptor.
Currently we do not populate these for SMPS other than SMPS10, this
results in spurious results as regmap assumes that the values are
valid and ends up reading register 0x0 RTC:SECONDS_REG on Palmas
variants that do have RTC! To fix this, we update proper parameters
for the descriptor fields.
Further, we want to ensure the behavior consistent with logic
prior to commit dbabd624d4eec50b6, where, once you do a set_mode,
enable/disable ensure the logic remains consistent and configures
Palmas to the configuration that we set with set_mode (since the
configuration register is common). To do this, we can rely on the
regulator core's regulator_register behavior where the regulator
descriptor pointer provided by the regulator driver is stored. (no
reallocation and copy is done). This lets us update the enable_value
post registration, to remain consistent with the mode we configure as
part of set_mode.
Fixes: dbabd624d4eec50b6 ("regulator: palmas: Reemove open coded functions with helper functions")
Reported-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
2014-06-21 01:26:23 +08:00
|
|
|
/* set_mode overrides this value */
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->enable_val = SMPS_CTRL_MODE_ON;
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->type = REGULATOR_VOLTAGE;
|
|
|
|
desc->owner = THIS_MODULE;
|
2012-11-29 10:01:44 +08:00
|
|
|
|
2012-08-28 19:47:40 +08:00
|
|
|
if (pdata)
|
2012-05-18 23:53:57 +08:00
|
|
|
config.init_data = pdata->reg_data[id];
|
|
|
|
else
|
|
|
|
config.init_data = NULL;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->supply_name = rinfo->sname;
|
2014-06-18 17:58:59 +08:00
|
|
|
config.of_node = ddata->palmas_matches[id].of_node;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
rdev = devm_regulator_register(pmic->dev, desc, &config);
|
2012-05-18 23:53:57 +08:00
|
|
|
if (IS_ERR(rdev)) {
|
2014-06-18 17:58:59 +08:00
|
|
|
dev_err(pmic->dev,
|
2012-05-18 23:53:57 +08:00
|
|
|
"failed to register %s regulator\n",
|
2014-06-18 17:58:59 +08:00
|
|
|
pdev_name);
|
2013-09-04 14:31:01 +08:00
|
|
|
return PTR_ERR(rdev);
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Save regulator for cleanup */
|
|
|
|
pmic->rdev[id] = rdev;
|
|
|
|
}
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
static int tps65917_smps_registration(struct palmas_pmic *pmic,
|
|
|
|
struct palmas_pmic_driver_data *ddata,
|
|
|
|
struct palmas_pmic_platform_data *pdata,
|
|
|
|
const char *pdev_name,
|
|
|
|
struct regulator_config config)
|
|
|
|
{
|
|
|
|
int id, ret;
|
|
|
|
unsigned int addr, reg;
|
|
|
|
struct regulator_dev *rdev;
|
|
|
|
struct palmas_reg_init *reg_init;
|
2014-06-30 23:57:36 +08:00
|
|
|
struct palmas_regs_info *rinfo;
|
2014-06-30 23:57:38 +08:00
|
|
|
struct regulator_desc *desc;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
for (id = ddata->smps_start; id <= ddata->smps_end; id++) {
|
|
|
|
/*
|
|
|
|
* Miss out regulators which are not available due
|
|
|
|
* to slaving configurations.
|
|
|
|
*/
|
2014-06-30 23:57:38 +08:00
|
|
|
desc = &pmic->desc[id];
|
|
|
|
desc->n_linear_ranges = 3;
|
2014-06-18 17:59:00 +08:00
|
|
|
if ((id == TPS65917_REG_SMPS2) && pmic->smps12)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Initialise sleep/init values from platform data */
|
|
|
|
if (pdata && pdata->reg_init[id]) {
|
|
|
|
reg_init = pdata->reg_init[id];
|
|
|
|
ret = palmas_smps_init(pmic->palmas, id, reg_init);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
reg_init = NULL;
|
|
|
|
}
|
2014-06-30 23:57:36 +08:00
|
|
|
rinfo = &ddata->palmas_regs_info[id];
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
/* Register the regulators */
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->name = rinfo->name;
|
|
|
|
desc->id = id;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Read and store the RANGE bit for later use
|
|
|
|
* This must be done before regulator is probed,
|
|
|
|
* otherwise we error in probe with unsupportable
|
|
|
|
* ranges. Read the current smps mode for later use.
|
|
|
|
*/
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->vsel_addr;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
ret = palmas_smps_read(pmic->palmas, addr, ®);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
if (reg & TPS65917_SMPS1_VOLTAGE_RANGE)
|
|
|
|
pmic->range[id] = 1;
|
|
|
|
|
|
|
|
if (pmic->range[id])
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->linear_ranges = smps_high_ranges;
|
|
|
|
else
|
|
|
|
desc->linear_ranges = smps_low_ranges;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
if (reg_init && reg_init->roof_floor)
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &tps65917_ops_ext_control_smps;
|
2014-06-18 17:59:00 +08:00
|
|
|
else
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->ops = &tps65917_ops_smps;
|
|
|
|
desc->n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
|
|
|
|
desc->vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
rinfo->vsel_addr);
|
|
|
|
desc->vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK;
|
|
|
|
desc->ramp_delay = 2500;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
/* Read the smps mode for later use. */
|
2014-06-30 23:57:36 +08:00
|
|
|
addr = rinfo->ctrl_addr;
|
2014-06-18 17:59:00 +08:00
|
|
|
ret = palmas_smps_read(pmic->palmas, addr, ®);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
pmic->current_reg_mode[id] = reg &
|
|
|
|
PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
2014-06-30 23:57:39 +08:00
|
|
|
desc->enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
|
|
|
rinfo->ctrl_addr);
|
|
|
|
desc->enable_mask = PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
|
|
|
/* set_mode overrides this value */
|
|
|
|
desc->enable_val = SMPS_CTRL_MODE_ON;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->type = REGULATOR_VOLTAGE;
|
|
|
|
desc->owner = THIS_MODULE;
|
2014-06-18 17:59:00 +08:00
|
|
|
|
|
|
|
if (pdata)
|
|
|
|
config.init_data = pdata->reg_data[id];
|
|
|
|
else
|
|
|
|
config.init_data = NULL;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
desc->supply_name = rinfo->sname;
|
2014-06-18 17:59:00 +08:00
|
|
|
config.of_node = ddata->palmas_matches[id].of_node;
|
|
|
|
|
2014-06-30 23:57:38 +08:00
|
|
|
rdev = devm_regulator_register(pmic->dev, desc, &config);
|
2014-06-18 17:59:00 +08:00
|
|
|
if (IS_ERR(rdev)) {
|
|
|
|
dev_err(pmic->dev,
|
|
|
|
"failed to register %s regulator\n",
|
|
|
|
pdev_name);
|
|
|
|
return PTR_ERR(rdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save regulator for cleanup */
|
|
|
|
pmic->rdev[id] = rdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
static struct of_regulator_match palmas_matches[] = {
|
|
|
|
{ .name = "smps12", },
|
|
|
|
{ .name = "smps123", },
|
|
|
|
{ .name = "smps3", },
|
|
|
|
{ .name = "smps45", },
|
|
|
|
{ .name = "smps457", },
|
|
|
|
{ .name = "smps6", },
|
|
|
|
{ .name = "smps7", },
|
|
|
|
{ .name = "smps8", },
|
|
|
|
{ .name = "smps9", },
|
|
|
|
{ .name = "smps10_out2", },
|
|
|
|
{ .name = "smps10_out1", },
|
|
|
|
{ .name = "ldo1", },
|
|
|
|
{ .name = "ldo2", },
|
|
|
|
{ .name = "ldo3", },
|
|
|
|
{ .name = "ldo4", },
|
|
|
|
{ .name = "ldo5", },
|
|
|
|
{ .name = "ldo6", },
|
|
|
|
{ .name = "ldo7", },
|
|
|
|
{ .name = "ldo8", },
|
|
|
|
{ .name = "ldo9", },
|
|
|
|
{ .name = "ldoln", },
|
|
|
|
{ .name = "ldousb", },
|
|
|
|
{ .name = "regen1", },
|
|
|
|
{ .name = "regen2", },
|
|
|
|
{ .name = "regen3", },
|
|
|
|
{ .name = "sysen1", },
|
|
|
|
{ .name = "sysen2", },
|
|
|
|
};
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-06-18 17:59:00 +08:00
|
|
|
static struct of_regulator_match tps65917_matches[] = {
|
|
|
|
{ .name = "smps1", },
|
|
|
|
{ .name = "smps2", },
|
|
|
|
{ .name = "smps3", },
|
|
|
|
{ .name = "smps4", },
|
|
|
|
{ .name = "smps5", },
|
|
|
|
{ .name = "ldo1", },
|
|
|
|
{ .name = "ldo2", },
|
|
|
|
{ .name = "ldo3", },
|
|
|
|
{ .name = "ldo4", },
|
|
|
|
{ .name = "ldo5", },
|
|
|
|
{ .name = "regen1", },
|
|
|
|
{ .name = "regen2", },
|
|
|
|
{ .name = "regen3", },
|
|
|
|
{ .name = "sysen1", },
|
|
|
|
{ .name = "sysen2", },
|
|
|
|
};
|
|
|
|
|
2014-06-30 23:57:34 +08:00
|
|
|
static struct palmas_pmic_driver_data palmas_ddata = {
|
2014-06-18 17:58:59 +08:00
|
|
|
.smps_start = PALMAS_REG_SMPS12,
|
|
|
|
.smps_end = PALMAS_REG_SMPS10_OUT1,
|
|
|
|
.ldo_begin = PALMAS_REG_LDO1,
|
|
|
|
.ldo_end = PALMAS_REG_LDOUSB,
|
|
|
|
.max_reg = PALMAS_NUM_REGS,
|
2015-03-17 18:26:05 +08:00
|
|
|
.has_regen3 = true,
|
2014-06-30 23:57:37 +08:00
|
|
|
.palmas_regs_info = palmas_generic_regs_info,
|
2014-06-18 17:58:59 +08:00
|
|
|
.palmas_matches = palmas_matches,
|
|
|
|
.sleep_req_info = palma_sleep_req_info,
|
|
|
|
.smps_register = palmas_smps_registration,
|
|
|
|
.ldo_register = palmas_ldo_registration,
|
|
|
|
};
|
2013-04-17 17:43:12 +08:00
|
|
|
|
2014-06-30 23:57:34 +08:00
|
|
|
static struct palmas_pmic_driver_data tps65917_ddata = {
|
2014-06-18 17:59:00 +08:00
|
|
|
.smps_start = TPS65917_REG_SMPS1,
|
|
|
|
.smps_end = TPS65917_REG_SMPS5,
|
|
|
|
.ldo_begin = TPS65917_REG_LDO1,
|
|
|
|
.ldo_end = TPS65917_REG_LDO5,
|
|
|
|
.max_reg = TPS65917_NUM_REGS,
|
2015-03-17 18:26:05 +08:00
|
|
|
.has_regen3 = true,
|
2014-06-18 17:59:00 +08:00
|
|
|
.palmas_regs_info = tps65917_regs_info,
|
|
|
|
.palmas_matches = tps65917_matches,
|
|
|
|
.sleep_req_info = tps65917_sleep_req_info,
|
|
|
|
.smps_register = tps65917_smps_registration,
|
|
|
|
.ldo_register = tps65917_ldo_registration,
|
|
|
|
};
|
|
|
|
|
2016-05-06 08:29:51 +08:00
|
|
|
static int palmas_dt_to_pdata(struct device *dev,
|
|
|
|
struct device_node *node,
|
|
|
|
struct palmas_pmic_platform_data *pdata,
|
|
|
|
struct palmas_pmic_driver_data *ddata)
|
2014-06-18 17:58:59 +08:00
|
|
|
{
|
|
|
|
struct device_node *regulators;
|
|
|
|
u32 prop;
|
|
|
|
int idx, ret;
|
2013-04-17 17:43:13 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
regulators = of_get_child_by_name(node, "regulators");
|
|
|
|
if (!regulators) {
|
|
|
|
dev_info(dev, "regulator node not found\n");
|
2016-05-06 08:29:51 +08:00
|
|
|
return 0;
|
2014-06-18 17:58:59 +08:00
|
|
|
}
|
2013-09-10 19:18:07 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
ret = of_regulator_match(dev, regulators, ddata->palmas_matches,
|
|
|
|
ddata->max_reg);
|
|
|
|
of_node_put(regulators);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
|
2016-05-06 08:29:51 +08:00
|
|
|
return 0;
|
2014-06-18 17:58:59 +08:00
|
|
|
}
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
for (idx = 0; idx < ddata->max_reg; idx++) {
|
2016-05-06 08:29:49 +08:00
|
|
|
static struct of_regulator_match *match;
|
2016-05-06 08:29:50 +08:00
|
|
|
struct palmas_reg_init *rinit;
|
2016-05-06 08:29:52 +08:00
|
|
|
struct device_node *np;
|
2016-05-06 08:29:49 +08:00
|
|
|
|
|
|
|
match = &ddata->palmas_matches[idx];
|
2016-05-06 08:29:52 +08:00
|
|
|
np = match->of_node;
|
2016-05-06 08:29:49 +08:00
|
|
|
|
2016-05-06 08:29:52 +08:00
|
|
|
if (!match->init_data || !np)
|
2014-06-18 17:58:59 +08:00
|
|
|
continue;
|
2012-05-18 23:53:57 +08:00
|
|
|
|
2016-05-06 08:29:50 +08:00
|
|
|
rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL);
|
2016-05-06 08:29:51 +08:00
|
|
|
if (!rinit)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-05-06 08:29:49 +08:00
|
|
|
pdata->reg_data[idx] = match->init_data;
|
2016-05-06 08:29:50 +08:00
|
|
|
pdata->reg_init[idx] = rinit;
|
2012-08-28 19:47:40 +08:00
|
|
|
|
2016-05-06 08:29:52 +08:00
|
|
|
rinit->warm_reset = of_property_read_bool(np, "ti,warm-reset");
|
|
|
|
ret = of_property_read_u32(np, "ti,roof-floor", &prop);
|
2014-06-18 17:58:59 +08:00
|
|
|
/* EINVAL: Property not found */
|
|
|
|
if (ret != -EINVAL) {
|
|
|
|
int econtrol;
|
|
|
|
|
|
|
|
/* use default value, when no value is specified */
|
|
|
|
econtrol = PALMAS_EXT_CONTROL_NSLEEP;
|
|
|
|
if (!ret) {
|
|
|
|
switch (prop) {
|
|
|
|
case 1:
|
|
|
|
econtrol = PALMAS_EXT_CONTROL_ENABLE1;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
econtrol = PALMAS_EXT_CONTROL_ENABLE2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
econtrol = PALMAS_EXT_CONTROL_NSLEEP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN_ON(1);
|
|
|
|
dev_warn(dev,
|
|
|
|
"%s: Invalid roof-floor option: %u\n",
|
2016-05-06 08:29:49 +08:00
|
|
|
match->name, prop);
|
2014-06-18 17:58:59 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
2016-05-06 08:29:50 +08:00
|
|
|
rinit->roof_floor = econtrol;
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
|
|
|
|
2016-05-06 08:29:52 +08:00
|
|
|
ret = of_property_read_u32(np, "ti,mode-sleep", &prop);
|
2014-06-18 17:58:59 +08:00
|
|
|
if (!ret)
|
2016-05-06 08:29:50 +08:00
|
|
|
rinit->mode_sleep = prop;
|
2013-04-17 17:43:13 +08:00
|
|
|
|
2016-05-06 08:29:52 +08:00
|
|
|
ret = of_property_read_bool(np, "ti,smps-range");
|
2014-06-18 17:58:59 +08:00
|
|
|
if (ret)
|
2016-05-06 08:29:50 +08:00
|
|
|
rinit->vsel = PALMAS_SMPS12_VOLTAGE_RANGE;
|
2014-06-18 17:58:59 +08:00
|
|
|
|
|
|
|
if (idx == PALMAS_REG_LDO8)
|
|
|
|
pdata->enable_ldo8_tracking = of_property_read_bool(
|
2016-05-06 08:29:52 +08:00
|
|
|
np, "ti,enable-ldo8-tracking");
|
2014-06-18 17:58:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator");
|
2016-05-06 08:29:51 +08:00
|
|
|
|
|
|
|
return 0;
|
2012-05-18 23:53:57 +08:00
|
|
|
}
|
|
|
|
|
2015-03-17 03:17:08 +08:00
|
|
|
static const struct of_device_id of_palmas_match_tbl[] = {
|
2014-06-18 17:58:59 +08:00
|
|
|
{
|
|
|
|
.compatible = "ti,palmas-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,twl6035-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,twl6036-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,twl6037-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,tps65913-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,tps65914-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,tps80036-pmic",
|
|
|
|
.data = &palmas_ddata,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,tps659038-pmic",
|
|
|
|
.data = &palmas_ddata,
|
2014-06-18 17:59:00 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.compatible = "ti,tps65917-pmic",
|
|
|
|
.data = &tps65917_ddata,
|
2014-06-18 17:58:59 +08:00
|
|
|
},
|
2012-08-28 19:47:40 +08:00
|
|
|
{ /* end */ }
|
|
|
|
};
|
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
static int palmas_regulators_probe(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
|
|
|
|
struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
|
|
|
struct device_node *node = pdev->dev.of_node;
|
|
|
|
struct palmas_pmic_driver_data *driver_data;
|
|
|
|
struct regulator_config config = { };
|
|
|
|
struct palmas_pmic *pmic;
|
|
|
|
const char *pdev_name;
|
|
|
|
const struct of_device_id *match;
|
|
|
|
int ret = 0;
|
|
|
|
unsigned int reg;
|
|
|
|
|
|
|
|
match = of_match_device(of_match_ptr(of_palmas_match_tbl), &pdev->dev);
|
|
|
|
|
|
|
|
if (!match)
|
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
driver_data = (struct palmas_pmic_driver_data *)match->data;
|
|
|
|
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
if (!pdata)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
|
|
|
|
if (!pmic)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2015-03-17 18:26:05 +08:00
|
|
|
if (of_device_is_compatible(node, "ti,tps659038-pmic")) {
|
2015-03-17 18:26:04 +08:00
|
|
|
palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr =
|
|
|
|
TPS659038_REGEN2_CTRL;
|
2015-03-17 18:26:05 +08:00
|
|
|
palmas_ddata.has_regen3 = false;
|
|
|
|
}
|
2015-03-17 18:26:04 +08:00
|
|
|
|
2014-06-18 17:58:59 +08:00
|
|
|
pmic->dev = &pdev->dev;
|
|
|
|
pmic->palmas = palmas;
|
|
|
|
palmas->pmic = pmic;
|
|
|
|
platform_set_drvdata(pdev, pmic);
|
|
|
|
pmic->palmas->pmic_ddata = driver_data;
|
|
|
|
|
2016-05-06 08:29:51 +08:00
|
|
|
ret = palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2014-06-18 17:58:59 +08:00
|
|
|
|
|
|
|
ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN)
|
|
|
|
pmic->smps123 = 1;
|
|
|
|
|
|
|
|
if (reg & PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN)
|
|
|
|
pmic->smps457 = 1;
|
|
|
|
|
|
|
|
config.regmap = palmas->regmap[REGULATOR_SLAVE];
|
|
|
|
config.dev = &pdev->dev;
|
|
|
|
config.driver_data = pmic;
|
|
|
|
pdev_name = pdev->name;
|
|
|
|
|
|
|
|
ret = driver_data->smps_register(pmic, driver_data, pdata, pdev_name,
|
|
|
|
config);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = driver_data->ldo_register(pmic, driver_data, pdata, pdev_name,
|
|
|
|
config);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-05-18 23:53:57 +08:00
|
|
|
static struct platform_driver palmas_driver = {
|
|
|
|
.driver = {
|
|
|
|
.name = "palmas-pmic",
|
2012-08-28 19:47:40 +08:00
|
|
|
.of_match_table = of_palmas_match_tbl,
|
2012-05-18 23:53:57 +08:00
|
|
|
},
|
2013-03-18 17:29:49 +08:00
|
|
|
.probe = palmas_regulators_probe,
|
2012-05-18 23:53:57 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init palmas_init(void)
|
|
|
|
{
|
|
|
|
return platform_driver_register(&palmas_driver);
|
|
|
|
}
|
|
|
|
subsys_initcall(palmas_init);
|
|
|
|
|
|
|
|
static void __exit palmas_exit(void)
|
|
|
|
{
|
|
|
|
platform_driver_unregister(&palmas_driver);
|
|
|
|
}
|
|
|
|
module_exit(palmas_exit);
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
|
|
|
|
MODULE_DESCRIPTION("Palmas voltage regulator driver");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_ALIAS("platform:palmas-pmic");
|
2012-08-28 19:47:40 +08:00
|
|
|
MODULE_DEVICE_TABLE(of, of_palmas_match_tbl);
|