Commit 733933a9 authored by David S. Miller's avatar David S. Miller

Merge branch 'microchip-ksz88x3'

Oleksij Rempel says:

====================
microchip: add support for ksz88x3 driver family

changes v8:
- add Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
- fix build issue on "net: dsa: microchip: ksz8795: move register
  offsets and shifts to separate struct"

changes v7:
- Reverse christmas tree fixes
- remove IS_88X3 and use chip_id instead
- drop own tag and use DSA_TAG_PROTO_KSZ9893 instead

changes v6:
- take over this patch set
- rebase against latest netdev-next and fix regressions
- disable VLAN support for KSZ8863. KSZ8863's VLAN is not compatible to the
  KSZ8795's. So disable it for now and mainline it separately.

This series adds support for the ksz88x3 driver family to the dsa based
ksz drivers. The driver is making use of the already available ksz8795
driver and moves it to an generic driver for the ksz8 based chips which
have similar functions but an totaly different register layout.

The mainlining discussion history of this branch:
v1: https://lore.kernel.org/netdev/20191107110030.25199-1-m.grzeschik@pengutronix.de/
v2: https://lore.kernel.org/netdev/20191218200831.13796-1-m.grzeschik@pengutronix.de/
v3: https://lore.kernel.org/netdev/20200508154343.6074-1-m.grzeschik@pengutronix.de/
v4: https://lore.kernel.org/netdev/20200803054442.20089-1-m.grzeschik@pengutronix.de/
v5: https://lore.kernel.org/netdev/20201207125627.30843-1-m.grzeschik@pengutronix.de/
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents aae0fdac 61b40598
......@@ -21,6 +21,8 @@ properties:
- microchip,ksz8765
- microchip,ksz8794
- microchip,ksz8795
- microchip,ksz8863
- microchip,ksz8873
- microchip,ksz9477
- microchip,ksz9897
- microchip,ksz9896
......
......@@ -2,6 +2,7 @@ MDIO on GPIOs
Currently defined compatibles:
- virtual,gpio-mdio
- microchip,mdio-smi0
MDC and MDIO lines connected to GPIO controllers are listed in the
gpios property as described in section VIII.1 in the following order:
......
......@@ -29,7 +29,7 @@ menuconfig NET_DSA_MICROCHIP_KSZ8795
depends on NET_DSA
select NET_DSA_MICROCHIP_KSZ_COMMON
help
This driver adds support for Microchip KSZ8795 switch chips.
This driver adds support for Microchip KSZ8795/KSZ88X3 switch chips.
config NET_DSA_MICROCHIP_KSZ8795_SPI
tristate "KSZ8795 series SPI connected switch driver"
......@@ -40,3 +40,11 @@ config NET_DSA_MICROCHIP_KSZ8795_SPI
It is required to use the KSZ8795 switch driver as the only access
is through SPI.
config NET_DSA_MICROCHIP_KSZ8863_SMI
tristate "KSZ series SMI connected switch driver"
depends on NET_DSA_MICROCHIP_KSZ8795
select MDIO_BITBANG
help
Select to enable support for registering switches configured through
Microchip SMI. It supports the KSZ8863 and KSZ8873 switch.
......@@ -5,3 +5,4 @@ obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C) += ksz9477_i2c.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI) += ksz9477_spi.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795) += ksz8795.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI) += ksz8795_spi.o
obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI) += ksz8863_smi.o
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Microchip KSZ8XXX series register access
*
* Copyright (C) 2020 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
*/
#ifndef __KSZ8XXX_H
#define __KSZ8XXX_H
#include <linux/kernel.h>
enum ksz_regs {
REG_IND_CTRL_0,
REG_IND_DATA_8,
REG_IND_DATA_CHECK,
REG_IND_DATA_HI,
REG_IND_DATA_LO,
REG_IND_MIB_CHECK,
P_FORCE_CTRL,
P_LINK_STATUS,
P_LOCAL_CTRL,
P_NEG_RESTART_CTRL,
P_REMOTE_STATUS,
P_SPEED_STATUS,
S_TAIL_TAG_CTRL,
};
enum ksz_masks {
PORT_802_1P_REMAPPING,
SW_TAIL_TAG_ENABLE,
MIB_COUNTER_OVERFLOW,
MIB_COUNTER_VALID,
VLAN_TABLE_FID,
VLAN_TABLE_MEMBERSHIP,
VLAN_TABLE_VALID,
STATIC_MAC_TABLE_VALID,
STATIC_MAC_TABLE_USE_FID,
STATIC_MAC_TABLE_FID,
STATIC_MAC_TABLE_OVERRIDE,
STATIC_MAC_TABLE_FWD_PORTS,
DYNAMIC_MAC_TABLE_ENTRIES_H,
DYNAMIC_MAC_TABLE_MAC_EMPTY,
DYNAMIC_MAC_TABLE_NOT_READY,
DYNAMIC_MAC_TABLE_ENTRIES,
DYNAMIC_MAC_TABLE_FID,
DYNAMIC_MAC_TABLE_SRC_PORT,
DYNAMIC_MAC_TABLE_TIMESTAMP,
};
enum ksz_shifts {
VLAN_TABLE_MEMBERSHIP_S,
VLAN_TABLE,
STATIC_MAC_FWD_PORTS,
STATIC_MAC_FID,
DYNAMIC_MAC_ENTRIES_H,
DYNAMIC_MAC_ENTRIES,
DYNAMIC_MAC_FID,
DYNAMIC_MAC_TIMESTAMP,
DYNAMIC_MAC_SRC_PORT,
};
struct ksz8 {
const u8 *regs;
const u32 *masks;
const u8 *shifts;
void *priv;
};
#endif
This diff is collapsed.
......@@ -16,7 +16,8 @@
#define REG_CHIP_ID0 0x00
#define FAMILY_ID 0x87
#define KSZ87_FAMILY_ID 0x87
#define KSZ88_FAMILY_ID 0x88
#define REG_CHIP_ID1 0x01
......@@ -28,6 +29,12 @@
#define CHIP_ID_94 0x60
#define CHIP_ID_95 0x90
#define CHIP_ID_63 0x30
#define KSZ8863_REG_SW_RESET 0x43
#define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4)
#define KSZ8863_PCS_RESET BIT(0)
#define REG_SW_CTRL_0 0x02
......@@ -98,7 +105,6 @@
#define REG_SW_CTRL_10 0x0C
#define SW_TAIL_TAG_ENABLE BIT(1)
#define SW_PASS_PAUSE BIT(0)
#define REG_SW_CTRL_11 0x0D
......@@ -150,7 +156,6 @@
#define REG_PORT_4_CTRL_2 0x42
#define REG_PORT_5_CTRL_2 0x52
#define PORT_802_1P_REMAPPING BIT(7)
#define PORT_INGRESS_FILTER BIT(6)
#define PORT_DISCARD_NON_VID BIT(5)
#define PORT_FORCE_FLOW_CTRL BIT(4)
......@@ -269,6 +274,7 @@
#define REG_PORT_3_CTRL_9 0x3C
#define REG_PORT_4_CTRL_9 0x4C
#define PORT_AUTO_NEG_ENABLE BIT(7)
#define PORT_AUTO_NEG_DISABLE BIT(7)
#define PORT_FORCE_100_MBIT BIT(6)
#define PORT_FORCE_FULL_DUPLEX BIT(5)
......@@ -319,14 +325,12 @@
#define REG_PORT_CTRL_5 0x05
#define REG_PORT_CTRL_7 0x07
#define REG_PORT_STATUS_0 0x08
#define REG_PORT_STATUS_1 0x09
#define REG_PORT_LINK_MD_CTRL 0x0A
#define REG_PORT_LINK_MD_RESULT 0x0B
#define REG_PORT_CTRL_9 0x0C
#define REG_PORT_CTRL_10 0x0D
#define REG_PORT_STATUS_2 0x0E
#define REG_PORT_STATUS_3 0x0F
#define REG_PORT_CTRL_12 0xA0
......@@ -356,8 +360,6 @@
#define REG_SW_MAC_ADDR_4 0x6C
#define REG_SW_MAC_ADDR_5 0x6D
#define REG_IND_CTRL_0 0x6E
#define TABLE_EXT_SELECT_S 5
#define TABLE_EEE_V 1
#define TABLE_ACL_V 2
......@@ -383,23 +385,13 @@
#define TABLE_ENTRY_MASK 0x03FF
#define TABLE_EXT_ENTRY_MASK 0x0FFF
#define REG_IND_DATA_8 0x70
#define REG_IND_DATA_7 0x71
#define REG_IND_DATA_6 0x72
#define REG_IND_DATA_5 0x73
#define REG_IND_DATA_4 0x74
#define REG_IND_DATA_3 0x75
#define REG_IND_DATA_2 0x76
#define REG_IND_DATA_1 0x77
#define REG_IND_DATA_0 0x78
#define REG_IND_DATA_PME_EEE_ACL 0xA0
#define REG_IND_DATA_CHECK REG_IND_DATA_6
#define REG_IND_MIB_CHECK REG_IND_DATA_4
#define REG_IND_DATA_HI REG_IND_DATA_7
#define REG_IND_DATA_LO REG_IND_DATA_3
#define REG_INT_STATUS 0x7C
#define REG_INT_ENABLE 0x7D
......@@ -816,6 +808,7 @@
#define KSZ8795_ID_HI 0x0022
#define KSZ8795_ID_LO 0x1550
#define KSZ8863_ID_LO 0x1430
#define KSZ8795_SW_ID 0x8795
......@@ -846,7 +839,7 @@
#define KS_PRIO_IN_REG 4
#define KSZ8795_COUNTER_NUM 0x20
#define MIB_COUNTER_NUM 0x20
/* Common names used by other drivers */
......@@ -856,12 +849,6 @@
#define P_MIRROR_CTRL REG_PORT_CTRL_1
#define P_802_1P_CTRL REG_PORT_CTRL_2
#define P_STP_CTRL REG_PORT_CTRL_2
#define P_LOCAL_CTRL REG_PORT_CTRL_7
#define P_REMOTE_STATUS REG_PORT_STATUS_0
#define P_FORCE_CTRL REG_PORT_CTRL_9
#define P_NEG_RESTART_CTRL REG_PORT_CTRL_10
#define P_SPEED_STATUS REG_PORT_STATUS_1
#define P_LINK_STATUS REG_PORT_STATUS_2
#define P_PASS_ALL_CTRL REG_PORT_CTRL_12
#define P_INS_SRC_PVID_CTRL REG_PORT_CTRL_12
#define P_DROP_TAG_CTRL REG_PORT_CTRL_13
......@@ -876,7 +863,6 @@
#define S_MIRROR_CTRL REG_SW_CTRL_3
#define S_REPLACE_VID_CTRL REG_SW_CTRL_4
#define S_PASS_PAUSE_CTRL REG_SW_CTRL_10
#define S_TAIL_TAG_CTRL REG_SW_CTRL_10
#define S_802_1P_PRIO_CTRL REG_SW_CTRL_12
#define S_TOS_PRIO_CTRL REG_TOS_PRIO_CTRL_0
#define S_IPV6_MLD_CTRL REG_SW_CTRL_21
......@@ -889,65 +875,6 @@
/* 148,800 frames * 67 ms / 100 */
#define BROADCAST_STORM_VALUE 9969
/**
* STATIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
* STATIC_MAC_TABLE_FWD_PORTS 00-001F0000-00000000
* STATIC_MAC_TABLE_VALID 00-00200000-00000000
* STATIC_MAC_TABLE_OVERRIDE 00-00400000-00000000
* STATIC_MAC_TABLE_USE_FID 00-00800000-00000000
* STATIC_MAC_TABLE_FID 00-7F000000-00000000
*/
#define STATIC_MAC_TABLE_ADDR 0x0000FFFF
#define STATIC_MAC_TABLE_FWD_PORTS 0x001F0000
#define STATIC_MAC_TABLE_VALID 0x00200000
#define STATIC_MAC_TABLE_OVERRIDE 0x00400000
#define STATIC_MAC_TABLE_USE_FID 0x00800000
#define STATIC_MAC_TABLE_FID 0x7F000000
#define STATIC_MAC_FWD_PORTS_S 16
#define STATIC_MAC_FID_S 24
/**
* VLAN_TABLE_FID 00-007F007F-007F007F
* VLAN_TABLE_MEMBERSHIP 00-0F800F80-0F800F80
* VLAN_TABLE_VALID 00-10001000-10001000
*/
#define VLAN_TABLE_FID 0x007F
#define VLAN_TABLE_MEMBERSHIP 0x0F80
#define VLAN_TABLE_VALID 0x1000
#define VLAN_TABLE_MEMBERSHIP_S 7
#define VLAN_TABLE_S 16
/**
* DYNAMIC_MAC_TABLE_ADDR 00-0000FFFF-FFFFFFFF
* DYNAMIC_MAC_TABLE_FID 00-007F0000-00000000
* DYNAMIC_MAC_TABLE_NOT_READY 00-00800000-00000000
* DYNAMIC_MAC_TABLE_SRC_PORT 00-07000000-00000000
* DYNAMIC_MAC_TABLE_TIMESTAMP 00-18000000-00000000
* DYNAMIC_MAC_TABLE_ENTRIES 7F-E0000000-00000000
* DYNAMIC_MAC_TABLE_MAC_EMPTY 80-00000000-00000000
*/
#define DYNAMIC_MAC_TABLE_ADDR 0x0000FFFF
#define DYNAMIC_MAC_TABLE_FID 0x007F0000
#define DYNAMIC_MAC_TABLE_SRC_PORT 0x07000000
#define DYNAMIC_MAC_TABLE_TIMESTAMP 0x18000000
#define DYNAMIC_MAC_TABLE_ENTRIES 0xE0000000
#define DYNAMIC_MAC_TABLE_NOT_READY 0x80
#define DYNAMIC_MAC_TABLE_ENTRIES_H 0x7F
#define DYNAMIC_MAC_TABLE_MAC_EMPTY 0x80
#define DYNAMIC_MAC_FID_S 16
#define DYNAMIC_MAC_SRC_PORT_S 24
#define DYNAMIC_MAC_TIMESTAMP_S 27
#define DYNAMIC_MAC_ENTRIES_S 29
#define DYNAMIC_MAC_ENTRIES_H_S 3
/**
* MIB_COUNTER_VALUE 00-00000000-3FFFFFFF
* MIB_TOTAL_BYTES 00-0000000F-FFFFFFFF
......@@ -956,31 +883,15 @@
* MIB_COUNTER_OVERFLOW 00-00000040-00000000
*/
#define MIB_COUNTER_OVERFLOW BIT(6)
#define MIB_COUNTER_VALID BIT(5)
#define MIB_COUNTER_VALUE 0x3FFFFFFF
#define KS_MIB_TOTAL_RX_0 0x100
#define KS_MIB_TOTAL_TX_0 0x101
#define KS_MIB_PACKET_DROPPED_RX_0 0x102
#define KS_MIB_PACKET_DROPPED_TX_0 0x103
#define KS_MIB_TOTAL_RX_1 0x104
#define KS_MIB_TOTAL_TX_1 0x105
#define KS_MIB_PACKET_DROPPED_TX_1 0x106
#define KS_MIB_PACKET_DROPPED_RX_1 0x107
#define KS_MIB_TOTAL_RX_2 0x108
#define KS_MIB_TOTAL_TX_2 0x109
#define KS_MIB_PACKET_DROPPED_TX_2 0x10A
#define KS_MIB_PACKET_DROPPED_RX_2 0x10B
#define KS_MIB_TOTAL_RX_3 0x10C
#define KS_MIB_TOTAL_TX_3 0x10D
#define KS_MIB_PACKET_DROPPED_TX_3 0x10E
#define KS_MIB_PACKET_DROPPED_RX_3 0x10F
#define KS_MIB_TOTAL_RX_4 0x110
#define KS_MIB_TOTAL_TX_4 0x111
#define KS_MIB_PACKET_DROPPED_TX_4 0x112
#define KS_MIB_PACKET_DROPPED_RX_4 0x113
#define KSZ8795_MIB_TOTAL_RX_0 0x100
#define KSZ8795_MIB_TOTAL_TX_0 0x101
#define KSZ8795_MIB_TOTAL_RX_1 0x104
#define KSZ8795_MIB_TOTAL_TX_1 0x105
#define KSZ8863_MIB_PACKET_DROPPED_TX_0 0x100
#define KSZ8863_MIB_PACKET_DROPPED_RX_0 0x105
#define MIB_PACKET_DROPPED 0x0000FFFF
......
......@@ -14,34 +14,52 @@
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ksz8.h"
#include "ksz_common.h"
#define SPI_ADDR_SHIFT 12
#define SPI_ADDR_ALIGN 3
#define SPI_TURNAROUND_SHIFT 1
#define KSZ8795_SPI_ADDR_SHIFT 12
#define KSZ8795_SPI_ADDR_ALIGN 3
#define KSZ8795_SPI_TURNAROUND_SHIFT 1
KSZ_REGMAP_TABLE(ksz8795, 16, SPI_ADDR_SHIFT,
SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
#define KSZ8863_SPI_ADDR_SHIFT 8
#define KSZ8863_SPI_ADDR_ALIGN 8
#define KSZ8863_SPI_TURNAROUND_SHIFT 0
KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
static int ksz8795_spi_probe(struct spi_device *spi)
{
const struct regmap_config *regmap_config;
struct device *ddev = &spi->dev;
struct regmap_config rc;
struct ksz_device *dev;
int i, ret;
struct ksz8 *ksz8;
int i, ret = 0;
dev = ksz_switch_alloc(&spi->dev, spi);
ksz8 = devm_kzalloc(&spi->dev, sizeof(struct ksz8), GFP_KERNEL);
ksz8->priv = spi;
dev = ksz_switch_alloc(&spi->dev, ksz8);
if (!dev)
return -ENOMEM;
regmap_config = device_get_match_data(ddev);
if (!regmap_config)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
rc = ksz8795_regmap_config[i];
rc = regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&spi->dev,
"Failed to initialize regmap%i: %d\n",
ksz8795_regmap_config[i].val_bits, ret);
regmap_config[i].val_bits, ret);
return ret;
}
}
......@@ -55,7 +73,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
if (ret)
return ret;
ret = ksz8795_switch_register(dev);
ret = ksz8_switch_register(dev);
/* Main DSA driver may not be started yet. */
if (ret)
......@@ -85,9 +103,11 @@ static void ksz8795_spi_shutdown(struct spi_device *spi)
}
static const struct of_device_id ksz8795_dt_ids[] = {
{ .compatible = "microchip,ksz8765" },
{ .compatible = "microchip,ksz8794" },
{ .compatible = "microchip,ksz8795" },
{ .compatible = "microchip,ksz8765", .data = &ksz8795_regmap_config },
{ .compatible = "microchip,ksz8794", .data = &ksz8795_regmap_config },
{ .compatible = "microchip,ksz8795", .data = &ksz8795_regmap_config },
{ .compatible = "microchip,ksz8863", .data = &ksz8863_regmap_config },
{ .compatible = "microchip,ksz8873", .data = &ksz8863_regmap_config },
{},
};
MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Microchip KSZ8863 series register access through SMI
*
* Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>
*/
#include "ksz8.h"
#include "ksz_common.h"
/* Serial Management Interface (SMI) uses the following frame format:
*
* preamble|start|Read/Write| PHY | REG |TA| Data bits | Idle
* |frame| OP code |address |address| | |
* read | 32x1´s | 01 | 00 | 1xRRR | RRRRR |Z0| 00000000DDDDDDDD | Z
* write| 32x1´s | 01 | 00 | 0xRRR | RRRRR |10| xxxxxxxxDDDDDDDD | Z
*
*/
#define SMI_KSZ88XX_READ_PHY BIT(4)
static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
void *val_buf, size_t val_len)
{
struct ksz_device *dev = ctx;
struct mdio_device *mdev;
u8 reg = *(u8 *)reg_buf;
u8 *val = val_buf;
struct ksz8 *ksz8;
int i, ret = 0;
ksz8 = dev->priv;
mdev = ksz8->priv;
mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
for (i = 0; i < val_len; i++) {
int tmp = reg + i;
ret = __mdiobus_read(mdev->bus, ((tmp & 0xE0) >> 5) |
SMI_KSZ88XX_READ_PHY, tmp);
if (ret < 0)
goto out;
val[i] = ret;
}
ret = 0;
out:
mutex_unlock(&mdev->bus->mdio_lock);
return ret;
}
static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)
{
struct ksz_device *dev = ctx;
struct mdio_device *mdev;
struct ksz8 *ksz8;
int i, ret = 0;
u32 reg;
u8 *val;
ksz8 = dev->priv;
mdev = ksz8->priv;
val = (u8 *)(data + 4);
reg = *(u32 *)data;
mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
for (i = 0; i < (count - 4); i++) {
int tmp = reg + i;
ret = __mdiobus_write(mdev->bus, ((tmp & 0xE0) >> 5),
tmp, val[i]);
if (ret < 0)
goto out;
}
out:
mutex_unlock(&mdev->bus->mdio_lock);
return ret;
}
static const struct regmap_bus regmap_smi[] = {
{
.read = ksz8863_mdio_read,
.write = ksz8863_mdio_write,
.max_raw_read = 1,
.max_raw_write = 1,
},
{
.read = ksz8863_mdio_read,
.write = ksz8863_mdio_write,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
.max_raw_read = 2,
.max_raw_write = 2,
},
{
.read = ksz8863_mdio_read,
.write = ksz8863_mdio_write,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
.max_raw_read = 4,
.max_raw_write = 4,
}
};
static const struct regmap_config ksz8863_regmap_config[] = {
{
.name = "#8",
.reg_bits = 8,
.pad_bits = 24,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
.use_single_read = 1,
.lock = ksz_regmap_lock,
.unlock = ksz_regmap_unlock,
},
{
.name = "#16",
.reg_bits = 8,
.pad_bits = 24,
.val_bits = 16,
.cache_type = REGCACHE_NONE,
.use_single_read = 1,
.lock = ksz_regmap_lock,
.unlock = ksz_regmap_unlock,
},
{
.name = "#32",
.reg_bits = 8,
.pad_bits = 24,
.val_bits = 32,
.cache_type = REGCACHE_NONE,
.use_single_read = 1,
.lock = ksz_regmap_lock,
.unlock = ksz_regmap_unlock,
}
};
static int ksz8863_smi_probe(struct mdio_device *mdiodev)
{
struct regmap_config rc;
struct ksz_device *dev;
struct ksz8 *ksz8;
int ret;
int i;
ksz8 = devm_kzalloc(&mdiodev->dev, sizeof(struct ksz8), GFP_KERNEL);
ksz8->priv = mdiodev;
dev = ksz_switch_alloc(&mdiodev->dev, ksz8);
if (!dev)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(ksz8863_regmap_config); i++) {
rc = ksz8863_regmap_config[i];
rc.lock_arg = &dev->regmap_mutex;
dev->regmap[i] = devm_regmap_init(&mdiodev->dev,
&regmap_smi[i], dev,
&rc);
if (IS_ERR(dev->regmap[i])) {
ret = PTR_ERR(dev->regmap[i]);
dev_err(&mdiodev->dev,
"Failed to initialize regmap%i: %d\n",
ksz8863_regmap_config[i].val_bits, ret);
return ret;
}
}
if (mdiodev->dev.platform_data)
dev->pdata = mdiodev->dev.platform_data;
ret = ksz8_switch_register(dev);
/* Main DSA driver may not be started yet. */
if (ret)
return ret;
dev_set_drvdata(&mdiodev->dev, dev);
return 0;
}
static void ksz8863_smi_remove(struct mdio_device *mdiodev)
{
struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);
if (dev)
ksz_switch_remove(dev);
}
static const struct of_device_id ksz8863_dt_ids[] = {
{ .compatible = "microchip,ksz8863" },
{ .compatible = "microchip,ksz8873" },
{ },
};
MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);
static struct mdio_driver ksz8863_driver = {
.probe = ksz8863_smi_probe,
.remove = ksz8863_smi_remove,
.mdiodrv.driver = {
.name = "ksz8863-switch",
.of_match_table = ksz8863_dt_ids,
},
};
mdio_module_driver(ksz8863_driver);
MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");
MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver");
MODULE_LICENSE("GPL v2");
......@@ -71,6 +71,7 @@ struct ksz_device {
int port_cnt;
int reg_mib_cnt;
int mib_cnt;
const struct mib_names *mib_names;
phy_interface_t compat_interface;
u32 regs_size;
bool phy_errata_9477;
......@@ -142,7 +143,7 @@ int ksz_switch_register(struct ksz_device *dev,
const struct ksz_dev_ops *ops);
void ksz_switch_remove(struct ksz_device *dev);
int ksz8795_switch_register(struct ksz_device *dev);
int ksz8_switch_register(struct ksz_device *dev);
int ksz9477_switch_register(struct ksz_device *dev);
void ksz_update_port_member(struct ksz_device *dev, int port);
......
......@@ -158,7 +158,7 @@ int mdiobb_read(struct mii_bus *bus, int phy, int reg)
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
} else
mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg);
ctrl->ops->set_mdio_dir(ctrl, 0);
......@@ -190,7 +190,7 @@ int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
reg = mdiobb_cmd_addr(ctrl, phy, reg);
mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
} else
mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg);
/* send the turnaround (10) */
mdiobb_send_bit(ctrl, 1);
......@@ -217,6 +217,10 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
bus->read = mdiobb_read;
bus->write = mdiobb_write;
bus->priv = ctrl;
if (!ctrl->override_op_c22) {
ctrl->op_c22_read = MDIO_READ;
ctrl->op_c22_write = MDIO_WRITE;
}
return bus;
}
......
......@@ -132,6 +132,13 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
}
if (dev->of_node &&
of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) {
bitbang->ctrl.op_c22_read = 0;
bitbang->ctrl.op_c22_write = 0;
bitbang->ctrl.override_op_c22 = 1;
}
dev_set_drvdata(dev, new_bus);
return new_bus;
......@@ -196,6 +203,7 @@ static int mdio_gpio_remove(struct platform_device *pdev)
static const struct of_device_id mdio_gpio_of_match[] = {
{ .compatible = "virtual,mdio-gpio", },
{ .compatible = "microchip,mdio-smi0" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
......
......@@ -33,6 +33,9 @@ struct mdiobb_ops {
struct mdiobb_ctrl {
const struct mdiobb_ops *ops;
unsigned int override_op_c22;
u8 op_c22_read;
u8 op_c22_write;
};
int mdiobb_read(struct mii_bus *bus, int phy, int reg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment