Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* DSA driver for:
0003  * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
0004  * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
0005  * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
0006  * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
0007  *
0008  * This driver takes control of the switch chip over SPI and
0009  * configures it to route packages around when connected to a CPU port.
0010  *
0011  * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
0012  * Includes portions of code from the firmware uploader by:
0013  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
0014  */
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/spi/spi.h>
0019 
0020 #include "vitesse-vsc73xx.h"
0021 
0022 #define VSC73XX_CMD_SPI_MODE_READ       0
0023 #define VSC73XX_CMD_SPI_MODE_WRITE      1
0024 #define VSC73XX_CMD_SPI_MODE_SHIFT      4
0025 #define VSC73XX_CMD_SPI_BLOCK_SHIFT     5
0026 #define VSC73XX_CMD_SPI_BLOCK_MASK      0x7
0027 #define VSC73XX_CMD_SPI_SUBBLOCK_MASK       0xf
0028 
0029 /*
0030  * struct vsc73xx_spi - VSC73xx SPI state container
0031  */
0032 struct vsc73xx_spi {
0033     struct spi_device   *spi;
0034     struct mutex        lock; /* Protects SPI traffic */
0035     struct vsc73xx      vsc;
0036 };
0037 
0038 static const struct vsc73xx_ops vsc73xx_spi_ops;
0039 
0040 static u8 vsc73xx_make_addr(u8 mode, u8 block, u8 subblock)
0041 {
0042     u8 ret;
0043 
0044     ret =
0045         (block & VSC73XX_CMD_SPI_BLOCK_MASK) << VSC73XX_CMD_SPI_BLOCK_SHIFT;
0046     ret |= (mode & 1) << VSC73XX_CMD_SPI_MODE_SHIFT;
0047     ret |= subblock & VSC73XX_CMD_SPI_SUBBLOCK_MASK;
0048 
0049     return ret;
0050 }
0051 
0052 static int vsc73xx_spi_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
0053                 u32 *val)
0054 {
0055     struct vsc73xx_spi *vsc_spi = vsc->priv;
0056     struct spi_transfer t[2];
0057     struct spi_message m;
0058     u8 cmd[4];
0059     u8 buf[4];
0060     int ret;
0061 
0062     if (!vsc73xx_is_addr_valid(block, subblock))
0063         return -EINVAL;
0064 
0065     spi_message_init(&m);
0066 
0067     memset(&t, 0, sizeof(t));
0068 
0069     t[0].tx_buf = cmd;
0070     t[0].len = sizeof(cmd);
0071     spi_message_add_tail(&t[0], &m);
0072 
0073     t[1].rx_buf = buf;
0074     t[1].len = sizeof(buf);
0075     spi_message_add_tail(&t[1], &m);
0076 
0077     cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_READ, block, subblock);
0078     cmd[1] = reg;
0079     cmd[2] = 0;
0080     cmd[3] = 0;
0081 
0082     mutex_lock(&vsc_spi->lock);
0083     ret = spi_sync(vsc_spi->spi, &m);
0084     mutex_unlock(&vsc_spi->lock);
0085 
0086     if (ret)
0087         return ret;
0088 
0089     *val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
0090 
0091     return 0;
0092 }
0093 
0094 static int vsc73xx_spi_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
0095                  u32 val)
0096 {
0097     struct vsc73xx_spi *vsc_spi = vsc->priv;
0098     struct spi_transfer t[2];
0099     struct spi_message m;
0100     u8 cmd[2];
0101     u8 buf[4];
0102     int ret;
0103 
0104     if (!vsc73xx_is_addr_valid(block, subblock))
0105         return -EINVAL;
0106 
0107     spi_message_init(&m);
0108 
0109     memset(&t, 0, sizeof(t));
0110 
0111     t[0].tx_buf = cmd;
0112     t[0].len = sizeof(cmd);
0113     spi_message_add_tail(&t[0], &m);
0114 
0115     t[1].tx_buf = buf;
0116     t[1].len = sizeof(buf);
0117     spi_message_add_tail(&t[1], &m);
0118 
0119     cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_WRITE, block, subblock);
0120     cmd[1] = reg;
0121 
0122     buf[0] = (val >> 24) & 0xff;
0123     buf[1] = (val >> 16) & 0xff;
0124     buf[2] = (val >> 8) & 0xff;
0125     buf[3] = val & 0xff;
0126 
0127     mutex_lock(&vsc_spi->lock);
0128     ret = spi_sync(vsc_spi->spi, &m);
0129     mutex_unlock(&vsc_spi->lock);
0130 
0131     return ret;
0132 }
0133 
0134 static int vsc73xx_spi_probe(struct spi_device *spi)
0135 {
0136     struct device *dev = &spi->dev;
0137     struct vsc73xx_spi *vsc_spi;
0138     int ret;
0139 
0140     vsc_spi = devm_kzalloc(dev, sizeof(*vsc_spi), GFP_KERNEL);
0141     if (!vsc_spi)
0142         return -ENOMEM;
0143 
0144     spi_set_drvdata(spi, vsc_spi);
0145     vsc_spi->spi = spi_dev_get(spi);
0146     vsc_spi->vsc.dev = dev;
0147     vsc_spi->vsc.priv = vsc_spi;
0148     vsc_spi->vsc.ops = &vsc73xx_spi_ops;
0149     mutex_init(&vsc_spi->lock);
0150 
0151     spi->mode = SPI_MODE_0;
0152     spi->bits_per_word = 8;
0153     ret = spi_setup(spi);
0154     if (ret < 0) {
0155         dev_err(dev, "spi setup failed.\n");
0156         return ret;
0157     }
0158 
0159     return vsc73xx_probe(&vsc_spi->vsc);
0160 }
0161 
0162 static void vsc73xx_spi_remove(struct spi_device *spi)
0163 {
0164     struct vsc73xx_spi *vsc_spi = spi_get_drvdata(spi);
0165 
0166     if (!vsc_spi)
0167         return;
0168 
0169     vsc73xx_remove(&vsc_spi->vsc);
0170 
0171     spi_set_drvdata(spi, NULL);
0172 }
0173 
0174 static void vsc73xx_spi_shutdown(struct spi_device *spi)
0175 {
0176     struct vsc73xx_spi *vsc_spi = spi_get_drvdata(spi);
0177 
0178     if (!vsc_spi)
0179         return;
0180 
0181     vsc73xx_shutdown(&vsc_spi->vsc);
0182 
0183     spi_set_drvdata(spi, NULL);
0184 }
0185 
0186 static const struct vsc73xx_ops vsc73xx_spi_ops = {
0187     .read = vsc73xx_spi_read,
0188     .write = vsc73xx_spi_write,
0189 };
0190 
0191 static const struct of_device_id vsc73xx_of_match[] = {
0192     {
0193         .compatible = "vitesse,vsc7385",
0194     },
0195     {
0196         .compatible = "vitesse,vsc7388",
0197     },
0198     {
0199         .compatible = "vitesse,vsc7395",
0200     },
0201     {
0202         .compatible = "vitesse,vsc7398",
0203     },
0204     { },
0205 };
0206 MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
0207 
0208 static const struct spi_device_id vsc73xx_spi_ids[] = {
0209     { "vsc7385" },
0210     { "vsc7388" },
0211     { "vsc7395" },
0212     { "vsc7398" },
0213     { },
0214 };
0215 MODULE_DEVICE_TABLE(spi, vsc73xx_spi_ids);
0216 
0217 static struct spi_driver vsc73xx_spi_driver = {
0218     .probe = vsc73xx_spi_probe,
0219     .remove = vsc73xx_spi_remove,
0220     .shutdown = vsc73xx_spi_shutdown,
0221     .id_table = vsc73xx_spi_ids,
0222     .driver = {
0223         .name = "vsc73xx-spi",
0224         .of_match_table = vsc73xx_of_match,
0225     },
0226 };
0227 module_spi_driver(vsc73xx_spi_driver);
0228 
0229 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
0230 MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 SPI driver");
0231 MODULE_LICENSE("GPL v2");