linux/drivers/net/dsa/microchip/ksz8795_spi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Microchip KSZ8795 series register access through SPI
   4 *
   5 * Copyright (C) 2017 Microchip Technology Inc.
   6 *      Tristram Ha <Tristram.Ha@microchip.com>
   7 */
   8
   9#include <asm/unaligned.h>
  10
  11#include <linux/delay.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/regmap.h>
  15#include <linux/spi/spi.h>
  16
  17#include "ksz8.h"
  18#include "ksz_common.h"
  19
  20#define KSZ8795_SPI_ADDR_SHIFT                  12
  21#define KSZ8795_SPI_ADDR_ALIGN                  3
  22#define KSZ8795_SPI_TURNAROUND_SHIFT            1
  23
  24#define KSZ8863_SPI_ADDR_SHIFT                  8
  25#define KSZ8863_SPI_ADDR_ALIGN                  8
  26#define KSZ8863_SPI_TURNAROUND_SHIFT            0
  27
  28KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
  29                 KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
  30
  31KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
  32                 KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
  33
  34static int ksz8795_spi_probe(struct spi_device *spi)
  35{
  36        const struct regmap_config *regmap_config;
  37        struct device *ddev = &spi->dev;
  38        struct regmap_config rc;
  39        struct ksz_device *dev;
  40        struct ksz8 *ksz8;
  41        int i, ret = 0;
  42
  43        ksz8 = devm_kzalloc(&spi->dev, sizeof(struct ksz8), GFP_KERNEL);
  44        if (!ksz8)
  45                return -ENOMEM;
  46
  47        ksz8->priv = spi;
  48
  49        dev = ksz_switch_alloc(&spi->dev, ksz8);
  50        if (!dev)
  51                return -ENOMEM;
  52
  53        regmap_config = device_get_match_data(ddev);
  54        if (!regmap_config)
  55                return -EINVAL;
  56
  57        for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
  58                rc = regmap_config[i];
  59                rc.lock_arg = &dev->regmap_mutex;
  60                dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
  61                if (IS_ERR(dev->regmap[i])) {
  62                        ret = PTR_ERR(dev->regmap[i]);
  63                        dev_err(&spi->dev,
  64                                "Failed to initialize regmap%i: %d\n",
  65                                regmap_config[i].val_bits, ret);
  66                        return ret;
  67                }
  68        }
  69
  70        if (spi->dev.platform_data)
  71                dev->pdata = spi->dev.platform_data;
  72
  73        /* setup spi */
  74        spi->mode = SPI_MODE_3;
  75        ret = spi_setup(spi);
  76        if (ret)
  77                return ret;
  78
  79        ret = ksz8_switch_register(dev);
  80
  81        /* Main DSA driver may not be started yet. */
  82        if (ret)
  83                return ret;
  84
  85        spi_set_drvdata(spi, dev);
  86
  87        return 0;
  88}
  89
  90static int ksz8795_spi_remove(struct spi_device *spi)
  91{
  92        struct ksz_device *dev = spi_get_drvdata(spi);
  93
  94        if (dev)
  95                ksz_switch_remove(dev);
  96
  97        spi_set_drvdata(spi, NULL);
  98
  99        return 0;
 100}
 101
 102static void ksz8795_spi_shutdown(struct spi_device *spi)
 103{
 104        struct ksz_device *dev = spi_get_drvdata(spi);
 105
 106        if (!dev)
 107                return;
 108
 109        if (dev->dev_ops->shutdown)
 110                dev->dev_ops->shutdown(dev);
 111
 112        dsa_switch_shutdown(dev->ds);
 113
 114        spi_set_drvdata(spi, NULL);
 115}
 116
 117static const struct of_device_id ksz8795_dt_ids[] = {
 118        { .compatible = "microchip,ksz8765", .data = &ksz8795_regmap_config },
 119        { .compatible = "microchip,ksz8794", .data = &ksz8795_regmap_config },
 120        { .compatible = "microchip,ksz8795", .data = &ksz8795_regmap_config },
 121        { .compatible = "microchip,ksz8863", .data = &ksz8863_regmap_config },
 122        { .compatible = "microchip,ksz8873", .data = &ksz8863_regmap_config },
 123        {},
 124};
 125MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
 126
 127static struct spi_driver ksz8795_spi_driver = {
 128        .driver = {
 129                .name   = "ksz8795-switch",
 130                .owner  = THIS_MODULE,
 131                .of_match_table = of_match_ptr(ksz8795_dt_ids),
 132        },
 133        .probe  = ksz8795_spi_probe,
 134        .remove = ksz8795_spi_remove,
 135        .shutdown = ksz8795_spi_shutdown,
 136};
 137
 138module_spi_driver(ksz8795_spi_driver);
 139
 140MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
 141MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch SPI Driver");
 142MODULE_LICENSE("GPL");
 143