diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-26 11:14:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-26 11:14:21 -0700 |
commit | 8900d92fd666d936a7bfb4c567ac26736a414fb4 (patch) | |
tree | 19c37bab5adc8d40d825cb629edf0e8a337955a2 /drivers/regulator | |
parent | c01c0716ccf5db2086d9693033472f37de96a699 (diff) | |
parent | c295d3007ff63064181befa734d9705dfc10b396 (diff) | |
download | linux-8900d92fd666d936a7bfb4c567ac26736a414fb4.tar.gz linux-8900d92fd666d936a7bfb4c567ac26736a414fb4.tar.bz2 linux-8900d92fd666d936a7bfb4c567ac26736a414fb4.zip |
Merge tag 'staging-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging/IIO driver updates from Greg KH:
"Here is the big set of staging and IIO driver updates for 5.13-rc1.
Lots of little churn in here, and some larger churn as well. Major
things are:
- removal of wimax drivers, no one has this hardware anymore for this
failed "experiment".
- removal of the Google gasket driver, turns out no one wanted to
maintain it or cares about it anymore, so they asked for it to be
removed.
- comedi finally moves out of the staging directory into drivers/comedi
This is one of the oldest kernel subsystems around, being created
in the 2.0 kernel days, and was one of the first things added to
drivers/staging/ when that was created over 15 years ago.
It should have been moved out of staging a long time ago, it's well
maintained and used by loads of different devices in the real world
every day. Nice to see this finally happen.
- so many tiny coding style cleanups it's not funny.
Perfect storm of at least 2 different intern project application
deadlines combined to provide a huge number of new contributions in
this area from people learning how to do kernel development. Great
job to everyone involved here.
There's also the normal updates for IIO drivers with new IIO drivers
and updates all over that subsystem.
All of these have been in linux-next for a while with no reported
issues"
* tag 'staging-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (907 commits)
staging: octeon: Use 'for_each_child_of_node'
Staging: rtl8723bs: rtw_xmit: fixed tabbing issue
staging: rtl8188eu: remove unused function parameters
staging: rtl8188eu: cmdThread is a task_struct
staging: rtl8188eu: remove constant variable and dead code
staging: rtl8188eu: change bLeisurePs' type to bool
staging: rtl8723bs: remove empty #ifdef block
staging: rtl8723bs: remove unused DBG_871X_LEVEL macro declarations
staging: rtl8723bs: split too long line
staging: rtl8723bs: fix indentation in if block
staging: rtl8723bs: fix code indent issue
staging: rtl8723bs: replace DBG_871X_LEVEL logs with netdev_*()
staging: rtl8192e: indent statement properly
staging: rtl8723bs: Remove led_blink_hdl() and everything related
staging: comedi: move out of staging directory
staging: rtl8723bs: remove sdio_drv_priv structure
staging: rtl8723bs: remove unused argument in function
staging: rtl8723bs: remove DBG_871X_SEL_NL macro declaration
staging: rtl8723bs: replace DBG_871X_SEL_NL with netdev_dbg()
staging: rtl8723bs: fix indentation issue introduced by long line split
...
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 9 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/hi6421v600-regulator.c | 299 |
3 files changed, 309 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 77c43134bc9e..ea1d284741cb 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -422,6 +422,15 @@ config REGULATOR_HI655X This driver provides support for the voltage regulators of the Hisilicon Hi655x PMIC device. +config REGULATOR_HI6421V600 + tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" + depends on MFD_HI6421_SPMI && OF + select REGMAP + help + This driver provides support for the voltage regulators on + HiSilicon Hi6421v600 PMU / Codec IC. + This is used on Kirin 3670 boards, like HiKey 970. + config REGULATOR_ISL9305 tristate "Intersil ISL9305 regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 44d2f8bf4b74..11c145886c98 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o +obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c new file mode 100644 index 000000000000..f6a14e9c3cbf --- /dev/null +++ b/drivers/regulator/hi6421v600-regulator.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Device driver for regulators in Hisi IC +// +// Copyright (c) 2013 Linaro Ltd. +// Copyright (c) 2011 Hisilicon. +// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd +// +// Guodong Xu <guodong.xu@linaro.org> + +#include <linux/delay.h> +#include <linux/mfd/hi6421-spmi-pmic.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/spmi.h> + +struct hi6421_spmi_reg_info { + struct regulator_desc desc; + struct hi6421_spmi_pmic *pmic; + u8 eco_mode_mask; + u32 eco_uA; + + /* Serialize regulator enable logic */ + struct mutex enable_mutex; +}; + +static const unsigned int ldo3_voltages[] = { + 1500000, 1550000, 1600000, 1650000, + 1700000, 1725000, 1750000, 1775000, + 1800000, 1825000, 1850000, 1875000, + 1900000, 1925000, 1950000, 2000000 +}; + +static const unsigned int ldo4_voltages[] = { + 1725000, 1750000, 1775000, 1800000, + 1825000, 1850000, 1875000, 1900000 +}; + +static const unsigned int ldo9_voltages[] = { + 1750000, 1800000, 1825000, 2800000, + 2850000, 2950000, 3000000, 3300000 +}; + +static const unsigned int ldo15_voltages[] = { + 1800000, 1850000, 2400000, 2600000, + 2700000, 2850000, 2950000, 3000000 +}; + +static const unsigned int ldo17_voltages[] = { + 2500000, 2600000, 2700000, 2800000, + 3000000, 3100000, 3200000, 3300000 +}; + +static const unsigned int ldo34_voltages[] = { + 2600000, 2700000, 2800000, 2900000, + 3000000, 3100000, 3200000, 3300000 +}; + +/** + * HI6421V600_LDO() - specify a LDO power line + * @_id: LDO id name string + * @vtable: voltage table + * @ereg: enable register + * @emask: enable mask + * @vreg: voltage select register + * @odelay: off/on delay time in uS + * @etime: enable time in uS + * @ecomask: eco mode mask + * @ecoamp: eco mode load uppler limit in uA + */ +#define HI6421V600_LDO(_id, vtable, ereg, emask, vreg, \ + odelay, etime, ecomask, ecoamp) \ + [HI6421V600_##_id] = { \ + .desc = { \ + .name = #_id, \ + .of_match = of_match_ptr(#_id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &hi6421_spmi_ldo_rops, \ + .type = REGULATOR_VOLTAGE, \ + .id = HI6421V600_##_id, \ + .owner = THIS_MODULE, \ + .volt_table = vtable, \ + .n_voltages = ARRAY_SIZE(vtable), \ + .vsel_mask = (1 << (ARRAY_SIZE(vtable) - 1)) - 1, \ + .vsel_reg = vreg, \ + .enable_reg = ereg, \ + .enable_mask = emask, \ + .enable_time = etime, \ + .ramp_delay = etime, \ + .off_on_delay = odelay, \ + }, \ + .eco_mode_mask = ecomask, \ + .eco_uA = ecoamp, \ + } + +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) +{ + struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + int ret; + + /* cannot enable more than one regulator at one time */ + mutex_lock(&sreg->enable_mutex); + + ret = regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); + + /* Avoid powering up multiple devices at the same time */ + usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 60); + + mutex_unlock(&sreg->enable_mutex); + + return ret; +} + +static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev) +{ + struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + + return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); +} + +static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) +{ + struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 reg_val; + + regmap_read(pmic->regmap, rdev->desc->enable_reg, ®_val); + + if (reg_val & sreg->eco_mode_mask) + return REGULATOR_MODE_IDLE; + + return REGULATOR_MODE_NORMAL; +} + +static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = 0; + break; + case REGULATOR_MODE_IDLE: + val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1); + break; + default: + return -EINVAL; + } + + return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, + sreg->eco_mode_mask, val); +} + +static unsigned int +hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, + int input_uV, int output_uV, + int load_uA) +{ + struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); + + if (!sreg->eco_uA || ((unsigned int)load_uA > sreg->eco_uA)) + return REGULATOR_MODE_NORMAL; + + return REGULATOR_MODE_IDLE; +} + +static const struct regulator_ops hi6421_spmi_ldo_rops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = hi6421_spmi_regulator_enable, + .disable = hi6421_spmi_regulator_disable, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = hi6421_spmi_regulator_get_mode, + .set_mode = hi6421_spmi_regulator_set_mode, + .get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode, +}; + +/* HI6421v600 regulators with known registers */ +enum hi6421_spmi_regulator_id { + HI6421V600_LDO3, + HI6421V600_LDO4, + HI6421V600_LDO9, + HI6421V600_LDO15, + HI6421V600_LDO16, + HI6421V600_LDO17, + HI6421V600_LDO33, + HI6421V600_LDO34, +}; + +static struct hi6421_spmi_reg_info regulator_info[] = { + HI6421V600_LDO(LDO3, ldo3_voltages, + 0x16, 0x01, 0x51, + 20000, 120, + 0, 0), + HI6421V600_LDO(LDO4, ldo4_voltages, + 0x17, 0x01, 0x52, + 20000, 120, + 0x10, 10000), + HI6421V600_LDO(LDO9, ldo9_voltages, + 0x1c, 0x01, 0x57, + 20000, 360, + 0x10, 10000), + HI6421V600_LDO(LDO15, ldo15_voltages, + 0x21, 0x01, 0x5c, + 20000, 360, + 0x10, 10000), + HI6421V600_LDO(LDO16, ldo15_voltages, + 0x22, 0x01, 0x5d, + 20000, 360, + 0x10, 10000), + HI6421V600_LDO(LDO17, ldo17_voltages, + 0x23, 0x01, 0x5e, + 20000, 120, + 0x10, 10000), + HI6421V600_LDO(LDO33, ldo17_voltages, + 0x32, 0x01, 0x6d, + 20000, 120, + 0, 0), + HI6421V600_LDO(LDO34, ldo34_voltages, + 0x33, 0x01, 0x6e, + 20000, 120, + 0, 0), +}; + +static int hi6421_spmi_regulator_probe(struct platform_device *pdev) +{ + struct device *pmic_dev = pdev->dev.parent; + struct regulator_config config = { }; + struct hi6421_spmi_reg_info *sreg; + struct hi6421_spmi_reg_info *info; + struct device *dev = &pdev->dev; + struct hi6421_spmi_pmic *pmic; + struct regulator_dev *rdev; + int i; + + /* + * This driver is meant to be called by hi6421-spmi-core, + * which should first set drvdata. If this doesn't happen, hit + * a warn on and return. + */ + pmic = dev_get_drvdata(pmic_dev); + if (WARN_ON(!pmic)) + return -ENODEV; + + sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); + if (!sreg) + return -ENOMEM; + + sreg->pmic = pmic; + mutex_init(&sreg->enable_mutex); + + for (i = 0; i < ARRAY_SIZE(regulator_info); i++) { + info = ®ulator_info[i]; + + config.dev = pdev->dev.parent; + config.driver_data = sreg; + config.regmap = pmic->regmap; + + rdev = devm_regulator_register(dev, &info->desc, &config); + if (IS_ERR(rdev)) { + dev_err(dev, "failed to register %s\n", + info->desc.name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id hi6421_spmi_regulator_table[] = { + { .name = "hi6421v600-regulator" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, hi6421_spmi_regulator_table); + +static struct platform_driver hi6421_spmi_regulator_driver = { + .id_table = hi6421_spmi_regulator_table, + .driver = { + .name = "hi6421v600-regulator", + }, + .probe = hi6421_spmi_regulator_probe, +}; +module_platform_driver(hi6421_spmi_regulator_driver); + +MODULE_DESCRIPTION("Hi6421v600 SPMI regulator driver"); +MODULE_LICENSE("GPL v2"); + |