root/drivers/net/dsa/vitesse-vsc73xx-spi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vsc73xx_make_addr
  2. vsc73xx_spi_read
  3. vsc73xx_spi_write
  4. vsc73xx_spi_probe
  5. vsc73xx_spi_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* DSA driver for:
   3  * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
   4  * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
   5  * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
   6  * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
   7  *
   8  * This driver takes control of the switch chip over SPI and
   9  * configures it to route packages around when connected to a CPU port.
  10  *
  11  * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
  12  * Includes portions of code from the firmware uploader by:
  13  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
  14  */
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/of.h>
  18 #include <linux/spi/spi.h>
  19 
  20 #include "vitesse-vsc73xx.h"
  21 
  22 #define VSC73XX_CMD_SPI_MODE_READ               0
  23 #define VSC73XX_CMD_SPI_MODE_WRITE              1
  24 #define VSC73XX_CMD_SPI_MODE_SHIFT              4
  25 #define VSC73XX_CMD_SPI_BLOCK_SHIFT             5
  26 #define VSC73XX_CMD_SPI_BLOCK_MASK              0x7
  27 #define VSC73XX_CMD_SPI_SUBBLOCK_MASK           0xf
  28 
  29 /**
  30  * struct vsc73xx_spi - VSC73xx SPI state container
  31  */
  32 struct vsc73xx_spi {
  33         struct spi_device       *spi;
  34         struct mutex            lock; /* Protects SPI traffic */
  35         struct vsc73xx          vsc;
  36 };
  37 
  38 static const struct vsc73xx_ops vsc73xx_spi_ops;
  39 
  40 static u8 vsc73xx_make_addr(u8 mode, u8 block, u8 subblock)
  41 {
  42         u8 ret;
  43 
  44         ret =
  45             (block & VSC73XX_CMD_SPI_BLOCK_MASK) << VSC73XX_CMD_SPI_BLOCK_SHIFT;
  46         ret |= (mode & 1) << VSC73XX_CMD_SPI_MODE_SHIFT;
  47         ret |= subblock & VSC73XX_CMD_SPI_SUBBLOCK_MASK;
  48 
  49         return ret;
  50 }
  51 
  52 static int vsc73xx_spi_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
  53                             u32 *val)
  54 {
  55         struct vsc73xx_spi *vsc_spi = vsc->priv;
  56         struct spi_transfer t[2];
  57         struct spi_message m;
  58         u8 cmd[4];
  59         u8 buf[4];
  60         int ret;
  61 
  62         if (!vsc73xx_is_addr_valid(block, subblock))
  63                 return -EINVAL;
  64 
  65         spi_message_init(&m);
  66 
  67         memset(&t, 0, sizeof(t));
  68 
  69         t[0].tx_buf = cmd;
  70         t[0].len = sizeof(cmd);
  71         spi_message_add_tail(&t[0], &m);
  72 
  73         t[1].rx_buf = buf;
  74         t[1].len = sizeof(buf);
  75         spi_message_add_tail(&t[1], &m);
  76 
  77         cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_READ, block, subblock);
  78         cmd[1] = reg;
  79         cmd[2] = 0;
  80         cmd[3] = 0;
  81 
  82         mutex_lock(&vsc_spi->lock);
  83         ret = spi_sync(vsc_spi->spi, &m);
  84         mutex_unlock(&vsc_spi->lock);
  85 
  86         if (ret)
  87                 return ret;
  88 
  89         *val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
  90 
  91         return 0;
  92 }
  93 
  94 static int vsc73xx_spi_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
  95                              u32 val)
  96 {
  97         struct vsc73xx_spi *vsc_spi = vsc->priv;
  98         struct spi_transfer t[2];
  99         struct spi_message m;
 100         u8 cmd[2];
 101         u8 buf[4];
 102         int ret;
 103 
 104         if (!vsc73xx_is_addr_valid(block, subblock))
 105                 return -EINVAL;
 106 
 107         spi_message_init(&m);
 108 
 109         memset(&t, 0, sizeof(t));
 110 
 111         t[0].tx_buf = cmd;
 112         t[0].len = sizeof(cmd);
 113         spi_message_add_tail(&t[0], &m);
 114 
 115         t[1].tx_buf = buf;
 116         t[1].len = sizeof(buf);
 117         spi_message_add_tail(&t[1], &m);
 118 
 119         cmd[0] = vsc73xx_make_addr(VSC73XX_CMD_SPI_MODE_WRITE, block, subblock);
 120         cmd[1] = reg;
 121 
 122         buf[0] = (val >> 24) & 0xff;
 123         buf[1] = (val >> 16) & 0xff;
 124         buf[2] = (val >> 8) & 0xff;
 125         buf[3] = val & 0xff;
 126 
 127         mutex_lock(&vsc_spi->lock);
 128         ret = spi_sync(vsc_spi->spi, &m);
 129         mutex_unlock(&vsc_spi->lock);
 130 
 131         return ret;
 132 }
 133 
 134 static int vsc73xx_spi_probe(struct spi_device *spi)
 135 {
 136         struct device *dev = &spi->dev;
 137         struct vsc73xx_spi *vsc_spi;
 138         int ret;
 139 
 140         vsc_spi = devm_kzalloc(dev, sizeof(*vsc_spi), GFP_KERNEL);
 141         if (!vsc_spi)
 142                 return -ENOMEM;
 143 
 144         spi_set_drvdata(spi, vsc_spi);
 145         vsc_spi->spi = spi_dev_get(spi);
 146         vsc_spi->vsc.dev = dev;
 147         vsc_spi->vsc.priv = vsc_spi;
 148         vsc_spi->vsc.ops = &vsc73xx_spi_ops;
 149         mutex_init(&vsc_spi->lock);
 150 
 151         spi->mode = SPI_MODE_0;
 152         spi->bits_per_word = 8;
 153         ret = spi_setup(spi);
 154         if (ret < 0) {
 155                 dev_err(dev, "spi setup failed.\n");
 156                 return ret;
 157         }
 158 
 159         return vsc73xx_probe(&vsc_spi->vsc);
 160 }
 161 
 162 static int vsc73xx_spi_remove(struct spi_device *spi)
 163 {
 164         struct vsc73xx_spi *vsc_spi = spi_get_drvdata(spi);
 165 
 166         return vsc73xx_remove(&vsc_spi->vsc);
 167 }
 168 
 169 static const struct vsc73xx_ops vsc73xx_spi_ops = {
 170         .read = vsc73xx_spi_read,
 171         .write = vsc73xx_spi_write,
 172 };
 173 
 174 static const struct of_device_id vsc73xx_of_match[] = {
 175         {
 176                 .compatible = "vitesse,vsc7385",
 177         },
 178         {
 179                 .compatible = "vitesse,vsc7388",
 180         },
 181         {
 182                 .compatible = "vitesse,vsc7395",
 183         },
 184         {
 185                 .compatible = "vitesse,vsc7398",
 186         },
 187         { },
 188 };
 189 MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
 190 
 191 static struct spi_driver vsc73xx_spi_driver = {
 192         .probe = vsc73xx_spi_probe,
 193         .remove = vsc73xx_spi_remove,
 194         .driver = {
 195                 .name = "vsc73xx-spi",
 196                 .of_match_table = vsc73xx_of_match,
 197         },
 198 };
 199 module_spi_driver(vsc73xx_spi_driver);
 200 
 201 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
 202 MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 SPI driver");
 203 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */