[2/2] mfd: max597x: Add support for MAX5970 and MAX5978

Message ID 20230301091234.3159953-2-Naresh.Solanki@9elements.com
State New
Headers
Series [1/2] dt-bindings: mfd: Add MAX5970 and MAX5978 |

Commit Message

Naresh Solanki March 1, 2023, 9:12 a.m. UTC
  From: Patrick Rudolph <patrick.rudolph@9elements.com>

Implement a regulator driver with IRQ support for fault management.
Written against documentation [1] and [2] and tested on real hardware.

Every channel has it's own regulator supply nammed 'vss1-supply' and
'vss2-supply'. The regulator supply is used to determine the output
voltage, as the smart switch provides no output regulation.
The driver requires the 'shunt-resistor-micro-ohms' to be present in
the devicetree to properly calculate current related values.

You must specify compatible devictree layout:

regulator@3a {
        reg = <0x3a>;
        vss1-supply = <&p3v3>;
        compatible = "maxim,max5978";

        ...

        regulators {
                sw0_ref: SW0 {
                        regulator-compatible = "SW0";
                        shunt-resistor-micro-ohms = <12000>;
                        ...
                }
        }
}

1: https://datasheets.maximintegrated.com/en/ds/MAX5970.pdf
2: https://datasheets.maximintegrated.com/en/ds/MAX5978.pdf

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Signed-off-by: Marcello Sylvester Bauer <sylv@sylv.io>
Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
---
 drivers/mfd/Kconfig          | 10 ++++
 drivers/mfd/simple-mfd-i2c.c | 13 +++++
 include/linux/mfd/max597x.h  | 97 ++++++++++++++++++++++++++++++++++++
 3 files changed, 120 insertions(+)
 create mode 100644 include/linux/mfd/max597x.h
  

Comments

kernel test robot March 1, 2023, 8:10 p.m. UTC | #1
Hi Naresh,

I love your patch! Yet something to improve:

[auto build test ERROR on 59c54c59974649b2e7bc92faae4a21e2b2408db2]

url:    https://github.com/intel-lab-lkp/linux/commits/Naresh-Solanki/mfd-max597x-Add-support-for-MAX5970-and-MAX5978/20230301-171527
base:   59c54c59974649b2e7bc92faae4a21e2b2408db2
patch link:    https://lore.kernel.org/r/20230301091234.3159953-2-Naresh.Solanki%409elements.com
patch subject: [PATCH 2/2] mfd: max597x: Add support for MAX5970 and MAX5978
config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20230302/202303020344.8ATqgdUl-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/68623f7868d887a57422ce2cd6f5dc1ee1510f1e
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Naresh-Solanki/mfd-max597x-Add-support-for-MAX5970-and-MAX5978/20230301-171527
        git checkout 68623f7868d887a57422ce2cd6f5dc1ee1510f1e
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh SHELL=/bin/bash drivers/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303020344.8ATqgdUl-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/regulator/max597x-regulator.c: In function 'max597x_regulator_probe':
>> drivers/regulator/max597x-regulator.c:447:41: error: 'struct max597x_data' has no member named 'dev'
     447 |                     devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator),
         |                                         ^~
>> drivers/regulator/max597x-regulator.c:453:39: error: 'struct max597x_data' has no member named 'regmap'
     453 |                 data->regmap = max597x->regmap;
         |                                       ^~
   drivers/regulator/max597x-regulator.c:462:37: error: 'struct max597x_data' has no member named 'dev'
     462 |                 config.dev = max597x->dev;
         |                                     ^~
   drivers/regulator/max597x-regulator.c:465:55: error: 'struct max597x_data' has no member named 'dev'
     465 |                 rdev = devm_regulator_register(max597x->dev,
         |                                                       ^~
   In file included from include/linux/device.h:15,
                    from drivers/regulator/max597x-regulator.c:11:
   drivers/regulator/max597x-regulator.c:468:40: error: 'struct max597x_data' has no member named 'dev'
     468 |                         dev_err(max597x->dev, "failed to register regulator %s\n",
         |                                        ^~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   drivers/regulator/max597x-regulator.c:468:25: note: in expansion of macro 'dev_err'
     468 |                         dev_err(max597x->dev, "failed to register regulator %s\n",
         |                         ^~~~~~~
>> drivers/regulator/max597x-regulator.c:476:20: error: 'struct max597x_data' has no member named 'irq'
     476 |         if (max597x->irq) {
         |                    ^~
   drivers/regulator/max597x-regulator.c:478:46: error: 'struct max597x_data' has no member named 'dev'
     478 |                     max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
         |                                              ^~
   drivers/regulator/max597x-regulator.c:478:60: error: 'struct max597x_data' has no member named 'irq'
     478 |                     max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
         |                                                            ^~
   drivers/regulator/max597x-regulator.c:481:40: error: 'struct max597x_data' has no member named 'dev'
     481 |                         dev_err(max597x->dev, "IRQ setup failed");
         |                                        ^~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   drivers/regulator/max597x-regulator.c:481:25: note: in expansion of macro 'dev_err'
     481 |                         dev_err(max597x->dev, "IRQ setup failed");
         |                         ^~~~~~~
   drivers/regulator/max597x-regulator.c: At top level:
   drivers/regulator/max597x-regulator.c:360:35: warning: 'max597x_regmap_config' defined but not used [-Wunused-const-variable=]
     360 | static const struct regmap_config max597x_regmap_config = {
         |                                   ^~~~~~~~~~~~~~~~~~~~~


vim +447 drivers/regulator/max597x-regulator.c

38493f008deb435 Patrick Rudolph 2022-07-05  434  
38493f008deb435 Patrick Rudolph 2022-07-05  435  
38493f008deb435 Patrick Rudolph 2022-07-05  436  	struct max597x_data *max597x = dev_get_drvdata(pdev->dev.parent);
38493f008deb435 Patrick Rudolph 2022-07-05  437  	struct max597x_regulator *data;
38493f008deb435 Patrick Rudolph 2022-07-05  438  
38493f008deb435 Patrick Rudolph 2022-07-05  439  	struct regulator_config config = { };
38493f008deb435 Patrick Rudolph 2022-07-05  440  	struct regulator_dev *rdev;
38493f008deb435 Patrick Rudolph 2022-07-05  441  	struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES];
38493f008deb435 Patrick Rudolph 2022-07-05  442  	int num_switches = max597x->num_switches;
38493f008deb435 Patrick Rudolph 2022-07-05  443  	int ret, i;
38493f008deb435 Patrick Rudolph 2022-07-05  444  
38493f008deb435 Patrick Rudolph 2022-07-05  445  	for (i = 0; i < num_switches; i++) {
38493f008deb435 Patrick Rudolph 2022-07-05  446  		data =
38493f008deb435 Patrick Rudolph 2022-07-05 @447  		    devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator),
38493f008deb435 Patrick Rudolph 2022-07-05  448  				 GFP_KERNEL);
38493f008deb435 Patrick Rudolph 2022-07-05  449  		if (!data)
38493f008deb435 Patrick Rudolph 2022-07-05  450  			return -ENOMEM;
38493f008deb435 Patrick Rudolph 2022-07-05  451  
38493f008deb435 Patrick Rudolph 2022-07-05  452  		data->num_switches = num_switches;
38493f008deb435 Patrick Rudolph 2022-07-05 @453  		data->regmap = max597x->regmap;
38493f008deb435 Patrick Rudolph 2022-07-05  454  
38493f008deb435 Patrick Rudolph 2022-07-05  455  		ret = max597x_adc_range(data->regmap, i, &max597x->irng[i], &max597x->mon_rng[i]);
38493f008deb435 Patrick Rudolph 2022-07-05  456  		if (ret < 0)
38493f008deb435 Patrick Rudolph 2022-07-05  457  			return ret;
38493f008deb435 Patrick Rudolph 2022-07-05  458  
38493f008deb435 Patrick Rudolph 2022-07-05  459  		data->irng = max597x->irng[i];
38493f008deb435 Patrick Rudolph 2022-07-05  460  		data->mon_rng = max597x->mon_rng[i];
38493f008deb435 Patrick Rudolph 2022-07-05  461  
38493f008deb435 Patrick Rudolph 2022-07-05  462  		config.dev = max597x->dev;
38493f008deb435 Patrick Rudolph 2022-07-05  463  		config.driver_data = (void *)data;
38493f008deb435 Patrick Rudolph 2022-07-05  464  		config.regmap = data->regmap;
38493f008deb435 Patrick Rudolph 2022-07-05  465  		rdev = devm_regulator_register(max597x->dev,
38493f008deb435 Patrick Rudolph 2022-07-05  466  					       &regulators[i], &config);
38493f008deb435 Patrick Rudolph 2022-07-05  467  		if (IS_ERR(rdev)) {
38493f008deb435 Patrick Rudolph 2022-07-05  468  			dev_err(max597x->dev, "failed to register regulator %s\n",
38493f008deb435 Patrick Rudolph 2022-07-05  469  				regulators[i].name);
38493f008deb435 Patrick Rudolph 2022-07-05  470  			return PTR_ERR(rdev);
38493f008deb435 Patrick Rudolph 2022-07-05  471  		}
38493f008deb435 Patrick Rudolph 2022-07-05  472  		rdevs[i] = rdev;
38493f008deb435 Patrick Rudolph 2022-07-05  473  		max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms;
38493f008deb435 Patrick Rudolph 2022-07-05  474  	}
38493f008deb435 Patrick Rudolph 2022-07-05  475  
38493f008deb435 Patrick Rudolph 2022-07-05 @476  	if (max597x->irq) {
38493f008deb435 Patrick Rudolph 2022-07-05  477  		ret =
38493f008deb435 Patrick Rudolph 2022-07-05  478  		    max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
38493f008deb435 Patrick Rudolph 2022-07-05  479  				      data);
38493f008deb435 Patrick Rudolph 2022-07-05  480  		if (ret) {
38493f008deb435 Patrick Rudolph 2022-07-05  481  			dev_err(max597x->dev, "IRQ setup failed");
38493f008deb435 Patrick Rudolph 2022-07-05  482  			return ret;
38493f008deb435 Patrick Rudolph 2022-07-05  483  		}
38493f008deb435 Patrick Rudolph 2022-07-05  484  	}
38493f008deb435 Patrick Rudolph 2022-07-05  485  
38493f008deb435 Patrick Rudolph 2022-07-05  486  	return ret;
38493f008deb435 Patrick Rudolph 2022-07-05  487  }
38493f008deb435 Patrick Rudolph 2022-07-05  488
  
kernel test robot March 2, 2023, 4:11 a.m. UTC | #2
Hi Naresh,

I love your patch! Perhaps something to improve:

[auto build test WARNING on 59c54c59974649b2e7bc92faae4a21e2b2408db2]

url:    https://github.com/intel-lab-lkp/linux/commits/Naresh-Solanki/mfd-max597x-Add-support-for-MAX5970-and-MAX5978/20230301-171527
base:   59c54c59974649b2e7bc92faae4a21e2b2408db2
patch link:    https://lore.kernel.org/r/20230301091234.3159953-2-Naresh.Solanki%409elements.com
patch subject: [PATCH 2/2] mfd: max597x: Add support for MAX5970 and MAX5978
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20230302/202303021248.Bk9jYUb1-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/68623f7868d887a57422ce2cd6f5dc1ee1510f1e
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Naresh-Solanki/mfd-max597x-Add-support-for-MAX5970-and-MAX5978/20230301-171527
        git checkout 68623f7868d887a57422ce2cd6f5dc1ee1510f1e
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=x86_64 olddefconfig
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/regulator/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303021248.Bk9jYUb1-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/regulator/max597x-regulator.c: In function 'max597x_regulator_probe':
   drivers/regulator/max597x-regulator.c:447:41: error: 'struct max597x_data' has no member named 'dev'
     447 |                     devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator),
         |                                         ^~
   drivers/regulator/max597x-regulator.c:453:39: error: 'struct max597x_data' has no member named 'regmap'
     453 |                 data->regmap = max597x->regmap;
         |                                       ^~
   drivers/regulator/max597x-regulator.c:462:37: error: 'struct max597x_data' has no member named 'dev'
     462 |                 config.dev = max597x->dev;
         |                                     ^~
   drivers/regulator/max597x-regulator.c:465:55: error: 'struct max597x_data' has no member named 'dev'
     465 |                 rdev = devm_regulator_register(max597x->dev,
         |                                                       ^~
   In file included from include/linux/device.h:15,
                    from drivers/regulator/max597x-regulator.c:11:
   drivers/regulator/max597x-regulator.c:468:40: error: 'struct max597x_data' has no member named 'dev'
     468 |                         dev_err(max597x->dev, "failed to register regulator %s\n",
         |                                        ^~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   drivers/regulator/max597x-regulator.c:468:25: note: in expansion of macro 'dev_err'
     468 |                         dev_err(max597x->dev, "failed to register regulator %s\n",
         |                         ^~~~~~~
   drivers/regulator/max597x-regulator.c:476:20: error: 'struct max597x_data' has no member named 'irq'
     476 |         if (max597x->irq) {
         |                    ^~
   drivers/regulator/max597x-regulator.c:478:46: error: 'struct max597x_data' has no member named 'dev'
     478 |                     max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
         |                                              ^~
   drivers/regulator/max597x-regulator.c:478:60: error: 'struct max597x_data' has no member named 'irq'
     478 |                     max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
         |                                                            ^~
   In file included from include/linux/device.h:15,
                    from drivers/regulator/max597x-regulator.c:11:
   drivers/regulator/max597x-regulator.c:481:40: error: 'struct max597x_data' has no member named 'dev'
     481 |                         dev_err(max597x->dev, "IRQ setup failed");
         |                                        ^~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   drivers/regulator/max597x-regulator.c:481:25: note: in expansion of macro 'dev_err'
     481 |                         dev_err(max597x->dev, "IRQ setup failed");
         |                         ^~~~~~~
   At top level:
>> drivers/regulator/max597x-regulator.c:360:35: warning: 'max597x_regmap_config' defined but not used [-Wunused-const-variable=]
     360 | static const struct regmap_config max597x_regmap_config = {
         |                                   ^~~~~~~~~~~~~~~~~~~~~


vim +/max597x_regmap_config +360 drivers/regulator/max597x-regulator.c

38493f008deb43 Patrick Rudolph 2022-07-05  359  
38493f008deb43 Patrick Rudolph 2022-07-05 @360  static const struct regmap_config max597x_regmap_config = {
38493f008deb43 Patrick Rudolph 2022-07-05  361  	.reg_bits = 8,
38493f008deb43 Patrick Rudolph 2022-07-05  362  	.val_bits = 8,
38493f008deb43 Patrick Rudolph 2022-07-05  363  	.max_register = MAX_REGISTERS,
38493f008deb43 Patrick Rudolph 2022-07-05  364  };
38493f008deb43 Patrick Rudolph 2022-07-05  365
  
Lee Jones March 5, 2023, 11:04 a.m. UTC | #3
On Wed, 01 Mar 2023, Naresh Solanki wrote:

> From: Patrick Rudolph <patrick.rudolph@9elements.com>
> 
> Implement a regulator driver with IRQ support for fault management.
> Written against documentation [1] and [2] and tested on real hardware.
> 
> Every channel has it's own regulator supply nammed 'vss1-supply' and
> 'vss2-supply'. The regulator supply is used to determine the output
> voltage, as the smart switch provides no output regulation.
> The driver requires the 'shunt-resistor-micro-ohms' to be present in
> the devicetree to properly calculate current related values.
> 
> You must specify compatible devictree layout:
> 
> regulator@3a {
>         reg = <0x3a>;
>         vss1-supply = <&p3v3>;
>         compatible = "maxim,max5978";
> 
>         ...
> 
>         regulators {
>                 sw0_ref: SW0 {
>                         regulator-compatible = "SW0";
>                         shunt-resistor-micro-ohms = <12000>;
>                         ...
>                 }
>         }
> }
> 
> 1: https://datasheets.maximintegrated.com/en/ds/MAX5970.pdf
> 2: https://datasheets.maximintegrated.com/en/ds/MAX5978.pdf
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
> Signed-off-by: Marcello Sylvester Bauer <sylv@sylv.io>
> Signed-off-by: Naresh Solanki <Naresh.Solanki@9elements.com>
> ---
>  drivers/mfd/Kconfig          | 10 ++++
>  drivers/mfd/simple-mfd-i2c.c | 13 +++++
>  include/linux/mfd/max597x.h  | 97 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 120 insertions(+)
>  create mode 100644 include/linux/mfd/max597x.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index d4fc4ca9fdbd..de899e0d2f1a 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -266,6 +266,16 @@ config MFD_MADERA_SPI
>  	  Support for the Cirrus Logic Madera platform audio SoC
>  	  core functionality controlled via SPI.
>  
> +config MFD_MAX597X
> +	tristate "Maxim 597x power switch and monitor"
> +	depends on (I2C && OF)
> +	select MFD_SIMPLE_MFD_I2C
> +	help
> +	  This driver controls a Maxim 5970/5978 switch via I2C bus.
> +	  The MAX5970/5978 is a smart switch with no output regulation, but
> +	  fault protection and voltage and current monitoring capabilities.
> +	  Also it supports upto 4 indication leds.
> +
>  config MFD_CS47L15
>  	bool "Cirrus Logic CS47L15"
>  	select PINCTRL_CS47L15
> diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
> index e31f13fd6a79..20782b4dd172 100644
> --- a/drivers/mfd/simple-mfd-i2c.c
> +++ b/drivers/mfd/simple-mfd-i2c.c
> @@ -72,9 +72,22 @@ static const struct simple_mfd_data silergy_sy7636a = {
>  	.mfd_cell_size = ARRAY_SIZE(sy7636a_cells),
>  };
>  
> +static const struct mfd_cell max597x_cells[] = {
> +	{ .name = "max597x-regulator", },
> +	{ .name = "max597x-iio", },
> +	{ .name = "max597x-led", },
> +};
> +
> +static const struct simple_mfd_data maxim_max597x = {
> +	.mfd_cell = max597x_cells,
> +	.mfd_cell_size = ARRAY_SIZE(max597x_cells),
> +};
> +
>  static const struct of_device_id simple_mfd_i2c_of_match[] = {
>  	{ .compatible = "kontron,sl28cpld" },
>  	{ .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
> +	{ .compatible = "maxim,max5970", .data = &maxim_max597x},
> +	{ .compatible = "maxim,max5978", .data = &maxim_max597x},
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);
> diff --git a/include/linux/mfd/max597x.h b/include/linux/mfd/max597x.h
> new file mode 100644
> index 000000000000..8a4da98caf3e
> --- /dev/null
> +++ b/include/linux/mfd/max597x.h
> @@ -0,0 +1,97 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Device driver for regulators in MAX5970 and MAX5978 IC
> + *
> + * Copyright (c) 2022 9elements GmbH
> + *
> + * Author: Patrick Rudolph <patrick.rudolph@9elements.com>
> + */
> +
> +#ifndef _MAX597X_H
> +#define _MAX597X_H

__MFD_*

> +#include <linux/regmap.h>
> +
> +#define MAX5970_NUM_SWITCHES 2
> +#define MAX5978_NUM_SWITCHES 1
> +#define MAX597X_NUM_LEDS     4
> +
> +struct max597x_data {
> +	int num_switches;
> +	u32 irng[MAX5970_NUM_SWITCHES];
> +	u32 mon_rng[MAX5970_NUM_SWITCHES];
> +	u32 shunt_micro_ohms[MAX5970_NUM_SWITCHES];
> +};
> +
> +enum max597x_chip_type {
> +	MAX597x_TYPE_MAX5978 = 1,
> +	MAX597x_TYPE_MAX5970,
> +};
> +
> +#define MAX5970_REG_CURRENT_L(ch)		(0x01 + (ch) * 4)
> +#define MAX5970_REG_CURRENT_H(ch)		(0x00 + (ch) * 4)
> +#define MAX5970_REG_VOLTAGE_L(ch)		(0x03 + (ch) * 4)
> +#define MAX5970_REG_VOLTAGE_H(ch)		(0x02 + (ch) * 4)
> +#define MAX5970_REG_MON_RANGE			0x18
> +#define  MAX5970_MON_MASK			0x3
> +#define  MAX5970_MON(reg, ch) \
> +	(((reg) >> ((ch) * 2)) & MAX5970_MON_MASK)

Why the '\n'?

> +#define  MAX5970_MON_MAX_RANGE_UV		16000000
> +
> +#define MAX5970_REG_CH_UV_WARN_H(ch)		(0x1A + (ch) * 10)
> +#define MAX5970_REG_CH_UV_WARN_L(ch)		(0x1B + (ch) * 10)
> +#define MAX5970_REG_CH_UV_CRIT_H(ch)		(0x1C + (ch) * 10)
> +#define MAX5970_REG_CH_UV_CRIT_L(ch)		(0x1D + (ch) * 10)
> +#define MAX5970_REG_CH_OV_WARN_H(ch)		(0x1E + (ch) * 10)
> +#define MAX5970_REG_CH_OV_WARN_L(ch)		(0x1F + (ch) * 10)
> +#define MAX5970_REG_CH_OV_CRIT_H(ch)		(0x20 + (ch) * 10)
> +#define MAX5970_REG_CH_OV_CRIT_L(ch)		(0x21 + (ch) * 10)
> +
> +#define  MAX5970_VAL2REG_H(x)		(((x) >> 2) & 0xFF)
> +#define  MAX5970_VAL2REG_L(x)		((x) & 0x3)
> +
> +#define MAX5970_REG_DAC_FAST(ch)	(0x2E + (ch))
> +
> +#define MAX5970_FAST2SLOW_RATIO		200
> +
> +#define MAX5970_REG_STATUS0		0x31
> +#define  MAX5970_CB_IFAULTF(ch)		(1 << (ch))
> +#define  MAX5970_CB_IFAULTS(ch)		(1 << ((ch) + 4))
> +
> +#define MAX5970_REG_STATUS1		0x32
> +#define  STATUS1_PROT_MASK		0x3
> +#define  STATUS1_PROT(reg) \
> +	(((reg) >> 6) & STATUS1_PROT_MASK)
> +#define  STATUS1_PROT_SHUTDOWN		0
> +#define  STATUS1_PROT_CLEAR_PG		1
> +#define  STATUS1_PROT_ALERT_ONLY	2
> +
> +#define MAX5970_REG_STATUS2		0x33
> +#define  MAX5970_IRNG_MASK		0x3
> +#define  MAX5970_IRNG(reg, ch) \
> +	(((reg) >> ((ch) * 2)) & MAX5970_IRNG_MASK)
> +
> +#define MAX5970_REG_STATUS3		0x34
> +#define  MAX5970_STATUS3_ALERT		BIT(4)
> +#define  MAX5970_STATUS3_PG(ch)		BIT(ch)
> +
> +#define MAX5970_REG_FAULT0		0x35
> +#define  UV_STATUS_WARN(ch)		(1 << (ch))
> +#define  UV_STATUS_CRIT(ch)		(1 << ((ch) + 4))
> +
> +#define MAX5970_REG_FAULT1		0x36
> +#define  OV_STATUS_WARN(ch)		(1 << (ch))
> +#define  OV_STATUS_CRIT(ch)		(1 << ((ch) + 4))
> +
> +#define MAX5970_REG_FAULT2		0x37
> +#define  OC_STATUS_WARN(ch)		(1 << (ch))
> +
> +#define MAX5970_REG_CHXEN		0x3b
> +#define  CHXEN(ch)			(3 << ((ch) * 2))
> +
> +#define MAX5970_REG_LED_FLASH		0x43
> +
> +#define MAX_REGISTERS			0x49
> +#define ADC_MASK			0x3FF
> +
> +#endif				/* _MAX597X_H */
> -- 
> 2.39.1
>
  

Patch

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d4fc4ca9fdbd..de899e0d2f1a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -266,6 +266,16 @@  config MFD_MADERA_SPI
 	  Support for the Cirrus Logic Madera platform audio SoC
 	  core functionality controlled via SPI.
 
+config MFD_MAX597X
+	tristate "Maxim 597x power switch and monitor"
+	depends on (I2C && OF)
+	select MFD_SIMPLE_MFD_I2C
+	help
+	  This driver controls a Maxim 5970/5978 switch via I2C bus.
+	  The MAX5970/5978 is a smart switch with no output regulation, but
+	  fault protection and voltage and current monitoring capabilities.
+	  Also it supports upto 4 indication leds.
+
 config MFD_CS47L15
 	bool "Cirrus Logic CS47L15"
 	select PINCTRL_CS47L15
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
index e31f13fd6a79..20782b4dd172 100644
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -72,9 +72,22 @@  static const struct simple_mfd_data silergy_sy7636a = {
 	.mfd_cell_size = ARRAY_SIZE(sy7636a_cells),
 };
 
+static const struct mfd_cell max597x_cells[] = {
+	{ .name = "max597x-regulator", },
+	{ .name = "max597x-iio", },
+	{ .name = "max597x-led", },
+};
+
+static const struct simple_mfd_data maxim_max597x = {
+	.mfd_cell = max597x_cells,
+	.mfd_cell_size = ARRAY_SIZE(max597x_cells),
+};
+
 static const struct of_device_id simple_mfd_i2c_of_match[] = {
 	{ .compatible = "kontron,sl28cpld" },
 	{ .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
+	{ .compatible = "maxim,max5970", .data = &maxim_max597x},
+	{ .compatible = "maxim,max5978", .data = &maxim_max597x},
 	{}
 };
 MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);
diff --git a/include/linux/mfd/max597x.h b/include/linux/mfd/max597x.h
new file mode 100644
index 000000000000..8a4da98caf3e
--- /dev/null
+++ b/include/linux/mfd/max597x.h
@@ -0,0 +1,97 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device driver for regulators in MAX5970 and MAX5978 IC
+ *
+ * Copyright (c) 2022 9elements GmbH
+ *
+ * Author: Patrick Rudolph <patrick.rudolph@9elements.com>
+ */
+
+#ifndef _MAX597X_H
+#define _MAX597X_H
+
+#include <linux/regmap.h>
+
+#define MAX5970_NUM_SWITCHES 2
+#define MAX5978_NUM_SWITCHES 1
+#define MAX597X_NUM_LEDS     4
+
+struct max597x_data {
+	int num_switches;
+	u32 irng[MAX5970_NUM_SWITCHES];
+	u32 mon_rng[MAX5970_NUM_SWITCHES];
+	u32 shunt_micro_ohms[MAX5970_NUM_SWITCHES];
+};
+
+enum max597x_chip_type {
+	MAX597x_TYPE_MAX5978 = 1,
+	MAX597x_TYPE_MAX5970,
+};
+
+#define MAX5970_REG_CURRENT_L(ch)		(0x01 + (ch) * 4)
+#define MAX5970_REG_CURRENT_H(ch)		(0x00 + (ch) * 4)
+#define MAX5970_REG_VOLTAGE_L(ch)		(0x03 + (ch) * 4)
+#define MAX5970_REG_VOLTAGE_H(ch)		(0x02 + (ch) * 4)
+#define MAX5970_REG_MON_RANGE			0x18
+#define  MAX5970_MON_MASK			0x3
+#define  MAX5970_MON(reg, ch) \
+	(((reg) >> ((ch) * 2)) & MAX5970_MON_MASK)
+#define  MAX5970_MON_MAX_RANGE_UV		16000000
+
+#define MAX5970_REG_CH_UV_WARN_H(ch)		(0x1A + (ch) * 10)
+#define MAX5970_REG_CH_UV_WARN_L(ch)		(0x1B + (ch) * 10)
+#define MAX5970_REG_CH_UV_CRIT_H(ch)		(0x1C + (ch) * 10)
+#define MAX5970_REG_CH_UV_CRIT_L(ch)		(0x1D + (ch) * 10)
+#define MAX5970_REG_CH_OV_WARN_H(ch)		(0x1E + (ch) * 10)
+#define MAX5970_REG_CH_OV_WARN_L(ch)		(0x1F + (ch) * 10)
+#define MAX5970_REG_CH_OV_CRIT_H(ch)		(0x20 + (ch) * 10)
+#define MAX5970_REG_CH_OV_CRIT_L(ch)		(0x21 + (ch) * 10)
+
+#define  MAX5970_VAL2REG_H(x)		(((x) >> 2) & 0xFF)
+#define  MAX5970_VAL2REG_L(x)		((x) & 0x3)
+
+#define MAX5970_REG_DAC_FAST(ch)	(0x2E + (ch))
+
+#define MAX5970_FAST2SLOW_RATIO		200
+
+#define MAX5970_REG_STATUS0		0x31
+#define  MAX5970_CB_IFAULTF(ch)		(1 << (ch))
+#define  MAX5970_CB_IFAULTS(ch)		(1 << ((ch) + 4))
+
+#define MAX5970_REG_STATUS1		0x32
+#define  STATUS1_PROT_MASK		0x3
+#define  STATUS1_PROT(reg) \
+	(((reg) >> 6) & STATUS1_PROT_MASK)
+#define  STATUS1_PROT_SHUTDOWN		0
+#define  STATUS1_PROT_CLEAR_PG		1
+#define  STATUS1_PROT_ALERT_ONLY	2
+
+#define MAX5970_REG_STATUS2		0x33
+#define  MAX5970_IRNG_MASK		0x3
+#define  MAX5970_IRNG(reg, ch) \
+	(((reg) >> ((ch) * 2)) & MAX5970_IRNG_MASK)
+
+#define MAX5970_REG_STATUS3		0x34
+#define  MAX5970_STATUS3_ALERT		BIT(4)
+#define  MAX5970_STATUS3_PG(ch)		BIT(ch)
+
+#define MAX5970_REG_FAULT0		0x35
+#define  UV_STATUS_WARN(ch)		(1 << (ch))
+#define  UV_STATUS_CRIT(ch)		(1 << ((ch) + 4))
+
+#define MAX5970_REG_FAULT1		0x36
+#define  OV_STATUS_WARN(ch)		(1 << (ch))
+#define  OV_STATUS_CRIT(ch)		(1 << ((ch) + 4))
+
+#define MAX5970_REG_FAULT2		0x37
+#define  OC_STATUS_WARN(ch)		(1 << (ch))
+
+#define MAX5970_REG_CHXEN		0x3b
+#define  CHXEN(ch)			(3 << ((ch) * 2))
+
+#define MAX5970_REG_LED_FLASH		0x43
+
+#define MAX_REGISTERS			0x49
+#define ADC_MASK			0x3FF
+
+#endif				/* _MAX597X_H */