brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · a8bfcd9 Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip KSZ8863 series register access through SMI4 *5 * Copyright (C) 2019 Pengutronix, Michael Grzeschik <kernel@pengutronix.de>6 */7 8#include <linux/mod_devicetable.h>9#include <linux/property.h>10 11#include "ksz8.h"12#include "ksz_common.h"13 14/* Serial Management Interface (SMI) uses the following frame format:15 *16 *       preamble|start|Read/Write|  PHY   |  REG  |TA|   Data bits      | Idle17 *               |frame| OP code  |address |address|  |                  |18 * read | 32x1´s | 01  |    00    | 1xRRR  | RRRRR |Z0| 00000000DDDDDDDD |  Z19 * write| 32x1´s | 01  |    00    | 0xRRR  | RRRRR |10| xxxxxxxxDDDDDDDD |  Z20 *21 */22 23#define SMI_KSZ88XX_READ_PHY	BIT(4)24 25static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,26			     void *val_buf, size_t val_len)27{28	struct ksz_device *dev = ctx;29	struct mdio_device *mdev;30	u8 reg = *(u8 *)reg_buf;31	u8 *val = val_buf;32	int i, ret = 0;33 34	mdev = dev->priv;35 36	mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);37	for (i = 0; i < val_len; i++) {38		int tmp = reg + i;39 40		ret = __mdiobus_read(mdev->bus, ((tmp & 0xE0) >> 5) |41				     SMI_KSZ88XX_READ_PHY, tmp);42		if (ret < 0)43			goto out;44 45		val[i] = ret;46	}47	ret = 0;48 49 out:50	mutex_unlock(&mdev->bus->mdio_lock);51 52	return ret;53}54 55static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)56{57	struct ksz_device *dev = ctx;58	struct mdio_device *mdev;59	int i, ret = 0;60	u32 reg;61	u8 *val;62 63	mdev = dev->priv;64 65	val = (u8 *)(data + 4);66	reg = *(u32 *)data;67 68	mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);69	for (i = 0; i < (count - 4); i++) {70		int tmp = reg + i;71 72		ret = __mdiobus_write(mdev->bus, ((tmp & 0xE0) >> 5),73				      tmp, val[i]);74		if (ret < 0)75			goto out;76	}77 78 out:79	mutex_unlock(&mdev->bus->mdio_lock);80 81	return ret;82}83 84static const struct regmap_bus regmap_smi[] = {85	{86		.read = ksz8863_mdio_read,87		.write = ksz8863_mdio_write,88	},89	{90		.read = ksz8863_mdio_read,91		.write = ksz8863_mdio_write,92		.val_format_endian_default = REGMAP_ENDIAN_BIG,93	},94	{95		.read = ksz8863_mdio_read,96		.write = ksz8863_mdio_write,97		.val_format_endian_default = REGMAP_ENDIAN_BIG,98	}99};100 101static const struct regmap_config ksz8863_regmap_config[] = {102	{103		.name = "#8",104		.reg_bits = 8,105		.pad_bits = 24,106		.val_bits = 8,107		.cache_type = REGCACHE_NONE,108		.lock = ksz_regmap_lock,109		.unlock = ksz_regmap_unlock,110		.max_register = U8_MAX,111	},112	{113		.name = "#16",114		.reg_bits = 8,115		.pad_bits = 24,116		.val_bits = 16,117		.cache_type = REGCACHE_NONE,118		.lock = ksz_regmap_lock,119		.unlock = ksz_regmap_unlock,120		.max_register = U8_MAX,121	},122	{123		.name = "#32",124		.reg_bits = 8,125		.pad_bits = 24,126		.val_bits = 32,127		.cache_type = REGCACHE_NONE,128		.lock = ksz_regmap_lock,129		.unlock = ksz_regmap_unlock,130		.max_register = U8_MAX,131	}132};133 134static int ksz8863_smi_probe(struct mdio_device *mdiodev)135{136	struct device *ddev = &mdiodev->dev;137	const struct ksz_chip_data *chip;138	struct regmap_config rc;139	struct ksz_device *dev;140	int ret;141	int i;142 143	dev = ksz_switch_alloc(&mdiodev->dev, mdiodev);144	if (!dev)145		return -ENOMEM;146 147	chip = device_get_match_data(ddev);148	if (!chip)149		return -EINVAL;150 151	for (i = 0; i < __KSZ_NUM_REGMAPS; i++) {152		rc = ksz8863_regmap_config[i];153		rc.lock_arg = &dev->regmap_mutex;154		rc.wr_table = chip->wr_table;155		rc.rd_table = chip->rd_table;156		dev->regmap[i] = devm_regmap_init(&mdiodev->dev,157						  &regmap_smi[i], dev,158						  &rc);159		if (IS_ERR(dev->regmap[i])) {160			return dev_err_probe(&mdiodev->dev,161					     PTR_ERR(dev->regmap[i]),162					     "Failed to initialize regmap%i\n",163					     ksz8863_regmap_config[i].val_bits);164		}165	}166 167	if (mdiodev->dev.platform_data)168		dev->pdata = mdiodev->dev.platform_data;169 170	ret = ksz_switch_register(dev);171 172	/* Main DSA driver may not be started yet. */173	if (ret)174		return ret;175 176	dev_set_drvdata(&mdiodev->dev, dev);177 178	return 0;179}180 181static void ksz8863_smi_remove(struct mdio_device *mdiodev)182{183	struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);184 185	if (dev)186		ksz_switch_remove(dev);187}188 189static void ksz8863_smi_shutdown(struct mdio_device *mdiodev)190{191	struct ksz_device *dev = dev_get_drvdata(&mdiodev->dev);192 193	if (dev)194		dsa_switch_shutdown(dev->ds);195 196	dev_set_drvdata(&mdiodev->dev, NULL);197}198 199static const struct of_device_id ksz8863_dt_ids[] = {200	{201		.compatible = "microchip,ksz8863",202		.data = &ksz_switch_chips[KSZ88X3]203	},204	{205		.compatible = "microchip,ksz8873",206		.data = &ksz_switch_chips[KSZ88X3]207	},208	{ },209};210MODULE_DEVICE_TABLE(of, ksz8863_dt_ids);211 212static struct mdio_driver ksz8863_driver = {213	.probe	= ksz8863_smi_probe,214	.remove	= ksz8863_smi_remove,215	.shutdown = ksz8863_smi_shutdown,216	.mdiodrv.driver = {217		.name	= "ksz8863-switch",218		.of_match_table = ksz8863_dt_ids,219	},220};221 222mdio_module_driver(ksz8863_driver);223 224MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>");225MODULE_DESCRIPTION("Microchip KSZ8863 SMI Switch driver");226MODULE_LICENSE("GPL v2");227