[RFC,v1] net: dsa: microchip: add KSZ9477 I2C driver
diff mbox series

Message ID 1547695462-31618-2-git-send-email-Tristram.Ha@microchip.com
State RFC
Delegated to: David Miller
Headers show
Series
  • [RFC,v1] net: dsa: microchip: add KSZ9477 I2C driver
Related show

Commit Message

Tristram.Ha@microchip.com Jan. 17, 2019, 3:24 a.m. UTC
From: Tristram Ha <Tristram.Ha@microchip.com>

Add KSZ9477 I2C driver support.  The code ksz9477.c and ksz_common.c are
used together to generate the I2C driver.

Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
---
 drivers/net/dsa/microchip/Kconfig       |   7 ++
 drivers/net/dsa/microchip/Makefile      |   1 +
 drivers/net/dsa/microchip/ksz9477_i2c.c | 120 ++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+)
 create mode 100644 drivers/net/dsa/microchip/ksz9477_i2c.c

Comments

Dan Carpenter Jan. 17, 2019, 8:38 a.m. UTC | #1
No need to send this as an RFC patch.  Adding a new driver is
normal and uncontroversial.

On Wed, Jan 16, 2019 at 07:24:22PM -0800, Tristram.Ha@microchip.com wrote:
> +
> +	i2c_set_clientdata(i2c, dev);
                                ^^^
> +
> +	return 0;
> +}
> +
> +static int ksz9477_i2c_remove(struct i2c_client *i2c)
> +{
> +	struct ksz_device *dev = i2c_get_clientdata(i2c);
> +
> +	if (dev)
            ^^^
No need.

> +		ksz_switch_remove(dev);
> +
> +	return 0;
> +}
> +

regards,
dan carpenter
Sergio Paracuellos Jan. 17, 2019, 9:36 a.m. UTC | #2
On Thu, Jan 17, 2019 at 4:24 AM <Tristram.Ha@microchip.com> wrote:
>
> From: Tristram Ha <Tristram.Ha@microchip.com>
>
> Add KSZ9477 I2C driver support.  The code ksz9477.c and ksz_common.c are
> used together to generate the I2C driver.
>
> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
> ---
>  drivers/net/dsa/microchip/Kconfig       |   7 ++
>  drivers/net/dsa/microchip/Makefile      |   1 +
>  drivers/net/dsa/microchip/ksz9477_i2c.c | 120 ++++++++++++++++++++++++++++++++
>  3 files changed, 128 insertions(+)
>  create mode 100644 drivers/net/dsa/microchip/ksz9477_i2c.c
>
> diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
> index 385b93f..1798755 100644
> --- a/drivers/net/dsa/microchip/Kconfig
> +++ b/drivers/net/dsa/microchip/Kconfig
> @@ -9,6 +9,13 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477
>         help
>           This driver adds support for Microchip KSZ9477 switch chips.
>
> +config NET_DSA_MICROCHIP_KSZ9477_I2C
> +       tristate "KSZ9477 series I2C connected switch driver"
> +       depends on NET_DSA_MICROCHIP_KSZ9477 && I2C
> +       select REGMAP_I2C
> +       help
> +         Select to enable support for registering switches configured through I2C.
> +
>  config NET_DSA_MICROCHIP_KSZ9477_SPI
>         tristate "KSZ9477 series SPI connected switch driver"
>         depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
> diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
> index 3142c18..dbcc5db 100644
> --- a/drivers/net/dsa/microchip/Makefile
> +++ b/drivers/net/dsa/microchip/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)     += ksz_common.o
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)                += ksz9477.o
> +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)    += ksz9477_i2c.o
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)    += ksz9477_spi.o
> diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
> new file mode 100644
> index 0000000..d8720ff
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Microchip KSZ9477 series register access through I2C
> + *
> + * Copyright (C) 2018-2019 Microchip Technology Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +
> +#include "ksz_priv.h"
> +
> +#define REG_SIZE                       0x8000
> +
> +#define I2C_REGMAP_VAL                 8
> +#define I2C_REGMAP_REG                 16
> +
> +#define KSZ_REGMAP_COMMON(n, width)                                    \
> +{                                                                      \
> +       .name                   = n,                                    \
> +       .max_register           = REG_SIZE - (width),                   \
> +       .reg_bits               = I2C_REGMAP_REG,                       \
> +       .val_bits               = I2C_REGMAP_VAL * (width),             \
> +       .reg_stride             = (width),                              \
> +       .reg_format_endian      = REGMAP_ENDIAN_BIG,                    \
> +       .val_format_endian      = REGMAP_ENDIAN_BIG,                    \
> +}
> +
> +static const struct regmap_config ksz9477_regmap_cfg[] = {
> +       KSZ_REGMAP_COMMON("8", 1),
> +       KSZ_REGMAP_COMMON("16", 2),
> +       KSZ_REGMAP_COMMON("32", 4),
> +};
> +
> +static int ksz9477_i2c_probe(struct i2c_client *i2c,
> +                            const struct i2c_device_id *i2c_id)
> +{
> +       struct ksz_device *dev;
> +       int i;
> +       int ret;
> +
> +       dev = ksz_switch_alloc(&i2c->dev);
> +       if (!dev)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_cfg); i++) {
> +               dev->regmap[i] = devm_regmap_init_i2c(i2c,
> +                                                     &ksz9477_regmap_cfg[i]);
> +               if (IS_ERR(dev->regmap[i])) {
> +                       ret = PTR_ERR(dev->regmap[i]);
> +                       dev_err(&i2c->dev, "Failed to initialize regmap: %d\n",
> +                               ret);
> +                       return ret;
> +               }
> +       }
> +
> +       if (i2c->dev.platform_data)
> +               dev->pdata = i2c->dev.platform_data;
> +
> +       ret = ksz9477_switch_register(dev);
> +
> +       /* Main DSA driver may not be started yet. */
> +       if (ret)
> +               return ret;
> +
> +       i2c_set_clientdata(i2c, dev);
> +
> +       return 0;
> +}
> +
> +static int ksz9477_i2c_remove(struct i2c_client *i2c)
> +{
> +       struct ksz_device *dev = i2c_get_clientdata(i2c);
> +
> +       if (dev)
> +               ksz_switch_remove(dev);
> +
> +       return 0;
> +}
> +
> +static void ksz9477_i2c_shutdown(struct i2c_client *i2c)
> +{
> +       struct ksz_device *dev = i2c_get_clientdata(i2c);
> +
> +       if (dev && dev->dev_ops->shutdown)
> +               dev->dev_ops->shutdown(dev);
> +}
> +
> +static const struct i2c_device_id ksz9477_i2c_id[] = {
> +       { "ksz9477-switch", 0 },
> +       {},
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, ksz9477_i2c_id);
> +
> +static const struct of_device_id ksz9477_dt_ids[] = {
> +       { .compatible = "microchip,ksz9477" },
> +       { .compatible = "microchip,ksz9897" },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
> +
> +static struct i2c_driver ksz9477_i2c_driver = {
> +       .driver = {
> +               .name   = "ksz9477-switch",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(ksz9477_dt_ids),
> +       },
> +       .probe  = ksz9477_i2c_probe,
> +       .remove = ksz9477_i2c_remove,
> +       .shutdown = ksz9477_i2c_shutdown,
> +       .id_table = ksz9477_i2c_id,
> +};
> +
> +module_i2c_driver(ksz9477_i2c_driver);
> +
> +MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
> +MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch I2C Driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.1
>
I have to make use of the microchip regs_bin utility and one extra
patch to provide access to switch registers through
/sys/bus/i2c/devices/0-005f/registers file because I need to configure
master direct mode with sgmii which is not supported yet by this
driver but the i2c interface using regmap as it is here works for me.
So you can add my:

Tested-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>

Best regards,
    Sergio Paracuellos
Sergio Paracuellos Jan. 17, 2019, 9:49 a.m. UTC | #3
On Thu, Jan 17, 2019 at 10:36 AM Sergio Paracuellos
<sergio.paracuellos@gmail.com> wrote:
>
> On Thu, Jan 17, 2019 at 4:24 AM <Tristram.Ha@microchip.com> wrote:
> >
> > From: Tristram Ha <Tristram.Ha@microchip.com>
> >
> > Add KSZ9477 I2C driver support.  The code ksz9477.c and ksz_common.c are
> > used together to generate the I2C driver.
> >
> > Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
> > ---
> >  drivers/net/dsa/microchip/Kconfig       |   7 ++
> >  drivers/net/dsa/microchip/Makefile      |   1 +
> >  drivers/net/dsa/microchip/ksz9477_i2c.c | 120 ++++++++++++++++++++++++++++++++
> >  3 files changed, 128 insertions(+)
> >  create mode 100644 drivers/net/dsa/microchip/ksz9477_i2c.c
> >
> > diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
> > index 385b93f..1798755 100644
> > --- a/drivers/net/dsa/microchip/Kconfig
> > +++ b/drivers/net/dsa/microchip/Kconfig
> > @@ -9,6 +9,13 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477
> >         help
> >           This driver adds support for Microchip KSZ9477 switch chips.
> >
> > +config NET_DSA_MICROCHIP_KSZ9477_I2C
> > +       tristate "KSZ9477 series I2C connected switch driver"
> > +       depends on NET_DSA_MICROCHIP_KSZ9477 && I2C
> > +       select REGMAP_I2C
> > +       help
> > +         Select to enable support for registering switches configured through I2C.
> > +
> >  config NET_DSA_MICROCHIP_KSZ9477_SPI
> >         tristate "KSZ9477 series SPI connected switch driver"
> >         depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
> > diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
> > index 3142c18..dbcc5db 100644
> > --- a/drivers/net/dsa/microchip/Makefile
> > +++ b/drivers/net/dsa/microchip/Makefile
> > @@ -1,3 +1,4 @@
> >  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)     += ksz_common.o
> >  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)                += ksz9477.o
> > +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)    += ksz9477_i2c.o
> >  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)    += ksz9477_spi.o
> > diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
> > new file mode 100644
> > index 0000000..d8720ff
> > --- /dev/null
> > +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
> > @@ -0,0 +1,120 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Microchip KSZ9477 series register access through I2C
> > + *
> > + * Copyright (C) 2018-2019 Microchip Technology Inc.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +
> > +#include "ksz_priv.h"
> > +
> > +#define REG_SIZE                       0x8000
> > +
> > +#define I2C_REGMAP_VAL                 8
> > +#define I2C_REGMAP_REG                 16
> > +
> > +#define KSZ_REGMAP_COMMON(n, width)                                    \
> > +{                                                                      \
> > +       .name                   = n,                                    \
> > +       .max_register           = REG_SIZE - (width),                   \
> > +       .reg_bits               = I2C_REGMAP_REG,                       \
> > +       .val_bits               = I2C_REGMAP_VAL * (width),             \
> > +       .reg_stride             = (width),                              \
> > +       .reg_format_endian      = REGMAP_ENDIAN_BIG,                    \
> > +       .val_format_endian      = REGMAP_ENDIAN_BIG,                    \
> > +}
> > +
> > +static const struct regmap_config ksz9477_regmap_cfg[] = {
> > +       KSZ_REGMAP_COMMON("8", 1),
> > +       KSZ_REGMAP_COMMON("16", 2),
> > +       KSZ_REGMAP_COMMON("32", 4),
> > +};
> > +
> > +static int ksz9477_i2c_probe(struct i2c_client *i2c,
> > +                            const struct i2c_device_id *i2c_id)
> > +{
> > +       struct ksz_device *dev;
> > +       int i;
> > +       int ret;
> > +
> > +       dev = ksz_switch_alloc(&i2c->dev);
> > +       if (!dev)
> > +               return -ENOMEM;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_cfg); i++) {
> > +               dev->regmap[i] = devm_regmap_init_i2c(i2c,
> > +                                                     &ksz9477_regmap_cfg[i]);
> > +               if (IS_ERR(dev->regmap[i])) {
> > +                       ret = PTR_ERR(dev->regmap[i]);
> > +                       dev_err(&i2c->dev, "Failed to initialize regmap: %d\n",
> > +                               ret);
> > +                       return ret;
> > +               }
> > +       }
> > +
> > +       if (i2c->dev.platform_data)
> > +               dev->pdata = i2c->dev.platform_data;
> > +
> > +       ret = ksz9477_switch_register(dev);
> > +
> > +       /* Main DSA driver may not be started yet. */
> > +       if (ret)
> > +               return ret;
> > +
> > +       i2c_set_clientdata(i2c, dev);
> > +
> > +       return 0;
> > +}
> > +
> > +static int ksz9477_i2c_remove(struct i2c_client *i2c)
> > +{
> > +       struct ksz_device *dev = i2c_get_clientdata(i2c);
> > +
> > +       if (dev)
> > +               ksz_switch_remove(dev);
> > +
> > +       return 0;
> > +}
> > +
> > +static void ksz9477_i2c_shutdown(struct i2c_client *i2c)
> > +{
> > +       struct ksz_device *dev = i2c_get_clientdata(i2c);
> > +
> > +       if (dev && dev->dev_ops->shutdown)
> > +               dev->dev_ops->shutdown(dev);
> > +}
> > +
> > +static const struct i2c_device_id ksz9477_i2c_id[] = {
> > +       { "ksz9477-switch", 0 },
> > +       {},
> > +};
> > +
> > +MODULE_DEVICE_TABLE(i2c, ksz9477_i2c_id);
> > +
> > +static const struct of_device_id ksz9477_dt_ids[] = {
> > +       { .compatible = "microchip,ksz9477" },
> > +       { .compatible = "microchip,ksz9897" },
> > +       {},
> > +};
> > +MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
> > +
> > +static struct i2c_driver ksz9477_i2c_driver = {
> > +       .driver = {
> > +               .name   = "ksz9477-switch",
> > +               .owner  = THIS_MODULE,
> > +               .of_match_table = of_match_ptr(ksz9477_dt_ids),
> > +       },
> > +       .probe  = ksz9477_i2c_probe,
> > +       .remove = ksz9477_i2c_remove,
> > +       .shutdown = ksz9477_i2c_shutdown,
> > +       .id_table = ksz9477_i2c_id,
> > +};
> > +
> > +module_i2c_driver(ksz9477_i2c_driver);
> > +
> > +MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
> > +MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch I2C Driver");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 1.9.1
> >
> I have to make use of the microchip regs_bin utility and one extra
> patch to provide access to switch registers through
> /sys/bus/i2c/devices/0-005f/registers file because I need to configure
> master direct mode with sgmii which is not supported yet by this
> driver but the i2c interface using regmap as it is here works for me.
> So you can add my:
>
> Tested-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
>
> Best regards,
>     Sergio Paracuellos

I forgot to mention that I have tested this on KSZ9897S switch.

Best regards,
    Sergio Paracuellos
Marek Vasut Jan. 18, 2019, 6:22 a.m. UTC | #4
On 1/17/19 4:24 AM, Tristram.Ha@microchip.com wrote:
> From: Tristram Ha <Tristram.Ha@microchip.com>
> 
> Add KSZ9477 I2C driver support.  The code ksz9477.c and ksz_common.c are
> used together to generate the I2C driver.
> 
> Signed-off-by: Tristram Ha <Tristram.Ha@microchip.com>
> ---
>  drivers/net/dsa/microchip/Kconfig       |   7 ++
>  drivers/net/dsa/microchip/Makefile      |   1 +
>  drivers/net/dsa/microchip/ksz9477_i2c.c | 120 ++++++++++++++++++++++++++++++++
>  3 files changed, 128 insertions(+)
>  create mode 100644 drivers/net/dsa/microchip/ksz9477_i2c.c
> 
> diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
> index 385b93f..1798755 100644
> --- a/drivers/net/dsa/microchip/Kconfig
> +++ b/drivers/net/dsa/microchip/Kconfig
> @@ -9,6 +9,13 @@ menuconfig NET_DSA_MICROCHIP_KSZ9477
>  	help
>  	  This driver adds support for Microchip KSZ9477 switch chips.
>  
> +config NET_DSA_MICROCHIP_KSZ9477_I2C
> +	tristate "KSZ9477 series I2C connected switch driver"
> +	depends on NET_DSA_MICROCHIP_KSZ9477 && I2C
> +	select REGMAP_I2C
> +	help
> +	  Select to enable support for registering switches configured through I2C.
> +
>  config NET_DSA_MICROCHIP_KSZ9477_SPI
>  	tristate "KSZ9477 series SPI connected switch driver"
>  	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
> diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
> index 3142c18..dbcc5db 100644
> --- a/drivers/net/dsa/microchip/Makefile
> +++ b/drivers/net/dsa/microchip/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)	+= ksz_common.o
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)		+= ksz9477.o
> +obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)	+= ksz9477_i2c.o
>  obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)	+= ksz9477_spi.o
> diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
> new file mode 100644
> index 0000000..d8720ff
> --- /dev/null
> +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Microchip KSZ9477 series register access through I2C
> + *
> + * Copyright (C) 2018-2019 Microchip Technology Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +
> +#include "ksz_priv.h"
> +
> +#define REG_SIZE			0x8000
> +
> +#define I2C_REGMAP_VAL			8
> +#define I2C_REGMAP_REG			16
> +
> +#define KSZ_REGMAP_COMMON(n, width)					\
> +{									\
> +	.name			= n,					\
> +	.max_register		= REG_SIZE - (width),			\
> +	.reg_bits		= I2C_REGMAP_REG,			\
> +	.val_bits		= I2C_REGMAP_VAL * (width),		\
> +	.reg_stride		= (width),				\
> +	.reg_format_endian	= REGMAP_ENDIAN_BIG,			\
> +	.val_format_endian	= REGMAP_ENDIAN_BIG,			\
> +}
This comes from my regmap RFC series, right ? Why do we need to redefine
it here again ?
Tristram.Ha@microchip.com Jan. 18, 2019, 8:25 p.m. UTC | #5
> > +#define REG_SIZE			0x8000
> > +
> > +#define I2C_REGMAP_VAL			8
> > +#define I2C_REGMAP_REG			16
> > +
> > +#define KSZ_REGMAP_COMMON(n, width)
> 		\
> > +{									\
> > +	.name			= n,					\
> > +	.max_register		= REG_SIZE - (width),			\
> > +	.reg_bits		= I2C_REGMAP_REG,			\
> > +	.val_bits		= I2C_REGMAP_VAL * (width),		\
> > +	.reg_stride		= (width),				\
> > +	.reg_format_endian	= REGMAP_ENDIAN_BIG,
> 	\
> > +	.val_format_endian	= REGMAP_ENDIAN_BIG,
> 	\
> > +}
> This comes from my regmap RFC series, right ? Why do we need to redefine
> it here again ?

This is different from the SPI version.  The variables pad_bits, read_flag_mask, and write_flag_mask are not used.  reg_bits is also different.

For KSZ8795 SPI the differences are SPI_ADDR_S, SPI_TURNAROUND_S, and SPI_CMD_LEN.
Marek Vasut Jan. 19, 2019, 6:22 a.m. UTC | #6
On 1/18/19 9:25 PM, Tristram.Ha@microchip.com wrote:
>>> +#define REG_SIZE			0x8000
>>> +
>>> +#define I2C_REGMAP_VAL			8
>>> +#define I2C_REGMAP_REG			16
>>> +
>>> +#define KSZ_REGMAP_COMMON(n, width)
>> 		\
>>> +{									\
>>> +	.name			= n,					\
>>> +	.max_register		= REG_SIZE - (width),			\
>>> +	.reg_bits		= I2C_REGMAP_REG,			\
>>> +	.val_bits		= I2C_REGMAP_VAL * (width),		\
>>> +	.reg_stride		= (width),				\
>>> +	.reg_format_endian	= REGMAP_ENDIAN_BIG,
>> 	\
>>> +	.val_format_endian	= REGMAP_ENDIAN_BIG,
>> 	\
>>> +}
>> This comes from my regmap RFC series, right ? Why do we need to redefine
>> it here again ?
> 
> This is different from the SPI version.  The variables pad_bits, read_flag_mask, and write_flag_mask are not used.  reg_bits is also different.
> 
> For KSZ8795 SPI the differences are SPI_ADDR_S, SPI_TURNAROUND_S, and SPI_CMD_LEN.

The SPI and I2C protocol of the switch is different ?

Patch
diff mbox series

diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index 385b93f..1798755 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -9,6 +9,13 @@  menuconfig NET_DSA_MICROCHIP_KSZ9477
 	help
 	  This driver adds support for Microchip KSZ9477 switch chips.
 
+config NET_DSA_MICROCHIP_KSZ9477_I2C
+	tristate "KSZ9477 series I2C connected switch driver"
+	depends on NET_DSA_MICROCHIP_KSZ9477 && I2C
+	select REGMAP_I2C
+	help
+	  Select to enable support for registering switches configured through I2C.
+
 config NET_DSA_MICROCHIP_KSZ9477_SPI
 	tristate "KSZ9477 series SPI connected switch driver"
 	depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index 3142c18..dbcc5db 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -1,3 +1,4 @@ 
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)	+= ksz_common.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)		+= ksz9477.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)	+= ksz9477_i2c.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)	+= ksz9477_spi.o
diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c
new file mode 100644
index 0000000..d8720ff
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
@@ -0,0 +1,120 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ9477 series register access through I2C
+ *
+ * Copyright (C) 2018-2019 Microchip Technology Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "ksz_priv.h"
+
+#define REG_SIZE			0x8000
+
+#define I2C_REGMAP_VAL			8
+#define I2C_REGMAP_REG			16
+
+#define KSZ_REGMAP_COMMON(n, width)					\
+{									\
+	.name			= n,					\
+	.max_register		= REG_SIZE - (width),			\
+	.reg_bits		= I2C_REGMAP_REG,			\
+	.val_bits		= I2C_REGMAP_VAL * (width),		\
+	.reg_stride		= (width),				\
+	.reg_format_endian	= REGMAP_ENDIAN_BIG,			\
+	.val_format_endian	= REGMAP_ENDIAN_BIG,			\
+}
+
+static const struct regmap_config ksz9477_regmap_cfg[] = {
+	KSZ_REGMAP_COMMON("8", 1),
+	KSZ_REGMAP_COMMON("16", 2),
+	KSZ_REGMAP_COMMON("32", 4),
+};
+
+static int ksz9477_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *i2c_id)
+{
+	struct ksz_device *dev;
+	int i;
+	int ret;
+
+	dev = ksz_switch_alloc(&i2c->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_cfg); i++) {
+		dev->regmap[i] = devm_regmap_init_i2c(i2c,
+						      &ksz9477_regmap_cfg[i]);
+		if (IS_ERR(dev->regmap[i])) {
+			ret = PTR_ERR(dev->regmap[i]);
+			dev_err(&i2c->dev, "Failed to initialize regmap: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	if (i2c->dev.platform_data)
+		dev->pdata = i2c->dev.platform_data;
+
+	ret = ksz9477_switch_register(dev);
+
+	/* Main DSA driver may not be started yet. */
+	if (ret)
+		return ret;
+
+	i2c_set_clientdata(i2c, dev);
+
+	return 0;
+}
+
+static int ksz9477_i2c_remove(struct i2c_client *i2c)
+{
+	struct ksz_device *dev = i2c_get_clientdata(i2c);
+
+	if (dev)
+		ksz_switch_remove(dev);
+
+	return 0;
+}
+
+static void ksz9477_i2c_shutdown(struct i2c_client *i2c)
+{
+	struct ksz_device *dev = i2c_get_clientdata(i2c);
+
+	if (dev && dev->dev_ops->shutdown)
+		dev->dev_ops->shutdown(dev);
+}
+
+static const struct i2c_device_id ksz9477_i2c_id[] = {
+	{ "ksz9477-switch", 0 },
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, ksz9477_i2c_id);
+
+static const struct of_device_id ksz9477_dt_ids[] = {
+	{ .compatible = "microchip,ksz9477" },
+	{ .compatible = "microchip,ksz9897" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
+
+static struct i2c_driver ksz9477_i2c_driver = {
+	.driver = {
+		.name	= "ksz9477-switch",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ksz9477_dt_ids),
+	},
+	.probe	= ksz9477_i2c_probe,
+	.remove	= ksz9477_i2c_remove,
+	.shutdown = ksz9477_i2c_shutdown,
+	.id_table = ksz9477_i2c_id,
+};
+
+module_i2c_driver(ksz9477_i2c_driver);
+
+MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
+MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch I2C Driver");
+MODULE_LICENSE("GPL v2");