All of lore.kernel.org
 help / color / mirror / Atom feed
From: <Tristram.Ha@microchip.com>
To: Sergio Paracuellos <sergio.paracuellos@gmail.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Florian Fainelli <f.fainelli@gmail.com>,
	Pavel Machek <pavel@ucw.cz>, Marek Vasut <marex@denx.de>,
	Dan Carpenter <dan.carpenter@oracle.com>
Cc: Tristram Ha <Tristram.Ha@microchip.com>,
	<vivien.didelot@savoirfairelinux.com>,
	<UNGLinuxDriver@microchip.com>, <netdev@vger.kernel.org>
Subject: [PATCH v1 net-next] net: dsa: microchip: add KSZ9477 I2C driver
Date: Tue, 18 Dec 2018 19:41:37 -0800	[thread overview]
Message-ID: <1545190897-22622-1-git-send-email-Tristram.Ha@microchip.com> (raw)

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>
---
v1
- Return error code from i2c_transfer
- Change GPL license
- Change author

 drivers/net/dsa/microchip/Kconfig       |   6 +
 drivers/net/dsa/microchip/Makefile      |   1 +
 drivers/net/dsa/microchip/ksz9477_i2c.c | 196 ++++++++++++++++++++++++++++++++
 drivers/net/dsa/microchip/ksz_i2c.h     |  69 +++++++++++
 4 files changed, 272 insertions(+)
 create mode 100644 drivers/net/dsa/microchip/ksz9477_i2c.c
 create mode 100644 drivers/net/dsa/microchip/ksz_i2c.h

diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index bea29fd..fd94441 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -9,6 +9,12 @@ 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
+	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..29511e9
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz9477_i2c.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip KSZ9477 series register access through I2C
+ *
+ * Copyright (C) 2018 Microchip Technology Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "ksz_priv.h"
+#include "ksz_i2c.h"
+
+/* Enough to read all switch port registers. */
+#define I2C_TX_BUF_LEN			0x100
+
+static int ksz9477_i2c_read_reg(struct i2c_client *i2c, u32 reg, u8 *val,
+				unsigned int len)
+{
+	struct i2c_msg msg[2];
+	int ret;
+
+	val[0] = (u8)(reg >> 8);
+	val[1] = (u8)reg;
+
+	msg[0].addr = i2c->addr;
+	msg[0].flags = 0;
+	msg[0].len = 2;
+	msg[0].buf = val;
+
+	msg[1].addr = i2c->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = &val[2];
+
+	ret = i2c_transfer(i2c->adapter, msg, 2);
+	if (ret == 2)
+		ret = 0;
+	return ret;
+}
+
+static int ksz9477_i2c_write_reg(struct i2c_client *i2c, u32 reg, u8 *val,
+				 unsigned int len)
+{
+	struct i2c_msg msg;
+	int ret;
+
+	val[0] = (u8)(reg >> 8);
+	val[1] = (u8)reg;
+
+	msg.addr = i2c->addr;
+	msg.flags = 0;
+	msg.len = 2 + len;
+	msg.buf = val;
+
+	ret = i2c_transfer(i2c->adapter, &msg, 1);
+	if (ret == 1)
+		ret = 0;
+	return ret;
+}
+
+static int ksz_i2c_read(struct ksz_device *dev, u32 reg, u8 *data,
+			unsigned int len)
+{
+	struct i2c_client *i2c = dev->priv;
+	int ret;
+
+	ret = ksz9477_i2c_read_reg(i2c, reg, dev->txbuf, len);
+	if (!ret)
+		memcpy(data, &dev->txbuf[2], len);
+	return ret;
+}
+
+static int ksz_i2c_write(struct ksz_device *dev, u32 reg, void *data,
+			 unsigned int len)
+{
+	struct i2c_client *i2c = dev->priv;
+
+	if (len > I2C_TX_BUF_LEN)
+		len = I2C_TX_BUF_LEN;
+	memcpy(&dev->txbuf[2], data, len);
+	return ksz9477_i2c_write_reg(i2c, reg, dev->txbuf, len);
+}
+
+static int ksz_i2c_read24(struct ksz_device *dev, u32 reg, u32 *val)
+{
+	int ret;
+
+	*val = 0;
+	ret = ksz_i2c_read(dev, reg, (u8 *)val, 3);
+	if (!ret) {
+		*val = be32_to_cpu(*val);
+		/* convert to 24bit */
+		*val >>= 8;
+	}
+
+	return ret;
+}
+
+static int ksz_i2c_write24(struct ksz_device *dev, u32 reg, u32 value)
+{
+	/* make it to big endian 24bit from MSB */
+	value <<= 8;
+	value = cpu_to_be32(value);
+	return ksz_i2c_write(dev, reg, &value, 3);
+}
+
+static const struct ksz_io_ops ksz9477_i2c_ops = {
+	.read8 = ksz_i2c_read8,
+	.read16 = ksz_i2c_read16,
+	.read24 = ksz_i2c_read24,
+	.read32 = ksz_i2c_read32,
+	.write8 = ksz_i2c_write8,
+	.write16 = ksz_i2c_write16,
+	.write24 = ksz_i2c_write24,
+	.write32 = ksz_i2c_write32,
+	.get = ksz_i2c_get,
+	.set = ksz_i2c_set,
+};
+
+static int ksz9477_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *i2c_id)
+{
+	struct ksz_device *dev;
+	int ret;
+
+	dev = ksz_switch_alloc(&i2c->dev, &ksz9477_i2c_ops, i2c);
+	if (!dev)
+		return -ENOMEM;
+
+	if (i2c->dev.platform_data)
+		dev->pdata = i2c->dev.platform_data;
+
+	dev->txbuf = devm_kzalloc(dev->dev, 2 + I2C_TX_BUF_LEN, GFP_KERNEL);
+
+	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 access Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/microchip/ksz_i2c.h b/drivers/net/dsa/microchip/ksz_i2c.h
new file mode 100644
index 0000000..b9af0a8
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_i2c.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Microchip KSZ series I2C access common header
+ *
+ * Copyright (C) 2018 Microchip Technology Inc.
+ *	Tristram Ha <Tristram.Ha@microchip.com>
+ */
+
+#ifndef __KSZ_I2C_H
+#define __KSZ_I2C_H
+
+/* Chip dependent I2C access */
+static int ksz_i2c_read(struct ksz_device *dev, u32 reg, u8 *data,
+			unsigned int len);
+static int ksz_i2c_write(struct ksz_device *dev, u32 reg, void *data,
+			 unsigned int len);
+
+static int ksz_i2c_read8(struct ksz_device *dev, u32 reg, u8 *val)
+{
+	return ksz_i2c_read(dev, reg, val, 1);
+}
+
+static int ksz_i2c_read16(struct ksz_device *dev, u32 reg, u16 *val)
+{
+	int ret = ksz_i2c_read(dev, reg, (u8 *)val, 2);
+
+	if (!ret)
+		*val = be16_to_cpu(*val);
+
+	return ret;
+}
+
+static int ksz_i2c_read32(struct ksz_device *dev, u32 reg, u32 *val)
+{
+	int ret = ksz_i2c_read(dev, reg, (u8 *)val, 4);
+
+	if (!ret)
+		*val = be32_to_cpu(*val);
+
+	return ret;
+}
+
+static int ksz_i2c_write8(struct ksz_device *dev, u32 reg, u8 value)
+{
+	return ksz_i2c_write(dev, reg, &value, 1);
+}
+
+static int ksz_i2c_write16(struct ksz_device *dev, u32 reg, u16 value)
+{
+	value = cpu_to_be16(value);
+	return ksz_i2c_write(dev, reg, &value, 2);
+}
+
+static int ksz_i2c_write32(struct ksz_device *dev, u32 reg, u32 value)
+{
+	value = cpu_to_be32(value);
+	return ksz_i2c_write(dev, reg, &value, 4);
+}
+
+static int ksz_i2c_get(struct ksz_device *dev, u32 reg, void *data, size_t len)
+{
+	return ksz_i2c_read(dev, reg, data, len);
+}
+
+static int ksz_i2c_set(struct ksz_device *dev, u32 reg, void *data, size_t len)
+{
+	return ksz_i2c_write(dev, reg, data, len);
+}
+
+#endif
-- 
1.9.1

             reply	other threads:[~2018-12-19  3:41 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-19  3:41 Tristram.Ha [this message]
2018-12-19  4:31 ` [PATCH v1 net-next] net: dsa: microchip: add KSZ9477 I2C driver Woojung.Huh
2018-12-19 22:59   ` Tristram.Ha
2018-12-19 23:19     ` Woojung.Huh
2018-12-19  8:09 ` Marek Vasut
2018-12-19 22:30   ` Tristram.Ha
2018-12-19 23:11     ` Marek Vasut
2018-12-19 23:31       ` Marek Vasut
2018-12-20  1:10         ` Marek Vasut
2018-12-21  0:48           ` Tristram.Ha
2018-12-21  2:03             ` Marek Vasut
2018-12-19 10:05 ` Jiri Pirko
2018-12-19 16:08   ` Pavel Machek
2018-12-19 16:15     ` Jiri Pirko
2018-12-19 17:22       ` Pavel Machek
2018-12-19 17:24         ` Marek Vasut
2018-12-19 22:50           ` Tristram.Ha
2018-12-19 23:12             ` Marek Vasut
2018-12-21  9:29             ` Dan Carpenter
2018-12-21 12:14               ` Marek Vasut
2018-12-21 12:23                 ` Dan Carpenter
2018-12-21 12:39                   ` Marek Vasut
2019-01-09 16:05             ` Pavel Machek
2019-01-09 16:15               ` Marek Vasut
2018-12-19 16:45     ` David Miller
2019-01-10  8:15 ` Sergio Paracuellos

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=1545190897-22622-1-git-send-email-Tristram.Ha@microchip.com \
    --to=tristram.ha@microchip.com \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=andrew@lunn.ch \
    --cc=dan.carpenter@oracle.com \
    --cc=f.fainelli@gmail.com \
    --cc=marex@denx.de \
    --cc=netdev@vger.kernel.org \
    --cc=pavel@ucw.cz \
    --cc=sergio.paracuellos@gmail.com \
    --cc=vivien.didelot@savoirfairelinux.com \
    /path/to/YOUR_REPLY

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

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