All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Andrey Zhizhikin <andrey.z@gmail.com>,
	Hans de Goede <hdegoede@redhat.com>,
	Adrian Hunter <adrian.hunter@intel.com>
Cc: lgirdwood@gmail.com, broonie@kernel.org, lee.jones@linaro.org,
	linux-kernel@vger.kernel.org,
	Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com>
Subject: Re: [PATCH 1/2] regulator: add support for Intel Cherry Whiskey Cove regulator
Date: Fri, 25 Oct 2019 11:01:29 +0300	[thread overview]
Message-ID: <20191025080129.GE32742@smile.fi.intel.com> (raw)
In-Reply-To: <20191024142939.25920-2-andrey.zhizhikin@leica-geosystems.com>

On Thu, Oct 24, 2019 at 02:29:38PM +0000, Andrey Zhizhikin wrote:
> Add regulator driver for Intel Cherry Trail Whiskey Cove PMIC, which
> supplies various voltage rails.
> 
> This initial version supports only vsdio, which is required to source
> vqmmc for sd card interface.

This patch has some style issues. I will wait for Adrian and Hans to comment on
the approach as a whole and then we will see how to improve the rest.

> Signed-off-by: Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com>
> ---
>  drivers/regulator/Kconfig                     |  10 +
>  drivers/regulator/Makefile                    |   1 +
>  drivers/regulator/intel-cht-wc-regulator.c    | 433 ++++++++++++++++++
>  .../linux/regulator/intel-cht-wc-regulator.h  |  64 +++
>  4 files changed, 508 insertions(+)
>  create mode 100644 drivers/regulator/intel-cht-wc-regulator.c
>  create mode 100644 include/linux/regulator/intel-cht-wc-regulator.h
> 
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 3ee63531f6d5..ae3d57f572df 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -1077,6 +1077,16 @@ config REGULATOR_VEXPRESS
>  	  This driver provides support for voltage regulators available
>  	  on the ARM Ltd's Versatile Express platform.
>  
> +config REGULATOR_WHISKEY_COVE
> +	tristate "PMIC Whiskey Cove voltage regulator"
> +	depends on INTEL_SOC_PMIC_CHTWC
> +	help
> +	  This driver provides support for the voltage regulators of the
> +	  Intel Whiskey Cove PMIC. It is provided as an mfd cell of the
> +	  Intel Cherry Trail PMIC driver.
> +	  Only select this regulator driver if the MFD part is selected
> +	  in the Kernel configuration, it is meant to be operable as a cell.
> +
>  config REGULATOR_WM831X
>  	tristate "Wolfson Microelectronics WM831x PMIC regulators"
>  	depends on MFD_WM831X
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 2210ba56f9bd..380d536126c6 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -132,6 +132,7 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
>  obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
>  obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
>  obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
> +obj-$(CONFIG_REGULATOR_WHISKEY_COVE) += intel-cht-wc-regulator.o
>  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
>  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
>  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
> diff --git a/drivers/regulator/intel-cht-wc-regulator.c b/drivers/regulator/intel-cht-wc-regulator.c
> new file mode 100644
> index 000000000000..5a66a6b37dc6
> --- /dev/null
> +++ b/drivers/regulator/intel-cht-wc-regulator.c
> @@ -0,0 +1,433 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * intel-cht-wc-regulator.c - CherryTrail regulator driver
> + *
> + * Copyright (c) 2019, Leica Geosystems AG
> + *
> + * Base on the non-upstreamed version from Intel,
> + * which was introduced for Intel Aero board.
> + * Copyright (c) 2014, Intel Corporation.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/mfd/intel_soc_pmic.h>
> +#include <linux/regulator/intel-cht-wc-regulator.h>
> +
> +
> +/*
> + * Voltage Control regulator offsets
> + */
> +
> +/* buck boost regulators */
> +#define CHT_WC_V3P3A_CTRL	0x6e5e
> +/* buck regulators */
> +#define CHT_WC_V1P8A_CTRL	0x6e56
> +#define CHT_WC_V1P05A_CTRL	0x6e3b
> +#define CHT_WC_V1P15_CTRL	0x6e3c
> +#define CHT_WC_VDDQ_CTRL	0x6e58
> +/* boot regulators */
> +/* ldo regulators */
> +#define CHT_WC_VPROG1A_CTRL	0x6e90
> +#define CHT_WC_VPROG1B_CTRL	0x6e91
> +#define CHT_WC_VPROG1F_CTRL	0x6e95
> +#define CHT_WC_V1P8SX_CTRL	0x6e57
> +#define CHT_WC_V1P2A_CTRL	0x6e59
> +#define CHT_WC_V1P2SX_CTRL	0x6e5a
> +#define CHT_WC_VSDIO_CTRL	0x6e67
> +#define CHT_WC_V2P8SX_CTRL	0x6e5d
> +#define CHT_WC_V3P3SD_CTRL	0x6e5f
> +#define CHT_WC_VPROG2D_CTRL	0x6e99
> +#define CHT_WC_VPROG3A_CTRL	0x6e9a
> +#define CHT_WC_VPROG3B_CTRL	0x6e9b
> +#define CHT_WC_VPROG4A_CTRL	0x6e9c
> +#define CHT_WC_VPROG4B_CTRL	0x6e9d
> +#define CHT_WC_VPROG4C_CTRL	0x6e9e
> +#define CHT_WC_VPROG4D_CTRL	0x6e9f
> +#define CHT_WC_VPROG5A_CTRL	0x6ea0
> +#define CHT_WC_VPROG5B_CTRL	0x6ea1
> +#define CHT_WC_VPROG6A_CTRL	0x6ea2
> +#define CHT_WC_VPROG6B_CTRL	0x6ea3
> +
> +
> +/*
> + * Voltage Selector regulator offsets
> + */
> +
> +/* buck boost regulators */
> +#define CHT_WC_V3P3A_VSEL	0x6e68
> +/* buck regulators */
> +#define CHT_WC_V1P8A_VSEL	0x6e5b
> +#define CHT_WC_V1P05A_VSEL	0x6e3d
> +#define CHT_WC_V1P15_VSEL	0x6e3e
> +#define CHT_WC_VDDQ_VSEL		0x6e5c
> +/* boot regulators */
> +/* ldo regulators */
> +#define CHT_WC_VPROG1A_VSEL	0x6ec0
> +#define CHT_WC_VPROG1B_VSEL	0x6ec1
> +#define CHT_WC_V1P8SX_VSEL	0x6ec2
> +#define CHT_WC_V1P2SX_VSEL	0x6ec3
> +#define CHT_WC_V1P2A_VSEL	0x6ec4
> +#define CHT_WC_VPROG1F_VSEL	0x6ec5
> +#define CHT_WC_VSDIO_VSEL	0x6ec6
> +#define CHT_WC_V2P8SX_VSEL	0x6ec7
> +#define CHT_WC_V3P3SD_VSEL	0x6ec8
> +#define CHT_WC_VPROG2D_VSEL	0x6ec9
> +#define CHT_WC_VPROG3A_VSEL	0x6eca
> +#define CHT_WC_VPROG3B_VSEL	0x6ecb
> +#define CHT_WC_VPROG4A_VSEL	0x6ecc
> +#define CHT_WC_VPROG4B_VSEL	0x6ecd
> +#define CHT_WC_VPROG4C_VSEL	0x6ece
> +#define CHT_WC_VPROG4D_VSEL	0x6ecf
> +#define CHT_WC_VPROG5A_VSEL	0x6ed0
> +#define CHT_WC_VPROG5B_VSEL	0x6ed1
> +#define CHT_WC_VPROG6A_VSEL	0x6ed2
> +#define CHT_WC_VPROG6B_VSEL	0x6ed3
> +
> +
> +/* number of voltage variations exposed */
> +
> +/* buck boost regulators */
> +#define CHT_WC_V3P3A_VRANGE	8
> +/* buck regulators */
> +#define CHT_WC_V1P8A_VRANGE	256
> +#define CHT_WC_V1P05A_VRANGE	256
> +#define CHT_WC_VDDQ_VRANGE	120
> +/* boot regulators */
> +/* ldo regulators */
> +#define CHT_WC_VPROG1A_VRANGE	53
> +#define CHT_WC_VPROG1B_VRANGE	53
> +#define CHT_WC_VPROG1F_VRANGE	53
> +#define CHT_WC_V1P8SX_VRANGE	53
> +#define CHT_WC_V1P2SX_VRANGE	53
> +#define CHT_WC_V1P2A_VRANGE	53
> +#define CHT_WC_VSDIO_VRANGE	53
> +#define CHT_WC_V2P8SX_VRANGE	53
> +#define CHT_WC_V3P3SD_VRANGE	53
> +#define CHT_WC_VPROG2D_VRANGE	53
> +#define CHT_WC_VPROG3A_VRANGE	53
> +#define CHT_WC_VPROG3B_VRANGE	53
> +#define CHT_WC_VPROG4A_VRANGE	53
> +#define CHT_WC_VPROG4B_VRANGE	53
> +#define CHT_WC_VPROG4C_VRANGE	53
> +#define CHT_WC_VPROG4D_VRANGE	53
> +#define CHT_WC_VPROG5A_VRANGE	53
> +#define CHT_WC_VPROG5B_VRANGE	53
> +#define CHT_WC_VPROG6A_VRANGE	53
> +#define CHT_WC_VPROG6B_VRANGE	53
> +
> +
> +/* voltage tables */
> +static unsigned int CHT_WC_V3P3A_VSEL_TABLE[CHT_WC_V3P3A_VRANGE],
> +		    CHT_WC_V1P8A_VSEL_TABLE[CHT_WC_V1P8A_VRANGE],
> +		    CHT_WC_V1P05A_VSEL_TABLE[CHT_WC_V1P05A_VRANGE],
> +		    CHT_WC_VDDQ_VSEL_TABLE[CHT_WC_VDDQ_VRANGE],
> +		    CHT_WC_V1P8SX_VSEL_TABLE[CHT_WC_V1P8SX_VRANGE],
> +		    CHT_WC_V1P2SX_VSEL_TABLE[CHT_WC_V1P2SX_VRANGE],
> +		    CHT_WC_V1P2A_VSEL_TABLE[CHT_WC_V1P2A_VRANGE],
> +		    CHT_WC_V2P8SX_VSEL_TABLE[CHT_WC_V2P8SX_VRANGE],
> +		    CHT_WC_V3P3SD_VSEL_TABLE[CHT_WC_V3P3SD_VRANGE],
> +		    CHT_WC_VPROG1A_VSEL_TABLE[CHT_WC_VPROG1A_VRANGE],
> +		    CHT_WC_VPROG1B_VSEL_TABLE[CHT_WC_VPROG1B_VRANGE],
> +		    CHT_WC_VPROG1F_VSEL_TABLE[CHT_WC_VPROG1F_VRANGE],
> +		    CHT_WC_VPROG2D_VSEL_TABLE[CHT_WC_VPROG2D_VRANGE],
> +		    CHT_WC_VPROG3A_VSEL_TABLE[CHT_WC_VPROG3A_VRANGE],
> +		    CHT_WC_VPROG3B_VSEL_TABLE[CHT_WC_VPROG3B_VRANGE],
> +		    CHT_WC_VPROG4A_VSEL_TABLE[CHT_WC_VPROG4A_VRANGE],
> +		    CHT_WC_VPROG4B_VSEL_TABLE[CHT_WC_VPROG4B_VRANGE],
> +		    CHT_WC_VPROG4C_VSEL_TABLE[CHT_WC_VPROG4C_VRANGE],
> +		    CHT_WC_VPROG4D_VSEL_TABLE[CHT_WC_VPROG4D_VRANGE],
> +		    CHT_WC_VPROG5A_VSEL_TABLE[CHT_WC_VPROG5A_VRANGE],
> +		    CHT_WC_VPROG5B_VSEL_TABLE[CHT_WC_VPROG5B_VRANGE],
> +		    CHT_WC_VPROG6A_VSEL_TABLE[CHT_WC_VPROG6A_VRANGE],
> +		    CHT_WC_VPROG6B_VSEL_TABLE[CHT_WC_VPROG6B_VRANGE];
> +
> +/*
> + * VSDIO regulator description, voltage tables, consumers and constraints
> + */
> +/*
> + * The VSDIO regulator should only support 1.8V and 3.3V. All other
> + * voltages are invalid for sd card, so disable them here.
> + */
> +static unsigned int CHT_WC_VSDIO_VSEL_TABLE[CHT_WC_VSDIO_VRANGE] = {
> +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0, 1800000, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 3300000, 0, 0
> +};
> +
> +/* List the SD card interface as a consumer of vqmmc voltage source from VSDIO
> + * regulator. This is the only interface that requires this source on Cherry
> + * Trail to operate with UHS-I cards.
> + */
> +static struct regulator_consumer_supply cht_wc_vqmmc_supply_consumer[] = {
> +	REGULATOR_SUPPLY("vqmmc", "80860F14:02"),
> +};
> +
> +static struct regulator_init_data vqmmc_init_data = {
> +	.constraints = {
> +		.min_uV			= 1800000,
> +		.max_uV			= 3300000,
> +		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE |
> +					REGULATOR_CHANGE_STATUS,
> +		.valid_modes_mask	= REGULATOR_MODE_NORMAL,
> +		.settling_time		= 20000,
> +	},
> +	.num_consumer_supplies	= ARRAY_SIZE(cht_wc_vqmmc_supply_consumer),
> +	.consumer_supplies	= cht_wc_vqmmc_supply_consumer,
> +};
> +
> +static int cht_wc_regulator_enable(struct regulator_dev *rdev)
> +{
> +	struct ch_wc_regulator_info *pmic_info = rdev_get_drvdata(rdev);
> +
> +	int ret = regmap_update_bits(rdev->regmap, pmic_info->vctl_reg,
> +			pmic_info->vctl_mask, pmic_info->reg_enbl_mask);
> +	if (ret < 0)
> +		dev_err(&rdev->dev, "Failed to enable regulator %s: %d\n",
> +			pmic_info->desc.name, ret);
> +
> +	return ret;
> +}
> +
> +static int cht_wc_regulator_disable(struct regulator_dev *rdev)
> +{
> +	struct ch_wc_regulator_info *pmic_info = rdev_get_drvdata(rdev);
> +
> +	int ret = regmap_update_bits(rdev->regmap, pmic_info->vctl_reg,
> +			pmic_info->vctl_mask, pmic_info->reg_dsbl_mask);
> +	if (ret < 0)
> +		dev_err(&rdev->dev, "Failed to disable regulator %s: %d\n",
> +			pmic_info->desc.name, ret);
> +
> +	return ret;
> +}
> +
> +static int cht_wc_regulator_is_enabled(struct regulator_dev *rdev)
> +{
> +	struct ch_wc_regulator_info *pmic_info = rdev_get_drvdata(rdev);
> +	int rval;
> +
> +	int ret = regmap_read(rdev->regmap, pmic_info->vctl_reg, &rval);
> +
> +	if (ret < 0) {
> +		dev_err(&rdev->dev, "Register 0x%04x read failed: %d\n",
> +			pmic_info->vsel_reg, ret);
> +		return ret;
> +	}
> +
> +	rval &= pmic_info->vctl_mask;
> +
> +	return rval & pmic_info->reg_enbl_mask;
> +}
> +
> +static int cht_wc_regulator_read_voltage_sel(struct regulator_dev *rdev)
> +{
> +	struct ch_wc_regulator_info *pmic_info = rdev_get_drvdata(rdev);
> +	int rval;
> +
> +	int ret = regmap_read(rdev->regmap, pmic_info->vsel_reg, &rval);
> +
> +	if (ret < 0) {
> +		dev_err(&rdev->dev, "Register 0x%04x read failed: %d\n",
> +			pmic_info->vsel_reg, ret);
> +		return ret;
> +	}
> +
> +	return (rval & pmic_info->vsel_mask) - pmic_info->start;
> +}
> +
> +static int cht_wc_regulator_set_voltage_sel(struct regulator_dev *rdev,
> +		unsigned int selector)
> +{
> +	struct ch_wc_regulator_info *pmic_info = rdev_get_drvdata(rdev);
> +
> +	int ret = regmap_update_bits(rdev->regmap, pmic_info->vsel_reg,
> +			pmic_info->vsel_mask, selector + pmic_info->start);
> +	if (ret < 0)
> +		dev_err(&rdev->dev, "Failed to set voltage for regulator %s: %d\n",
> +			pmic_info->desc.name, ret);
> +
> +	return ret;
> +}
> +
> +/* regulator ops */
> +static struct regulator_ops wcove_regulator_ops = {
> +	.enable			= cht_wc_regulator_enable,
> +	.disable		= cht_wc_regulator_disable,
> +	.is_enabled		= cht_wc_regulator_is_enabled,
> +	.get_voltage_sel	= cht_wc_regulator_read_voltage_sel,
> +	.set_voltage_sel	= cht_wc_regulator_set_voltage_sel,
> +	.list_voltage		= regulator_list_voltage_table,
> +};
> +
> +#define CHT_WC_REGULATOR(_id, minv, maxv, strt, vselmsk, vscale, \
> +				vctlmsk, enbl, dsbl, rt_flag, _init_data) \
> +{\
> +	.desc = {\
> +		.name		= ""#_id,\
> +		.ops		= &wcove_regulator_ops,\
> +		.type		= REGULATOR_VOLTAGE,\
> +		.id		= CHT_WC_REGULATOR_##_id,\
> +		.owner		= THIS_MODULE,\
> +	},\
> +	.rdev		= NULL, \
> +	.init_data	= (_init_data), \
> +	.vctl_reg	= CHT_WC_##_id##_CTRL,\
> +	.vsel_reg	= CHT_WC_##_id##_VSEL,\
> +	.min_mV		= (minv),\
> +	.max_mV		= (maxv),\
> +	.start		= (strt),\
> +	.vsel_mask	= (vselmsk),\
> +	.scale		= (vscale),\
> +	.nvolts		= CHT_WC_##_id##_VRANGE,\
> +	.vctl_mask	= (vctlmsk),\
> +	.reg_enbl_mask	= (enbl),\
> +	.reg_dsbl_mask	= (dsbl),\
> +	.vtable		= CHT_WC_##_id##_VSEL_TABLE,\
> +	.runtime_table	= (rt_flag),\
> +}
> +
> +/* Regulator descriptions */
> +static struct ch_wc_regulator_info regulators_info[] = {
> +	CHT_WC_REGULATOR(V3P3A,    3000, 3350, 0x00, 0x07, 50, 0x01, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V1P8A,    250,  2100, 0x00, 0xff, 10, 0x01, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V1P05A,   250,  2100, 0x00, 0xff, 10, 0x01, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VDDQ,     250,  1440, 0x00, 0x7f, 10, 0x01, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V1P8SX,   800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V1P2A,    800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V1P2SX,   800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(V2P8SX,   800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VSDIO,    800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, false, &vqmmc_init_data),
> +	CHT_WC_REGULATOR(V3P3SD,   800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG1A,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG1B,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG1F,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG2D,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG3A,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG3B,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG4A,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG4B,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG4C,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG4D,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG5A,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG5B,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG6A,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +	CHT_WC_REGULATOR(VPROG6B,  800,  3400, 0x0b, 0x3f, 50, 0x07, 0x01, 0x0, true,  NULL),
> +};
> +
> +static inline struct ch_wc_regulator_info *cht_wc_find_regulator_info(int id)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(regulators_info); i++) {
> +		if (regulators_info[i].desc.id == id)
> +			return &regulators_info[i];
> +	}
> +	return NULL;
> +}
> +
> +static void initialize_vtable(struct ch_wc_regulator_info *reg_info)
> +{
> +	unsigned int i, volt;
> +
> +	if (reg_info->runtime_table == true) {
> +		for (i = 0; i < reg_info->nvolts; i++) {
> +			volt = reg_info->min_mV + (i * reg_info->scale);
> +			if (volt < reg_info->min_mV)
> +				volt = reg_info->min_mV;
> +			if (volt > reg_info->max_mV)
> +				volt = reg_info->max_mV;
> +			/* set value in uV */
> +			reg_info->vtable[i] = volt*1000;
> +		}
> +	}
> +	reg_info->desc.volt_table = reg_info->vtable;
> +	reg_info->desc.n_voltages = reg_info->nvolts;
> +}
> +
> +static int cht_wc_regulator_probe(struct platform_device *pdev)
> +{
> +	struct ch_wc_regulator_info *regulator;
> +	struct regulator_config config = { };
> +
> +	struct ch_wc_regulator_info *reg_info =
> +		cht_wc_find_regulator_info(pdev->id);
> +
> +	if (reg_info == NULL)
> +		return -EINVAL;
> +
> +	regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
> +	if (!regulator)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, regulator);
> +
> +	initialize_vtable(reg_info);
> +
> +	config.dev = &pdev->dev;
> +	config.driver_data = reg_info;
> +	config.init_data = reg_info->init_data;
> +
> +	regulator->rdev = regulator_register(&reg_info->desc, &config);
> +
> +	if (IS_ERR(regulator->rdev)) {
> +		dev_err(&pdev->dev, "failed to register regulator as %s\n",
> +				reg_info->desc.name);
> +		return PTR_ERR(regulator->rdev);
> +	}
> +
> +	dev_dbg(&pdev->dev, "registered Whiskey Cove regulator as %s\n",
> +			dev_name(&regulator->rdev->dev));
> +
> +	return 0;
> +}
> +
> +static int cht_wc_regulator_remove(struct platform_device *pdev)
> +{
> +	regulator_unregister(platform_get_drvdata(pdev));
> +	return 0;
> +}
> +
> +static const struct platform_device_id cht_wc_regulator_id_table[] = {
> +	{
> +		.name = "cht_wcove_regulator"
> +	},
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(platform, wcove_regulator_id_table);
> +
> +static struct platform_driver cht_wc_regulator_driver = {
> +	.driver = {
> +		.name = "cht_wcove_regulator",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe    = cht_wc_regulator_probe,
> +	.remove   = cht_wc_regulator_remove,
> +	.id_table = cht_wc_regulator_id_table,
> +};
> +
> +static int __init cht_wc_regulator_init(void)
> +{
> +	return platform_driver_register(&cht_wc_regulator_driver);
> +}
> +subsys_initcall_sync(cht_wc_regulator_init);
> +
> +static void __exit cht_wc_regulator_exit(void)
> +{
> +	platform_driver_unregister(&cht_wc_regulator_driver);
> +}
> +module_exit(cht_wc_regulator_exit);
> +
> +MODULE_ALIAS("platform:cht-wc-regulator");
> +MODULE_DESCRIPTION("Intel Cherry Trail Whiskey Cove Regulator driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com");
> +MODULE_AUTHOR("Nitheesh K L <nitheesh.k.l@intel.com");
> diff --git a/include/linux/regulator/intel-cht-wc-regulator.h b/include/linux/regulator/intel-cht-wc-regulator.h
> new file mode 100644
> index 000000000000..0f6b3be11fea
> --- /dev/null
> +++ b/include/linux/regulator/intel-cht-wc-regulator.h
> @@ -0,0 +1,64 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * intel-cht-wc-regulator.h - Cherry Trail Whiskey Cove PMIC regulator
> + *
> + * Copyright (c) 2019, Leica Geosystems AG
> + *
> + * Base on the non-upstreamed version from Intel, which was
> + * introduced for Intel Aero board.
> + * Copyright (c) 2014, Intel Corporation.
> + */
> +
> +#ifndef __LINUX_REGULATOR_INTEL_CHT_WC_H_
> +#define __LINUX_REGULATOR_INTEL_CHT_WC_H_
> +
> +#include <linux/regulator/driver.h>
> +
> +enum {
> +	CHT_WC_REGULATOR_V1P8A = 1,
> +	CHT_WC_REGULATOR_V1P05A,
> +	CHT_WC_REGULATOR_V1P15,
> +	CHT_WC_REGULATOR_VDDQ,
> +	CHT_WC_REGULATOR_V3P3A,
> +	CHT_WC_REGULATOR_VPROG1A,
> +	CHT_WC_REGULATOR_VPROG1B,
> +	CHT_WC_REGULATOR_VPROG1F,
> +	CHT_WC_REGULATOR_V1P8SX,
> +	CHT_WC_REGULATOR_V1P2SX,
> +	CHT_WC_REGULATOR_V1P2A,
> +	CHT_WC_REGULATOR_VSDIO,
> +	CHT_WC_REGULATOR_V2P8SX,
> +	CHT_WC_REGULATOR_V3P3SD,
> +	CHT_WC_REGULATOR_VPROG2D,
> +	CHT_WC_REGULATOR_VPROG3A,
> +	CHT_WC_REGULATOR_VPROG3B,
> +	CHT_WC_REGULATOR_VPROG4A,
> +	CHT_WC_REGULATOR_VPROG4B,
> +	CHT_WC_REGULATOR_VPROG4C,
> +	CHT_WC_REGULATOR_VPROG4D,
> +	CHT_WC_REGULATOR_VPROG5A,
> +	CHT_WC_REGULATOR_VPROG5B,
> +	CHT_WC_REGULATOR_VPROG6A,
> +	CHT_WC_REGULATOR_VPROG6B,
> +};
> +
> +struct ch_wc_regulator_info {
> +	struct regulator_desc desc;
> +	struct regulator_dev *rdev;
> +	struct regulator_init_data *init_data;
> +	unsigned int vctl_reg;
> +	unsigned int vsel_reg;
> +	unsigned int min_mV;
> +	unsigned int max_mV;
> +	unsigned int start;
> +	unsigned int vsel_mask;
> +	unsigned int scale;
> +	unsigned int nvolts;
> +	unsigned int vctl_mask;
> +	unsigned int reg_enbl_mask;
> +	unsigned int reg_dsbl_mask;
> +	unsigned int *vtable;
> +	bool runtime_table;
> +};
> +
> +#endif /* __LINUX_REGULATOR_INTEL_CHT_WC_H_ */
> -- 
> 2.17.1
> 

-- 
With Best Regards,
Andy Shevchenko



  reply	other threads:[~2019-10-25  8:01 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-24 14:29 [PATCH 0/2] add regulator driver and mfd cell for Intel Cherry Trail Whiskey Cove PMIC Andrey Zhizhikin
2019-10-24 14:29 ` [PATCH 1/2] regulator: add support for Intel Cherry Whiskey Cove regulator Andrey Zhizhikin
2019-10-25  8:01   ` Andy Shevchenko [this message]
2019-10-25  8:58     ` Andrey Zhizhikin
2019-10-25  9:14       ` Andy Shevchenko
2019-10-25  9:31         ` Andrey Zhizhikin
2019-10-25 10:47           ` Andy Shevchenko
2019-10-25 12:17   ` Mark Brown
2019-10-25 15:26     ` Andrey Zhizhikin
2019-10-25 16:02       ` Andy Shevchenko
2019-10-25 16:21         ` Andrey Zhizhikin
2019-10-24 14:29 ` [PATCH 2/2] mfd: add regulator cell to Cherry Trail Whiskey Cove PMIC Andrey Zhizhikin
2019-10-25  8:06   ` Andy Shevchenko
2019-10-25  9:16     ` Andrey Zhizhikin
2019-10-25 10:49       ` Andy Shevchenko
2019-10-25 12:00         ` Andrey Zhizhikin
2019-10-25  7:53 ` [PATCH 0/2] add regulator driver and mfd cell for Intel " Andy Shevchenko
2019-10-25  7:55   ` Andy Shevchenko
2019-10-25  8:51     ` Andrey Zhizhikin
2019-10-28 12:41     ` Adrian Hunter
2019-10-28 12:45       ` Mark Brown
2019-10-28 13:26         ` Hans de Goede
2019-10-28 15:01           ` Andrey Zhizhikin
2019-10-29 12:03             ` Hans de Goede
2019-10-29 16:57               ` Andrey Zhizhikin
2019-10-29 17:14                 ` Hans de Goede
2019-10-28 16:28           ` Andy Shevchenko
2019-10-28 14:40       ` Andrey Zhizhikin
2019-10-25  9:38   ` Hans de Goede
2019-10-25 10:11     ` Andrey Zhizhikin
2019-10-25 10:45       ` Hans de Goede
2019-10-25 11:54         ` Andrey Zhizhikin
2019-10-25 12:05         ` Mark Brown
2019-10-25 12:18           ` Hans de Goede
2019-10-25 10:44     ` Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191025080129.GE32742@smile.fi.intel.com \
    --to=andriy.shevchenko@linux.intel.com \
    --cc=adrian.hunter@intel.com \
    --cc=andrey.z@gmail.com \
    --cc=andrey.zhizhikin@leica-geosystems.com \
    --cc=broonie@kernel.org \
    --cc=hdegoede@redhat.com \
    --cc=lee.jones@linaro.org \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.