diff mbox

[v1,1/3] mfd: Add new mfd device TPS68470

Message ID 1496750118-5570-2-git-send-email-rajmohan.mani@intel.com
State New
Headers show

Commit Message

Mani, Rajmohan June 6, 2017, 11:55 a.m. UTC
The TPS68470 device is an advanced power management
unit that powers a Compact Camera Module (CCM),
generates clocks for image sensors, drives a dual
LED for Flash and incorporates two LED drivers for
general purpose indicators.

This patch adds support for TPS68470 mfd device.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
---
 drivers/mfd/Kconfig          |  12 +++
 drivers/mfd/Makefile         |   1 +
 drivers/mfd/tps68470.c       | 227 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/tps68470.h | 167 +++++++++++++++++++++++++++++++
 4 files changed, 407 insertions(+)
 create mode 100644 drivers/mfd/tps68470.c
 create mode 100644 include/linux/mfd/tps68470.h

Comments

Heikki Krogerus June 6, 2017, 12:48 p.m. UTC | #1
Hi Rajmohan,

On Tue, Jun 06, 2017 at 04:55:16AM -0700, Rajmohan Mani wrote:
> +/*
> + * tps68470_reg_read: Read a single tps68470 register.
> + *
> + * @tps: Device to read from.
> + * @reg: Register to read.
> + * @val: Contains the value
> + */
> +int tps68470_reg_read(struct tps68470 *tps, unsigned int reg,
> +			unsigned int *val)
> +{
> +	int ret;
> +
> +	mutex_lock(&tps->lock);
> +	ret = regmap_read(tps->regmap, reg, val);
> +	mutex_unlock(&tps->lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tps68470_reg_read);
> +
> +/*
> + * tps68470_reg_write: Write a single tps68470 register.
> + *
> + * @tps68470: Device to write to.
> + * @reg: Register to write to.
> + * @val: Value to write.
> + */
> +int tps68470_reg_write(struct tps68470 *tps, unsigned int reg,
> +			unsigned int val)
> +{
> +	int ret;
> +
> +	mutex_lock(&tps->lock);
> +	ret = regmap_write(tps->regmap, reg, val);
> +	mutex_unlock(&tps->lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tps68470_reg_write);
> +
> +/*
> + * tps68470_update_bits: Modify bits w.r.t mask and val.
> + *
> + * @tps68470: Device to write to.
> + * @reg: Register to read-write to.
> + * @mask: Mask.
> + * @val: Value to write.
> + */
> +int tps68470_update_bits(struct tps68470 *tps, unsigned int reg,
> +				unsigned int mask, unsigned int val)
> +{
> +	int ret;
> +
> +	mutex_lock(&tps->lock);
> +	ret = regmap_update_bits(tps->regmap, reg, mask, val);
> +	mutex_unlock(&tps->lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(tps68470_update_bits);

I'm not sure you need those above wrappers at all, regmap is handling
locking in any case.

> +static const struct regmap_config tps68470_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.max_register = TPS68470_REG_MAX,
> +};
> +
> +static int tps68470_chip_init(struct tps68470 *tps)
> +{
> +	unsigned int version;
> +	int ret;
> +
> +	ret = tps68470_reg_read(tps, TPS68470_REG_REVID, &version);
> +	if (ret < 0) {
> +		dev_err(tps->dev,
> +			"Failed to read revision register: %d\n", ret);
> +		return ret;
> +	}
> +
> +	dev_info(tps->dev, "TPS68470 REVID: 0x%x\n", version);
> +
> +	ret = tps68470_reg_write(tps, TPS68470_REG_RESET, 0xff);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* FIXME: configure these dynamically */
> +	/* Enable Daisy Chain LDO and configure relevant GPIOs as output */
> +	ret = tps68470_reg_write(tps, TPS68470_REG_S_I2C_CTL, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL4A, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL5A, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL6A, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * When SDA and SCL are routed to GPIO1 and GPIO2, the mode
> +	 * for these GPIOs must be configured using their respective
> +	 * GPCTLxA registers as inputs with no pull-ups.
> +	 */
> +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL1A, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL2A, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Enable daisy chain */
> +	ret = tps68470_update_bits(tps, TPS68470_REG_S_I2C_CTL, 1, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	usleep_range(TPS68470_DAISY_CHAIN_DELAY_US,
> +			TPS68470_DAISY_CHAIN_DELAY_US + 10);
> +	return 0;
> +}
> +
> +static int tps68470_probe(struct i2c_client *client)
> +{
> +	struct tps68470 *tps;
> +	int ret;
> +
> +	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
> +	if (!tps)
> +		return -ENOMEM;
> +
> +	mutex_init(&tps->lock);
> +	i2c_set_clientdata(client, tps);
> +	tps->dev = &client->dev;
> +
> +	tps->regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
> +	if (IS_ERR(tps->regmap)) {
> +		dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
> +		return PTR_ERR(tps->regmap);
> +	}
> +
> +	ret = mfd_add_devices(tps->dev, -1, tps68470s,
> +			      ARRAY_SIZE(tps68470s), NULL, 0, NULL);
> +	if (ret < 0) {
> +		dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
> +		return ret;
> +	}

devm_mfd_add_devices()?

> +	ret = tps68470_chip_init(tps);
> +	if (ret < 0) {
> +		dev_err(tps->dev, "TPS68470 Init Error %d\n", ret);
> +		goto fail;
> +	}
> +
> +	return 0;
> +fail:
> +	mutex_lock(&tps->lock);

Why do you need to lock here?

> +	mfd_remove_devices(tps->dev);
> +	mutex_unlock(&tps->lock);
> +
> +	return ret;
> +}
> +
> +static int tps68470_remove(struct i2c_client *client)
> +{
> +	struct tps68470 *tps = i2c_get_clientdata(client);
> +
> +	mutex_lock(&tps->lock);
> +	mfd_remove_devices(tps->dev);
> +	mutex_unlock(&tps->lock);
> +
> +	return 0;
> +}
> +
> +static const struct acpi_device_id tps68470_acpi_ids[] = {
> +	{"INT3472"},
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids);
> +
> +static struct i2c_driver tps68470_driver = {
> +	.driver = {
> +		   .name = "tps68470",
> +		   .acpi_match_table = ACPI_PTR(tps68470_acpi_ids),
> +	},
> +	.probe_new = tps68470_probe,
> +	.remove = tps68470_remove,
> +};

<snip>

> +/**
> + * struct tps68470 - tps68470 sub-driver chip access routines
> + *
> + * Device data may be used to access the TPS68470 chip
> + */
> +
> +struct tps68470 {
> +	struct device *dev;
> +	struct regmap *regmap;
> +	/*
> +	 * Used to synchronize access to tps68470_ operations
> +	 * and addition and removal of mfd devices
> +	 */
> +	struct mutex lock;

Is this lock really necessary at all? Actually, you probable don't
even need this structure at all if you just rely on regmap functions
in the drivers.


Thanks,
Andy Shevchenko June 6, 2017, 12:59 p.m. UTC | #2
On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani <rajmohan.mani@intel.com> wrote:
> The TPS68470 device is an advanced power management
> unit that powers a Compact Camera Module (CCM),
> generates clocks for image sensors, drives a dual
> LED for Flash and incorporates two LED drivers for
> general purpose indicators.
>
> This patch adds support for TPS68470 mfd device.

I dunno why you decide to send this out now, see my comments below.

> +static int tps68470_chip_init(struct tps68470 *tps)
> +{
> +       unsigned int version;
> +       int ret;

> +       /* FIXME: configure these dynamically */

So, what prevents you to fix this?

> +       /* Enable Daisy Chain LDO and configure relevant GPIOs as output */

> +}

> +static int tps68470_probe(struct i2c_client *client)
> +{
> +       struct tps68470 *tps;
> +       int ret;
> +
> +       tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
> +       if (!tps)
> +               return -ENOMEM;
> +
> +       mutex_init(&tps->lock);
> +       i2c_set_clientdata(client, tps);
> +       tps->dev = &client->dev;
> +
> +       tps->regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
> +       if (IS_ERR(tps->regmap)) {
> +               dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
> +               return PTR_ERR(tps->regmap);
> +       }
> +

> +       ret = mfd_add_devices(tps->dev, -1, tps68470s,
> +                             ARRAY_SIZE(tps68470s), NULL, 0, NULL);

devm_?

> +       if (ret < 0) {
> +               dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = tps68470_chip_init(tps);
> +       if (ret < 0) {
> +               dev_err(tps->dev, "TPS68470 Init Error %d\n", ret);
> +               goto fail;
> +       }
> +
> +       return 0;

> +fail:
> +       mutex_lock(&tps->lock);

I'm not sure you need this mutex to be held here.
Otherwise your code has a bug with locking.

> +       mfd_remove_devices(tps->dev);
> +       mutex_unlock(&tps->lock);
> +
> +       return ret;

Taking above into consideration I suggest to clarify your locking scheme.

> +}
> +
> +static int tps68470_remove(struct i2c_client *client)
> +{
> +       struct tps68470 *tps = i2c_get_clientdata(client);
> +

> +       mutex_lock(&tps->lock);
> +       mfd_remove_devices(tps->dev);
> +       mutex_unlock(&tps->lock);

Ditto.

> +       return 0;
> +}

> +/**
> + * struct tps68470 - tps68470 sub-driver chip access routines
> + *

kbuild bot will be unhappy. You need to file a description per field.

> + * Device data may be used to access the TPS68470 chip
> + */
> +
> +struct tps68470 {
> +       struct device *dev;
> +       struct regmap *regmap;

> +       /*
> +        * Used to synchronize access to tps68470_ operations
> +        * and addition and removal of mfd devices
> +        */

Move it to kernel-doc above.

> +       struct mutex lock;
> +};
kernel test robot June 7, 2017, 2:10 a.m. UTC | #3
Hi Rajmohan,

[auto build test WARNING on ljones-mfd/for-mfd-next]
[also build test WARNING on v4.12-rc4 next-20170606]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Rajmohan-Mani/mfd-Add-new-mfd-device-TPS68470/20170607-080306
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/mfd/tps68470.c: In function 'tps68470_probe':
>> drivers/mfd/tps68470.c:175:3: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
      dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

vim +/ret +175 drivers/mfd/tps68470.c

   159	
   160	static int tps68470_probe(struct i2c_client *client)
   161	{
   162		struct tps68470 *tps;
   163		int ret;
   164	
   165		tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
   166		if (!tps)
   167			return -ENOMEM;
   168	
   169		mutex_init(&tps->lock);
   170		i2c_set_clientdata(client, tps);
   171		tps->dev = &client->dev;
   172	
   173		tps->regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
   174		if (IS_ERR(tps->regmap)) {
 > 175			dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
   176			return PTR_ERR(tps->regmap);
   177		}
   178	
   179		ret = mfd_add_devices(tps->dev, -1, tps68470s,
   180				      ARRAY_SIZE(tps68470s), NULL, 0, NULL);
   181		if (ret < 0) {
   182			dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
   183			return ret;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot June 7, 2017, 10:07 a.m. UTC | #4
Hi Rajmohan,

[auto build test ERROR on ljones-mfd/for-mfd-next]
[also build test ERROR on v4.12-rc4 next-20170607]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Rajmohan-Mani/mfd-Add-new-mfd-device-TPS68470/20170607-080306
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: alpha-allyesconfig (attached as .config)
compiler: alpha-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=alpha 

All error/warnings (new ones prefixed by >>):

>> drivers/mfd/tps68470.c:217:1: warning: data definition has no type or storage class
    MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids);
    ^~~~~~~~~~~~~~~~~~~
>> drivers/mfd/tps68470.c:217:1: error: type defaults to 'int' in declaration of 'MODULE_DEVICE_TABLE' [-Werror=implicit-int]
>> drivers/mfd/tps68470.c:217:1: warning: parameter names (without types) in function declaration
   drivers/mfd/tps68470.c: In function 'tps68470_probe':
   drivers/mfd/tps68470.c:175:3: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
      dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +217 drivers/mfd/tps68470.c

   211	
   212	static const struct acpi_device_id tps68470_acpi_ids[] = {
   213		{"INT3472"},
   214		{},
   215	};
   216	
 > 217	MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids);
   218	
   219	static struct i2c_driver tps68470_driver = {
   220		.driver = {

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Sakari Ailus June 7, 2017, 11:58 a.m. UTC | #5
Hi Andy,

On Tue, Jun 06, 2017 at 03:59:49PM +0300, Andy Shevchenko wrote:
> On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani <rajmohan.mani@intel.com> wrote:
> > The TPS68470 device is an advanced power management
> > unit that powers a Compact Camera Module (CCM),
> > generates clocks for image sensors, drives a dual
> > LED for Flash and incorporates two LED drivers for
> > general purpose indicators.
> >
> > This patch adds support for TPS68470 mfd device.
> 
> I dunno why you decide to send this out now, see my comments below.
> 
> > +static int tps68470_chip_init(struct tps68470 *tps)
> > +{
> > +       unsigned int version;
> > +       int ret;
> 
> > +       /* FIXME: configure these dynamically */
> 
> So, what prevents you to fix this?

Nothing I suppose. They're however not needed right now and can be
implemented later on if they're ever needed.
Mani, Rajmohan June 9, 2017, 10:04 p.m. UTC | #6
Hi Heikki,

Thanks for the reviews and patience.

> -----Original Message-----
> From: Heikki Krogerus [mailto:heikki.krogerus@linux.intel.com]
> Sent: Tuesday, June 06, 2017 5:49 AM
> To: Mani, Rajmohan <rajmohan.mani@intel.com>
> Cc: linux-kernel@vger.kernel.org; linux-gpio@vger.kernel.org; linux-
> acpi@vger.kernel.org; Lee Jones <lee.jones@linaro.org>; Linus Walleij
> <linus.walleij@linaro.org>; Alexandre Courbot <gnurou@gmail.com>; Rafael J.
> Wysocki <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>
> Subject: Re: [PATCH v1 1/3] mfd: Add new mfd device TPS68470
> 
> Hi Rajmohan,
> 
> On Tue, Jun 06, 2017 at 04:55:16AM -0700, Rajmohan Mani wrote:
> > +/*
> > + * tps68470_reg_read: Read a single tps68470 register.
> > + *
> > + * @tps: Device to read from.
> > + * @reg: Register to read.
> > + * @val: Contains the value
> > + */
> > +int tps68470_reg_read(struct tps68470 *tps, unsigned int reg,
> > +			unsigned int *val)
> > +{
> > +	int ret;
> > +
> > +	mutex_lock(&tps->lock);
> > +	ret = regmap_read(tps->regmap, reg, val);
> > +	mutex_unlock(&tps->lock);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(tps68470_reg_read);
> > +
> > +/*
> > + * tps68470_reg_write: Write a single tps68470 register.
> > + *
> > + * @tps68470: Device to write to.
> > + * @reg: Register to write to.
> > + * @val: Value to write.
> > + */
> > +int tps68470_reg_write(struct tps68470 *tps, unsigned int reg,
> > +			unsigned int val)
> > +{
> > +	int ret;
> > +
> > +	mutex_lock(&tps->lock);
> > +	ret = regmap_write(tps->regmap, reg, val);
> > +	mutex_unlock(&tps->lock);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(tps68470_reg_write);
> > +
> > +/*
> > + * tps68470_update_bits: Modify bits w.r.t mask and val.
> > + *
> > + * @tps68470: Device to write to.
> > + * @reg: Register to read-write to.
> > + * @mask: Mask.
> > + * @val: Value to write.
> > + */
> > +int tps68470_update_bits(struct tps68470 *tps, unsigned int reg,
> > +				unsigned int mask, unsigned int val) {
> > +	int ret;
> > +
> > +	mutex_lock(&tps->lock);
> > +	ret = regmap_update_bits(tps->regmap, reg, mask, val);
> > +	mutex_unlock(&tps->lock);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(tps68470_update_bits);
> 
> I'm not sure you need those above wrappers at all, regmap is handling locking in
> any case.
> 

I had this following question from Alan Cox on the original code without these wrappers.

"What is the model for insuring that no interrupt or thread of a driver is not in parallel issuing a tps68470_ operation when the device goes away (eg if I down the i2c controller) ?"

To address the above concerns, I got extra cautious and implemented locks around the regmap_* calls.
Now, I have been asked from more than one reviewer about the necessity of the same.
With the use of devm_* calls, tps68470_remove() goes away and leaves the driver just with regmap_* calls.
Unless I hear from Alan or other reviewers otherwise, I will drop these wrappers around regmap_* calls.

> > +static const struct regmap_config tps68470_regmap_config = {
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.max_register = TPS68470_REG_MAX,
> > +};
> > +
> > +static int tps68470_chip_init(struct tps68470 *tps) {
> > +	unsigned int version;
> > +	int ret;
> > +
> > +	ret = tps68470_reg_read(tps, TPS68470_REG_REVID, &version);
> > +	if (ret < 0) {
> > +		dev_err(tps->dev,
> > +			"Failed to read revision register: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	dev_info(tps->dev, "TPS68470 REVID: 0x%x\n", version);
> > +
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_RESET, 0xff);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* FIXME: configure these dynamically */
> > +	/* Enable Daisy Chain LDO and configure relevant GPIOs as output */
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_S_I2C_CTL, 2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL4A, 2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL5A, 2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL6A, 2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/*
> > +	 * When SDA and SCL are routed to GPIO1 and GPIO2, the mode
> > +	 * for these GPIOs must be configured using their respective
> > +	 * GPCTLxA registers as inputs with no pull-ups.
> > +	 */
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL1A, 0);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL2A, 0);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* Enable daisy chain */
> > +	ret = tps68470_update_bits(tps, TPS68470_REG_S_I2C_CTL, 1, 1);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	usleep_range(TPS68470_DAISY_CHAIN_DELAY_US,
> > +			TPS68470_DAISY_CHAIN_DELAY_US + 10);
> > +	return 0;
> > +}
> > +
> > +static int tps68470_probe(struct i2c_client *client) {
> > +	struct tps68470 *tps;
> > +	int ret;
> > +
> > +	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
> > +	if (!tps)
> > +		return -ENOMEM;
> > +
> > +	mutex_init(&tps->lock);
> > +	i2c_set_clientdata(client, tps);
> > +	tps->dev = &client->dev;
> > +
> > +	tps->regmap = devm_regmap_init_i2c(client,
> &tps68470_regmap_config);
> > +	if (IS_ERR(tps->regmap)) {
> > +		dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
> > +		return PTR_ERR(tps->regmap);
> > +	}
> > +
> > +	ret = mfd_add_devices(tps->dev, -1, tps68470s,
> > +			      ARRAY_SIZE(tps68470s), NULL, 0, NULL);
> > +	if (ret < 0) {
> > +		dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
> > +		return ret;
> > +	}
> 
> devm_mfd_add_devices()?
> 

Ack

> > +	ret = tps68470_chip_init(tps);
> > +	if (ret < 0) {
> > +		dev_err(tps->dev, "TPS68470 Init Error %d\n", ret);
> > +		goto fail;
> > +	}
> > +
> > +	return 0;
> > +fail:
> > +	mutex_lock(&tps->lock);
> 
> Why do you need to lock here?
> 

Same as explained above (to address Alan's comments)

> > +	mfd_remove_devices(tps->dev);
> > +	mutex_unlock(&tps->lock);
> > +
> > +	return ret;
> > +}
> > +
> > +static int tps68470_remove(struct i2c_client *client) {
> > +	struct tps68470 *tps = i2c_get_clientdata(client);
> > +
> > +	mutex_lock(&tps->lock);
> > +	mfd_remove_devices(tps->dev);
> > +	mutex_unlock(&tps->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct acpi_device_id tps68470_acpi_ids[] = {
> > +	{"INT3472"},
> > +	{},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids);
> > +
> > +static struct i2c_driver tps68470_driver = {
> > +	.driver = {
> > +		   .name = "tps68470",
> > +		   .acpi_match_table = ACPI_PTR(tps68470_acpi_ids),
> > +	},
> > +	.probe_new = tps68470_probe,
> > +	.remove = tps68470_remove,
> > +};
> 
> <snip>
> 
> > +/**
> > + * struct tps68470 - tps68470 sub-driver chip access routines
> > + *
> > + * Device data may be used to access the TPS68470 chip  */
> > +
> > +struct tps68470 {
> > +	struct device *dev;
> > +	struct regmap *regmap;
> > +	/*
> > +	 * Used to synchronize access to tps68470_ operations
> > +	 * and addition and removal of mfd devices
> > +	 */
> > +	struct mutex lock;
> 
> Is this lock really necessary at all? Actually, you probable don't even need this
> structure at all if you just rely on regmap functions in the drivers.
> 

Ack
I am looking into this and will get back with v2.

> 
> Thanks,
> 
> --
> heikki
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mani, Rajmohan June 9, 2017, 10:09 p.m. UTC | #7
SGkgQW5keSwNCg0KVGhhbmtzIGZvciB0aGUgcmV2aWV3cyBhbmQgcGF0aWVuY2UuDQoNCj4gLS0t
LS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQW5keSBTaGV2Y2hlbmtvIFttYWlsdG86
YW5keS5zaGV2Y2hlbmtvQGdtYWlsLmNvbV0NCj4gU2VudDogVHVlc2RheSwgSnVuZSAwNiwgMjAx
NyA2OjAwIEFNDQo+IFRvOiBNYW5pLCBSYWptb2hhbiA8cmFqbW9oYW4ubWFuaUBpbnRlbC5jb20+
DQo+IENjOiBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnOyBsaW51eC1ncGlvQHZnZXIua2Vy
bmVsLm9yZzsgbGludXgtDQo+IGFjcGlAdmdlci5rZXJuZWwub3JnOyBMZWUgSm9uZXMgPGxlZS5q
b25lc0BsaW5hcm8ub3JnPjsgTGludXMgV2FsbGVpag0KPiA8bGludXMud2FsbGVpakBsaW5hcm8u
b3JnPjsgQWxleGFuZHJlIENvdXJib3QgPGdudXJvdUBnbWFpbC5jb20+OyBSYWZhZWwgSi4NCj4g
V3lzb2NraSA8cmp3QHJqd3lzb2NraS5uZXQ+OyBMZW4gQnJvd24gPGxlbmJAa2VybmVsLm9yZz4N
Cj4gU3ViamVjdDogUmU6IFtQQVRDSCB2MSAxLzNdIG1mZDogQWRkIG5ldyBtZmQgZGV2aWNlIFRQ
UzY4NDcwDQo+IA0KPiBPbiBUdWUsIEp1biA2LCAyMDE3IGF0IDI6NTUgUE0sIFJham1vaGFuIE1h
bmkgPHJham1vaGFuLm1hbmlAaW50ZWwuY29tPg0KPiB3cm90ZToNCj4gPiBUaGUgVFBTNjg0NzAg
ZGV2aWNlIGlzIGFuIGFkdmFuY2VkIHBvd2VyIG1hbmFnZW1lbnQgdW5pdCB0aGF0IHBvd2VycyBh
DQo+ID4gQ29tcGFjdCBDYW1lcmEgTW9kdWxlIChDQ00pLCBnZW5lcmF0ZXMgY2xvY2tzIGZvciBp
bWFnZSBzZW5zb3JzLA0KPiA+IGRyaXZlcyBhIGR1YWwgTEVEIGZvciBGbGFzaCBhbmQgaW5jb3Jw
b3JhdGVzIHR3byBMRUQgZHJpdmVycyBmb3INCj4gPiBnZW5lcmFsIHB1cnBvc2UgaW5kaWNhdG9y
cy4NCj4gPg0KPiA+IFRoaXMgcGF0Y2ggYWRkcyBzdXBwb3J0IGZvciBUUFM2ODQ3MCBtZmQgZGV2
aWNlLg0KPiANCj4gSSBkdW5ubyB3aHkgeW91IGRlY2lkZSB0byBzZW5kIHRoaXMgb3V0IG5vdywg
c2VlIG15IGNvbW1lbnRzIGJlbG93Lg0KPiANCg0KV2UgZGVjaWRlZCB0byBnbyB3aXRoIHRoZSBz
dWJtaXNzaW9uIG9mIHRoZXNlIGRyaXZlcnMgZm9yIHVwc3RyZWFtIHJldmlldyBzb29uZXIgcmF0
aGVyIHRoYW4gbGF0ZXIuDQoNCj4gPiArc3RhdGljIGludCB0cHM2ODQ3MF9jaGlwX2luaXQoc3Ry
dWN0IHRwczY4NDcwICp0cHMpIHsNCj4gPiArICAgICAgIHVuc2lnbmVkIGludCB2ZXJzaW9uOw0K
PiA+ICsgICAgICAgaW50IHJldDsNCj4gDQo+ID4gKyAgICAgICAvKiBGSVhNRTogY29uZmlndXJl
IHRoZXNlIGR5bmFtaWNhbGx5ICovDQo+IA0KPiBTbywgd2hhdCBwcmV2ZW50cyB5b3UgdG8gZml4
IHRoaXM/DQo+IA0KDQpJIHdpbGwgcmVzcG9uZCBvbiB0b3Agb2YgU2FrYXJpJ3MgcmVzcG9uc2Uu
DQoNCj4gPiArICAgICAgIC8qIEVuYWJsZSBEYWlzeSBDaGFpbiBMRE8gYW5kIGNvbmZpZ3VyZSBy
ZWxldmFudCBHUElPcyBhcw0KPiA+ICsgb3V0cHV0ICovDQo+IA0KPiA+ICt9DQo+IA0KPiA+ICtz
dGF0aWMgaW50IHRwczY4NDcwX3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpIHsNCj4g
PiArICAgICAgIHN0cnVjdCB0cHM2ODQ3MCAqdHBzOw0KPiA+ICsgICAgICAgaW50IHJldDsNCj4g
PiArDQo+ID4gKyAgICAgICB0cHMgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2LCBzaXplb2Yo
KnRwcyksIEdGUF9LRVJORUwpOw0KPiA+ICsgICAgICAgaWYgKCF0cHMpDQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+ICsNCj4gPiArICAgICAgIG11dGV4X2luaXQoJnRw
cy0+bG9jayk7DQo+ID4gKyAgICAgICBpMmNfc2V0X2NsaWVudGRhdGEoY2xpZW50LCB0cHMpOw0K
PiA+ICsgICAgICAgdHBzLT5kZXYgPSAmY2xpZW50LT5kZXY7DQo+ID4gKw0KPiA+ICsgICAgICAg
dHBzLT5yZWdtYXAgPSBkZXZtX3JlZ21hcF9pbml0X2kyYyhjbGllbnQsDQo+ICZ0cHM2ODQ3MF9y
ZWdtYXBfY29uZmlnKTsNCj4gPiArICAgICAgIGlmIChJU19FUlIodHBzLT5yZWdtYXApKSB7DQo+
ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIodHBzLT5kZXYsICJkZXZtX3JlZ21hcF9pbml0X2ky
YyBFcnJvciAlZFxuIiwgcmV0KTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIFBUUl9FUlIo
dHBzLT5yZWdtYXApOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gDQo+ID4gKyAgICAgICByZXQg
PSBtZmRfYWRkX2RldmljZXModHBzLT5kZXYsIC0xLCB0cHM2ODQ3MHMsDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgQVJSQVlfU0laRSh0cHM2ODQ3MHMpLCBOVUxMLCAwLCBOVUxM
KTsNCj4gDQo+IGRldm1fPw0KPiANCg0KQWNrDQoNCj4gPiArICAgICAgIGlmIChyZXQgPCAwKSB7
DQo+ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIodHBzLT5kZXYsICJtZmRfYWRkX2RldmljZXMg
ZmFpbGVkOiAlZFxuIiwgcmV0KTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHJldDsNCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXQgPSB0cHM2ODQ3MF9jaGlwX2luaXQo
dHBzKTsNCj4gPiArICAgICAgIGlmIChyZXQgPCAwKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGRl
dl9lcnIodHBzLT5kZXYsICJUUFM2ODQ3MCBJbml0IEVycm9yICVkXG4iLCByZXQpOw0KPiA+ICsg
ICAgICAgICAgICAgICBnb3RvIGZhaWw7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgcmV0dXJuIDA7DQo+IA0KPiA+ICtmYWlsOg0KPiA+ICsgICAgICAgbXV0ZXhfbG9jaygmdHBz
LT5sb2NrKTsNCj4gDQo+IEknbSBub3Qgc3VyZSB5b3UgbmVlZCB0aGlzIG11dGV4IHRvIGJlIGhl
bGQgaGVyZS4NCj4gT3RoZXJ3aXNlIHlvdXIgY29kZSBoYXMgYSBidWcgd2l0aCBsb2NraW5nLg0K
PiANCg0KUmVwZWF0aW5nIHRoZSByZXNwb25zZSB0byBIZWlra2kgaGVyZQ0KDQpJIGhhZCB0aGlz
IGZvbGxvd2luZyBxdWVzdGlvbiBmcm9tIEFsYW4gQ294IG9uIHRoZSBvcmlnaW5hbCBjb2RlIHdp
dGhvdXQgdGhlc2Ugd3JhcHBlcnMuDQoNCiJXaGF0IGlzIHRoZSBtb2RlbCBmb3IgaW5zdXJpbmcg
dGhhdCBubyBpbnRlcnJ1cHQgb3IgdGhyZWFkIG9mIGEgZHJpdmVyIGlzIG5vdCBpbiBwYXJhbGxl
bCBpc3N1aW5nIGEgdHBzNjg0NzBfIG9wZXJhdGlvbiB3aGVuIHRoZSBkZXZpY2UgZ29lcyBhd2F5
IChlZyBpZiBJIGRvd24gdGhlIGkyYyBjb250cm9sbGVyKSA/Ig0KDQpUbyBhZGRyZXNzIHRoZSBh
Ym92ZSBjb25jZXJucywgSSBnb3QgZXh0cmEgY2F1dGlvdXMgYW5kIGltcGxlbWVudGVkIGxvY2tz
IGFyb3VuZCB0aGUgcmVnbWFwXyogY2FsbHMuDQpOb3csIEkgaGF2ZSBiZWVuIGFza2VkIGZyb20g
bW9yZSB0aGFuIG9uZSByZXZpZXdlciBhYm91dCB0aGUgbmVjZXNzaXR5IG9mIHRoZSBzYW1lLg0K
V2l0aCB0aGUgdXNlIG9mIGRldm1fKiBjYWxscywgdHBzNjg0NzBfcmVtb3ZlKCkgZ29lcyBhd2F5
IGFuZCBsZWF2ZXMgdGhlIGRyaXZlciBqdXN0IHdpdGggcmVnbWFwXyogY2FsbHMuDQpVbmxlc3Mg
SSBoZWFyIGZyb20gQWxhbiBvciBvdGhlciByZXZpZXdlcnMgb3RoZXJ3aXNlLCBJIHdpbGwgZHJv
cCB0aGVzZSB3cmFwcGVycyBhcm91bmQgcmVnbWFwXyogY2FsbHMuDQoNCj4gPiArICAgICAgIG1m
ZF9yZW1vdmVfZGV2aWNlcyh0cHMtPmRldik7DQo+ID4gKyAgICAgICBtdXRleF91bmxvY2soJnRw
cy0+bG9jayk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHJldDsNCj4gDQo+IFRha2luZyBh
Ym92ZSBpbnRvIGNvbnNpZGVyYXRpb24gSSBzdWdnZXN0IHRvIGNsYXJpZnkgeW91ciBsb2NraW5n
IHNjaGVtZS4NCj4gDQoNClNhbWUgYXMgYWJvdmUuDQoNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3Rh
dGljIGludCB0cHM2ODQ3MF9yZW1vdmUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCkgew0KPiA+
ICsgICAgICAgc3RydWN0IHRwczY4NDcwICp0cHMgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50
KTsNCj4gPiArDQo+IA0KPiA+ICsgICAgICAgbXV0ZXhfbG9jaygmdHBzLT5sb2NrKTsNCj4gPiAr
ICAgICAgIG1mZF9yZW1vdmVfZGV2aWNlcyh0cHMtPmRldik7DQo+ID4gKyAgICAgICBtdXRleF91
bmxvY2soJnRwcy0+bG9jayk7DQo+IA0KPiBEaXR0by4NCj4gDQoNClNhbWUgYXMgYWJvdmUNCg0K
PiA+ICsgICAgICAgcmV0dXJuIDA7DQo+ID4gK30NCj4gDQo+ID4gKy8qKg0KPiA+ICsgKiBzdHJ1
Y3QgdHBzNjg0NzAgLSB0cHM2ODQ3MCBzdWItZHJpdmVyIGNoaXAgYWNjZXNzIHJvdXRpbmVzDQo+
ID4gKyAqDQo+IA0KPiBrYnVpbGQgYm90IHdpbGwgYmUgdW5oYXBweS4gWW91IG5lZWQgdG8gZmls
ZSBhIGRlc2NyaXB0aW9uIHBlciBmaWVsZC4NCj4gDQoNCkFjaw0KSXQgbG9va3MgbGlrZSB0aGlz
IHN0cnVjdHVyZSB3aWxsIGdvIGF3YXksIG9uY2UgSSBpbXBsZW1lbnQgdGhlIGZlZWRiYWNrIGZy
b20gSGVpa2tpLg0KDQo+ID4gKyAqIERldmljZSBkYXRhIG1heSBiZSB1c2VkIHRvIGFjY2VzcyB0
aGUgVFBTNjg0NzAgY2hpcCAqLw0KPiA+ICsNCj4gPiArc3RydWN0IHRwczY4NDcwIHsNCj4gPiAr
ICAgICAgIHN0cnVjdCBkZXZpY2UgKmRldjsNCj4gPiArICAgICAgIHN0cnVjdCByZWdtYXAgKnJl
Z21hcDsNCj4gDQo+ID4gKyAgICAgICAvKg0KPiA+ICsgICAgICAgICogVXNlZCB0byBzeW5jaHJv
bml6ZSBhY2Nlc3MgdG8gdHBzNjg0NzBfIG9wZXJhdGlvbnMNCj4gPiArICAgICAgICAqIGFuZCBh
ZGRpdGlvbiBhbmQgcmVtb3ZhbCBvZiBtZmQgZGV2aWNlcw0KPiA+ICsgICAgICAgICovDQo+IA0K
PiBNb3ZlIGl0IHRvIGtlcm5lbC1kb2MgYWJvdmUuDQo+IA0KDQpTYW1lIGFzIGFib3ZlDQoNCj4g
PiArICAgICAgIHN0cnVjdCBtdXRleCBsb2NrOw0KPiA+ICt9Ow0KPiANCj4gLS0NCj4gV2l0aCBC
ZXN0IFJlZ2FyZHMsDQo+IEFuZHkgU2hldmNoZW5rbw0K
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mani, Rajmohan June 9, 2017, 10:12 p.m. UTC | #8
Hi Andy,

> On Tue, Jun 06, 2017 at 03:59:49PM +0300, Andy Shevchenko wrote:
> > On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani
> <rajmohan.mani@intel.com> wrote:
> > > The TPS68470 device is an advanced power management unit that powers
> > > a Compact Camera Module (CCM), generates clocks for image sensors,
> > > drives a dual LED for Flash and incorporates two LED drivers for
> > > general purpose indicators.
> > >
> > > This patch adds support for TPS68470 mfd device.
> >
> > I dunno why you decide to send this out now, see my comments below.
> >
> > > +static int tps68470_chip_init(struct tps68470 *tps) {
> > > +       unsigned int version;
> > > +       int ret;
> >
> > > +       /* FIXME: configure these dynamically */
> >
> > So, what prevents you to fix this?
> 
> Nothing I suppose. They're however not needed right now and can be
> implemented later on if they're ever needed.
> 

Ack

--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lee Jones June 12, 2017, 8:20 a.m. UTC | #9
On Fri, 09 Jun 2017, Mani, Rajmohan wrote:

> Hi Andy,
> 
> > On Tue, Jun 06, 2017 at 03:59:49PM +0300, Andy Shevchenko wrote:
> > > On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani
> > <rajmohan.mani@intel.com> wrote:
> > > > The TPS68470 device is an advanced power management unit that powers
> > > > a Compact Camera Module (CCM), generates clocks for image sensors,
> > > > drives a dual LED for Flash and incorporates two LED drivers for
> > > > general purpose indicators.
> > > >
> > > > This patch adds support for TPS68470 mfd device.
> > >
> > > I dunno why you decide to send this out now, see my comments below.
> > >
> > > > +static int tps68470_chip_init(struct tps68470 *tps) {
> > > > +       unsigned int version;
> > > > +       int ret;
> > >
> > > > +       /* FIXME: configure these dynamically */
> > >
> > > So, what prevents you to fix this?
> > 
> > Nothing I suppose. They're however not needed right now and can be
> > implemented later on if they're ever needed.
> > 
> 
> Ack

What does this mean?  Is the plan to fix it or not?  I don't want
FIXMEs in the code that a) can be fixed right away or b) might never
be fixed.
Mani, Rajmohan June 12, 2017, 9:20 a.m. UTC | #10
Hi Lee,

> Subject: Re: [PATCH v1 1/3] mfd: Add new mfd device TPS68470

> 

> On Fri, 09 Jun 2017, Mani, Rajmohan wrote:

> 

> > Hi Andy,

> >

> > > On Tue, Jun 06, 2017 at 03:59:49PM +0300, Andy Shevchenko wrote:

> > > > On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani

> > > <rajmohan.mani@intel.com> wrote:

> > > > > The TPS68470 device is an advanced power management unit that

> > > > > powers a Compact Camera Module (CCM), generates clocks for image

> > > > > sensors, drives a dual LED for Flash and incorporates two LED

> > > > > drivers for general purpose indicators.

> > > > >

> > > > > This patch adds support for TPS68470 mfd device.

> > > >

> > > > I dunno why you decide to send this out now, see my comments below.

> > > >

> > > > > +static int tps68470_chip_init(struct tps68470 *tps) {

> > > > > +       unsigned int version;

> > > > > +       int ret;

> > > >

> > > > > +       /* FIXME: configure these dynamically */

> > > >

> > > > So, what prevents you to fix this?

> > >

> > > Nothing I suppose. They're however not needed right now and can be

> > > implemented later on if they're ever needed.

> > >

> >

> > Ack

> 

> What does this mean?  Is the plan to fix it or not?  I don't want FIXMEs in the

> code that a) can be fixed right away or b) might never be fixed.

> 


I meant that this can be implemented later on, if there's a need.
I will look into this and see how this can be fixed.

Thanks
Raj
Mani, Rajmohan July 19, 2017, 11:23 p.m. UTC | #11
SGkgTGVlLA0KDQo+ID4gT24gRnJpLCAwOSBKdW4gMjAxNywgTWFuaSwgUmFqbW9oYW4gd3JvdGU6
DQo+ID4NCj4gPiA+IEhpIEFuZHksDQo+ID4gPg0KPiA+ID4gPiBPbiBUdWUsIEp1biAwNiwgMjAx
NyBhdCAwMzo1OTo0OVBNICswMzAwLCBBbmR5IFNoZXZjaGVua28gd3JvdGU6DQo+ID4gPiA+ID4g
T24gVHVlLCBKdW4gNiwgMjAxNyBhdCAyOjU1IFBNLCBSYWptb2hhbiBNYW5pDQo+ID4gPiA+IDxy
YWptb2hhbi5tYW5pQGludGVsLmNvbT4gd3JvdGU6DQo+ID4gPiA+ID4gPiBUaGUgVFBTNjg0NzAg
ZGV2aWNlIGlzIGFuIGFkdmFuY2VkIHBvd2VyIG1hbmFnZW1lbnQgdW5pdCB0aGF0DQo+ID4gPiA+
ID4gPiBwb3dlcnMgYSBDb21wYWN0IENhbWVyYSBNb2R1bGUgKENDTSksIGdlbmVyYXRlcyBjbG9j
a3MgZm9yDQo+ID4gPiA+ID4gPiBpbWFnZSBzZW5zb3JzLCBkcml2ZXMgYSBkdWFsIExFRCBmb3Ig
Rmxhc2ggYW5kIGluY29ycG9yYXRlcw0KPiA+ID4gPiA+ID4gdHdvIExFRCBkcml2ZXJzIGZvciBn
ZW5lcmFsIHB1cnBvc2UgaW5kaWNhdG9ycy4NCj4gPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiBUaGlz
IHBhdGNoIGFkZHMgc3VwcG9ydCBmb3IgVFBTNjg0NzAgbWZkIGRldmljZS4NCj4gPiA+ID4gPg0K
PiA+ID4gPiA+IEkgZHVubm8gd2h5IHlvdSBkZWNpZGUgdG8gc2VuZCB0aGlzIG91dCBub3csIHNl
ZSBteSBjb21tZW50cw0KPiBiZWxvdy4NCj4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gK3N0YXRpYyBp
bnQgdHBzNjg0NzBfY2hpcF9pbml0KHN0cnVjdCB0cHM2ODQ3MCAqdHBzKSB7DQo+ID4gPiA+ID4g
PiArICAgICAgIHVuc2lnbmVkIGludCB2ZXJzaW9uOw0KPiA+ID4gPiA+ID4gKyAgICAgICBpbnQg
cmV0Ow0KPiA+ID4gPiA+DQo+ID4gPiA+ID4gPiArICAgICAgIC8qIEZJWE1FOiBjb25maWd1cmUg
dGhlc2UgZHluYW1pY2FsbHkgKi8NCj4gPiA+ID4gPg0KPiA+ID4gPiA+IFNvLCB3aGF0IHByZXZl
bnRzIHlvdSB0byBmaXggdGhpcz8NCj4gPiA+ID4NCj4gPiA+ID4gTm90aGluZyBJIHN1cHBvc2Uu
IFRoZXkncmUgaG93ZXZlciBub3QgbmVlZGVkIHJpZ2h0IG5vdyBhbmQgY2FuIGJlDQo+ID4gPiA+
IGltcGxlbWVudGVkIGxhdGVyIG9uIGlmIHRoZXkncmUgZXZlciBuZWVkZWQuDQo+ID4gPiA+DQo+
ID4gPg0KPiA+ID4gQWNrDQo+ID4NCj4gPiBXaGF0IGRvZXMgdGhpcyBtZWFuPyAgSXMgdGhlIHBs
YW4gdG8gZml4IGl0IG9yIG5vdD8gIEkgZG9uJ3Qgd2FudA0KPiA+IEZJWE1FcyBpbiB0aGUgY29k
ZSB0aGF0IGEpIGNhbiBiZSBmaXhlZCByaWdodCBhd2F5IG9yIGIpIG1pZ2h0IG5ldmVyIGJlDQo+
IGZpeGVkLg0KPiA+DQo+IA0KPiBJIG1lYW50IHRoYXQgdGhpcyBjYW4gYmUgaW1wbGVtZW50ZWQg
bGF0ZXIgb24sIGlmIHRoZXJlJ3MgYSBuZWVkLg0KPiBJIHdpbGwgbG9vayBpbnRvIHRoaXMgYW5k
IHNlZSBob3cgdGhpcyBjYW4gYmUgZml4ZWQuDQo+IA0KDQpUaGFua3MgZm9yIHlvdXIgcGF0aWVu
Y2UuDQpUaGlzIGlzIGZpeGVkIHdpdGggdjQgb2YgdGhpcyBzZXJpZXMuDQoNClJhag0K
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lee Jones July 20, 2017, 8:15 a.m. UTC | #12
On Wed, 19 Jul 2017, Mani, Rajmohan wrote:

> Hi Lee,
> 
> > > On Fri, 09 Jun 2017, Mani, Rajmohan wrote:
> > >
> > > > Hi Andy,
> > > >
> > > > > On Tue, Jun 06, 2017 at 03:59:49PM +0300, Andy Shevchenko wrote:
> > > > > > On Tue, Jun 6, 2017 at 2:55 PM, Rajmohan Mani
> > > > > <rajmohan.mani@intel.com> wrote:
> > > > > > > The TPS68470 device is an advanced power management unit that
> > > > > > > powers a Compact Camera Module (CCM), generates clocks for
> > > > > > > image sensors, drives a dual LED for Flash and incorporates
> > > > > > > two LED drivers for general purpose indicators.
> > > > > > >
> > > > > > > This patch adds support for TPS68470 mfd device.
> > > > > >
> > > > > > I dunno why you decide to send this out now, see my comments
> > below.
> > > > > >
> > > > > > > +static int tps68470_chip_init(struct tps68470 *tps) {
> > > > > > > +       unsigned int version;
> > > > > > > +       int ret;
> > > > > >
> > > > > > > +       /* FIXME: configure these dynamically */
> > > > > >
> > > > > > So, what prevents you to fix this?
> > > > >
> > > > > Nothing I suppose. They're however not needed right now and can be
> > > > > implemented later on if they're ever needed.
> > > > >
> > > >
> > > > Ack
> > >
> > > What does this mean?  Is the plan to fix it or not?  I don't want
> > > FIXMEs in the code that a) can be fixed right away or b) might never be
> > fixed.
> > >
> > 
> > I meant that this can be implemented later on, if there's a need.
> > I will look into this and see how this can be fixed.
> > 
> 
> Thanks for your patience.
> This is fixed with v4 of this series.

Great, thanks.
diff mbox

Patch

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3eb5c93..c5e51bc 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1311,6 +1311,18 @@  config MFD_TPS65217
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps65217.
 
+config MFD_TPS68470
+	bool "TI TPS68470 Power Management / LED chips"
+	depends on I2C
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the TPS68470 series of
+	  Power Management / LED chips.
+
+	  These include voltage regulators, led and other features
+	  that are often used in portable devices.
+
 config MFD_TI_LP873X
 	tristate "TI LP873X Power Management IC"
 	depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c16bf1e..6dd2b94 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -82,6 +82,7 @@  obj-$(CONFIG_MFD_TPS65910)	+= tps65910.o
 obj-$(CONFIG_MFD_TPS65912)	+= tps65912-core.o
 obj-$(CONFIG_MFD_TPS65912_I2C)	+= tps65912-i2c.o
 obj-$(CONFIG_MFD_TPS65912_SPI)  += tps65912-spi.o
+obj-$(CONFIG_MFD_TPS68470)	+= tps68470.o
 obj-$(CONFIG_MFD_TPS80031)	+= tps80031.o
 obj-$(CONFIG_MENELAUS)		+= menelaus.o
 
diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c
new file mode 100644
index 0000000..ca174fb
--- /dev/null
+++ b/drivers/mfd/tps68470.c
@@ -0,0 +1,227 @@ 
+/*
+ * TPS68470 chip family multi-function driver
+ *
+ * Copyright (C) 2017 Intel Corporation
+ * Authors:
+ * Rajmohan Mani <rajmohan.mani@intel.com>
+ * Tianshu Qiu <tian.shu.qiu@intel.com>
+ * Jian Xu Zheng <jian.xu.zheng@intel.com>
+ * Yuning Pu <yuning.pu@intel.com>
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+
+static const struct mfd_cell tps68470s[] = {
+	{
+		.name = "tps68470-gpio",
+	},
+	{
+		.name = "tps68470_pmic_opregion",
+	},
+};
+
+/*
+ * tps68470_reg_read: Read a single tps68470 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contains the value
+ */
+int tps68470_reg_read(struct tps68470 *tps, unsigned int reg,
+			unsigned int *val)
+{
+	int ret;
+
+	mutex_lock(&tps->lock);
+	ret = regmap_read(tps->regmap, reg, val);
+	mutex_unlock(&tps->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps68470_reg_read);
+
+/*
+ * tps68470_reg_write: Write a single tps68470 register.
+ *
+ * @tps68470: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int tps68470_reg_write(struct tps68470 *tps, unsigned int reg,
+			unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&tps->lock);
+	ret = regmap_write(tps->regmap, reg, val);
+	mutex_unlock(&tps->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps68470_reg_write);
+
+/*
+ * tps68470_update_bits: Modify bits w.r.t mask and val.
+ *
+ * @tps68470: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ */
+int tps68470_update_bits(struct tps68470 *tps, unsigned int reg,
+				unsigned int mask, unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&tps->lock);
+	ret = regmap_update_bits(tps->regmap, reg, mask, val);
+	mutex_unlock(&tps->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps68470_update_bits);
+
+static const struct regmap_config tps68470_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = TPS68470_REG_MAX,
+};
+
+static int tps68470_chip_init(struct tps68470 *tps)
+{
+	unsigned int version;
+	int ret;
+
+	ret = tps68470_reg_read(tps, TPS68470_REG_REVID, &version);
+	if (ret < 0) {
+		dev_err(tps->dev,
+			"Failed to read revision register: %d\n", ret);
+		return ret;
+	}
+
+	dev_info(tps->dev, "TPS68470 REVID: 0x%x\n", version);
+
+	ret = tps68470_reg_write(tps, TPS68470_REG_RESET, 0xff);
+	if (ret < 0)
+		return ret;
+
+	/* FIXME: configure these dynamically */
+	/* Enable Daisy Chain LDO and configure relevant GPIOs as output */
+	ret = tps68470_reg_write(tps, TPS68470_REG_S_I2C_CTL, 2);
+	if (ret < 0)
+		return ret;
+
+	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL4A, 2);
+	if (ret < 0)
+		return ret;
+
+	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL5A, 2);
+	if (ret < 0)
+		return ret;
+
+	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL6A, 2);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * When SDA and SCL are routed to GPIO1 and GPIO2, the mode
+	 * for these GPIOs must be configured using their respective
+	 * GPCTLxA registers as inputs with no pull-ups.
+	 */
+	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL1A, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = tps68470_reg_write(tps, TPS68470_REG_GPCTL2A, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Enable daisy chain */
+	ret = tps68470_update_bits(tps, TPS68470_REG_S_I2C_CTL, 1, 1);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(TPS68470_DAISY_CHAIN_DELAY_US,
+			TPS68470_DAISY_CHAIN_DELAY_US + 10);
+	return 0;
+}
+
+static int tps68470_probe(struct i2c_client *client)
+{
+	struct tps68470 *tps;
+	int ret;
+
+	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+	if (!tps)
+		return -ENOMEM;
+
+	mutex_init(&tps->lock);
+	i2c_set_clientdata(client, tps);
+	tps->dev = &client->dev;
+
+	tps->regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
+	if (IS_ERR(tps->regmap)) {
+		dev_err(tps->dev, "devm_regmap_init_i2c Error %d\n", ret);
+		return PTR_ERR(tps->regmap);
+	}
+
+	ret = mfd_add_devices(tps->dev, -1, tps68470s,
+			      ARRAY_SIZE(tps68470s), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = tps68470_chip_init(tps);
+	if (ret < 0) {
+		dev_err(tps->dev, "TPS68470 Init Error %d\n", ret);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	mutex_lock(&tps->lock);
+	mfd_remove_devices(tps->dev);
+	mutex_unlock(&tps->lock);
+
+	return ret;
+}
+
+static int tps68470_remove(struct i2c_client *client)
+{
+	struct tps68470 *tps = i2c_get_clientdata(client);
+
+	mutex_lock(&tps->lock);
+	mfd_remove_devices(tps->dev);
+	mutex_unlock(&tps->lock);
+
+	return 0;
+}
+
+static const struct acpi_device_id tps68470_acpi_ids[] = {
+	{"INT3472"},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, tps68470_acpi_ids);
+
+static struct i2c_driver tps68470_driver = {
+	.driver = {
+		   .name = "tps68470",
+		   .acpi_match_table = ACPI_PTR(tps68470_acpi_ids),
+	},
+	.probe_new = tps68470_probe,
+	.remove = tps68470_remove,
+};
+builtin_i2c_driver(tps68470_driver);
diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h
new file mode 100644
index 0000000..440c802
--- /dev/null
+++ b/include/linux/mfd/tps68470.h
@@ -0,0 +1,167 @@ 
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Functions to access TPS68470 power management chip.
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_MFD_TPS68470_H
+#define __LINUX_MFD_TPS68470_H
+
+#include <linux/i2c.h>
+
+/* All register addresses */
+#define TPS68470_REG_GSTAT		0x01
+#define TPS68470_REG_VRSTA		0x02
+#define TPS68470_REG_VRSHORT		0x03
+#define TPS68470_REG_INTMASK		0x04
+#define TPS68470_REG_VCOSPEED		0x05
+#define TPS68470_REG_POSTDIV2		0x06
+#define TPS68470_REG_BOOSTDIV		0x07
+#define TPS68470_REG_BUCKDIV		0x08
+#define TPS68470_REG_PLLSWR		0x09
+#define TPS68470_REG_XTALDIV		0x0A
+#define TPS68470_REG_PLLDIV		0x0B
+#define TPS68470_REG_POSTDIV		0x0C
+#define TPS68470_REG_PLLCTL		0x0D
+#define TPS68470_REG_PLLCTL2		0x0E
+#define TPS68470_REG_CLKCFG1		0x0F
+#define TPS68470_REG_CLKCFG2		0x10
+#define TPS68470_REG_GPCTL0A		0x14
+#define TPS68470_REG_GPCTL0B		0x15
+#define TPS68470_REG_GPCTL1A		0x16
+#define TPS68470_REG_GPCTL1B		0x17
+#define TPS68470_REG_GPCTL2A		0x18
+#define TPS68470_REG_GPCTL2B		0x19
+#define TPS68470_REG_GPCTL3A		0x1A
+#define TPS68470_REG_GPCTL3B		0x1B
+#define TPS68470_REG_GPCTL4A		0x1C
+#define TPS68470_REG_GPCTL4B		0x1D
+#define TPS68470_REG_GPCTL5A		0x1E
+#define TPS68470_REG_GPCTL5B		0x1F
+#define TPS68470_REG_GPCTL6A		0x20
+#define TPS68470_REG_GPCTL6B		0x21
+#define TPS68470_REG_SGPO		0x22
+#define TPS68470_REG_PITCTL		0x23
+#define TPS68470_REG_WAKECFG		0x24
+#define TPS68470_REG_IOWAKESTAT		0x25
+#define TPS68470_REG_GPDI		0x26
+#define TPS68470_REG_GPDO		0x27
+#define TPS68470_REG_ILEDCTL		0x28
+#define TPS68470_REG_WLEDSTAT		0x29
+#define TPS68470_REG_VWLEDILIM		0x2A
+#define TPS68470_REG_VWLEDVAL		0x2B
+#define TPS68470_REG_WLEDMAXRER		0x2C
+#define TPS68470_REG_WLEDMAXT		0x2D
+#define TPS68470_REG_WLEDMAXAF		0x2E
+#define TPS68470_REG_WLEDMAXF		0x2F
+#define TPS68470_REG_WLEDTO		0x30
+#define TPS68470_REG_VWLEDCTL		0x31
+#define TPS68470_REG_WLEDTIMER_MSB	0x32
+#define TPS68470_REG_WLEDTIMER_LSB	0x33
+#define TPS68470_REG_WLEDC1		0x34
+#define TPS68470_REG_WLEDC2		0x35
+#define TPS68470_REG_WLEDCTL		0x36
+#define TPS68470_REG_VCMVAL		0x3C
+#define TPS68470_REG_VAUX1VAL		0x3D
+#define TPS68470_REG_VAUX2VAL		0x3E
+#define TPS68470_REG_VIOVAL		0x3F
+#define TPS68470_REG_VSIOVAL		0x40
+#define TPS68470_REG_VAVAL		0x41
+#define TPS68470_REG_VDVAL		0x42
+#define TPS68470_REG_S_I2C_CTL		0x43
+#define TPS68470_REG_VCMCTL		0x44
+#define TPS68470_REG_VAUX1CTL		0x45
+#define TPS68470_REG_VAUX2CTL		0x46
+#define TPS68470_REG_VACTL		0x47
+#define TPS68470_REG_VDCTL		0x48
+#define TPS68470_REG_RESET		0x50
+#define TPS68470_REG_REVID		0xFF
+
+#define TPS68470_REG_MAX		TPS68470_REG_REVID
+
+/* Register field definitions */
+
+#define TPS68470_VAVAL_AVOLT_MASK	GENMASK(6, 0)
+
+#define TPS68470_VDVAL_DVOLT_MASK	GENMASK(5, 0)
+#define TPS68470_VCMVAL_VCVOLT_MASK	GENMASK(6, 0)
+#define TPS68470_VIOVAL_IOVOLT_MASK	GENMASK(6, 0)
+#define TPS68470_VSIOVAL_IOVOLT_MASK	GENMASK(6, 0)
+#define TPS68470_VAUX1VAL_AUX1VOLT_MASK	GENMASK(6, 0)
+#define TPS68470_VAUX2VAL_AUX2VOLT_MASK	GENMASK(6, 0)
+
+#define TPS68470_VACTL_EN_MASK		GENMASK(0, 0)
+#define TPS68470_VDCTL_EN_MASK		GENMASK(0, 0)
+#define TPS68470_VCMCTL_EN_MASK		GENMASK(0, 0)
+#define TPS68470_S_I2C_CTL_EN_MASK	GENMASK(1, 0)
+#define TPS68470_VAUX1CTL_EN_MASK	GENMASK(0, 0)
+#define TPS68470_VAUX2CTL_EN_MASK	GENMASK(0, 0)
+#define TPS68470_PLL_EN_MASK		GENMASK(0, 0)
+
+#define TPS68470_OSC_EXT_CAP_SHIFT	4
+#define TPS68470_OSC_EXT_CAP_DEFAULT	0x05	/* 10pf */
+
+#define TPS68470_CLK_SRC_SHIFT		7
+#define TPS68470_CLK_SRC_GPIO3		0
+#define TPS68470_CLK_SRC_XTAL		1
+
+#define TPS68470_DRV_STR_1MA		0
+#define TPS68470_DRV_STR_2MA		1
+#define TPS68470_DRV_STR_4MA		2
+#define TPS68470_DRV_STR_8MA		3
+#define TPS68470_DRV_STR_A_SHIFT	0
+#define TPS68470_DRV_STR_B_SHIFT	2
+
+#define TPS68470_OUTPUT_XTAL_BUFFERED	1
+#define TPS68470_PLL_OUTPUT_ENABLE	2
+#define TPS68470_PLL_OUTPUT_SS_ENABLE	3
+#define TPS68470_OUTPUT_A_SHIFT		0
+#define TPS68470_OUTPUT_B_SHIFT		2
+
+#define TPS68470_CLKCFG1_MODE_A_MASK	GENMASK(1, 0)
+#define TPS68470_CLKCFG1_MODE_B_MASK	GENMASK(3, 2)
+
+#define TPS68470_GPIO_CTL_REG_A(x)	(TPS68470_REG_GPCTL0A + (x) * 2)
+#define TPS68470_GPIO_CTL_REG_B(x)	(TPS68470_REG_GPCTL0B + (x) * 2)
+#define TPS68470_GPIO_MODE_MASK		GENMASK(1, 0)
+#define TPS68470_GPIO_MODE_IN		0
+#define TPS68470_GPIO_MODE_IN_PULLUP	1
+#define TPS68470_GPIO_MODE_OUT_CMOS	2
+#define TPS68470_GPIO_MODE_OUT_ODRAIN	3
+
+#define TPS68470_PLL_STARTUP_DELAY_US	1000
+#define TPS68470_DAISY_CHAIN_DELAY_US	3000
+
+/**
+ * struct tps68470 - tps68470 sub-driver chip access routines
+ *
+ * Device data may be used to access the TPS68470 chip
+ */
+
+struct tps68470 {
+	struct device *dev;
+	struct regmap *regmap;
+	/*
+	 * Used to synchronize access to tps68470_ operations
+	 * and addition and removal of mfd devices
+	 */
+	struct mutex lock;
+};
+
+int tps68470_reg_read(struct tps68470 *tps, unsigned int reg,
+		      unsigned int *val);
+int tps68470_reg_write(struct tps68470 *tps, unsigned int reg,
+		       unsigned int val);
+int tps68470_update_bits(struct tps68470 *tps, unsigned int reg,
+		      unsigned int mask, unsigned int val);
+
+#endif /* __LINUX_MFD_TPS68470_H */