net: dsa: microchip: Initial SPI regmap support
[platform/kernel/linux-rpi.git] / drivers / net / dsa / microchip / ksz9477_spi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Microchip KSZ9477 series register access through SPI
4  *
5  * Copyright (C) 2017-2019 Microchip Technology Inc.
6  */
7
8 #include <asm/unaligned.h>
9
10 #include <linux/delay.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/regmap.h>
14 #include <linux/spi/spi.h>
15
16 #include "ksz_priv.h"
17
18 #define SPI_ADDR_SHIFT                  24
19 #define SPI_ADDR_ALIGN                  3
20 #define SPI_TURNAROUND_SHIFT            5
21
22 /* SPI frame opcodes */
23 #define KS_SPIOP_RD                     3
24 #define KS_SPIOP_WR                     2
25
26 #define KS_SPIOP_FLAG_MASK(opcode)              \
27         swab32((opcode) << (SPI_ADDR_SHIFT + SPI_TURNAROUND_SHIFT))
28
29 #define KSZ_REGMAP_COMMON(width)                                        \
30         {                                                               \
31                 .val_bits = (width),                                    \
32                 .reg_stride = (width) / 8,                              \
33                 .reg_bits = SPI_ADDR_SHIFT + SPI_ADDR_ALIGN,            \
34                 .pad_bits = SPI_TURNAROUND_SHIFT,                       \
35                 .max_register = BIT(SPI_ADDR_SHIFT) - 1,                \
36                 .cache_type = REGCACHE_NONE,                            \
37                 .read_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_RD),      \
38                 .write_flag_mask = KS_SPIOP_FLAG_MASK(KS_SPIOP_WR),     \
39                 .reg_format_endian = REGMAP_ENDIAN_BIG,                 \
40                 .val_format_endian = REGMAP_ENDIAN_BIG                  \
41         }
42
43 static const struct regmap_config ksz9477_regmap_config[] = {
44         KSZ_REGMAP_COMMON(8),
45         KSZ_REGMAP_COMMON(16),
46         KSZ_REGMAP_COMMON(32),
47 };
48
49 static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val)
50 {
51         unsigned int value;
52         int ret = regmap_read(dev->regmap, reg, &value);
53
54         *val = value;
55         return ret;
56 }
57
58 static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val)
59 {
60         int ret = regmap_bulk_read(dev->regmap, reg, val, 2);
61
62         if (!ret)
63                 *val = be16_to_cpu(*val);
64
65         return ret;
66 }
67
68 static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val)
69 {
70         int ret = regmap_bulk_read(dev->regmap, reg, val, 4);
71
72         if (!ret)
73                 *val = be32_to_cpu(*val);
74
75         return ret;
76 }
77
78 static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value)
79 {
80         return regmap_write(dev->regmap, reg, value);
81 }
82
83 static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value)
84 {
85         value = cpu_to_be16(value);
86         return regmap_bulk_write(dev->regmap, reg, &value, 2);
87 }
88
89 static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value)
90 {
91         value = cpu_to_be32(value);
92         return regmap_bulk_write(dev->regmap, reg, &value, 4);
93 }
94
95 static const struct ksz_io_ops ksz9477_spi_ops = {
96         .read8 = ksz_spi_read8,
97         .read16 = ksz_spi_read16,
98         .read32 = ksz_spi_read32,
99         .write8 = ksz_spi_write8,
100         .write16 = ksz_spi_write16,
101         .write32 = ksz_spi_write32,
102 };
103
104 static int ksz9477_spi_probe(struct spi_device *spi)
105 {
106         struct ksz_device *dev;
107         int i, ret;
108
109         dev = ksz_switch_alloc(&spi->dev, &ksz9477_spi_ops, spi);
110         if (!dev)
111                 return -ENOMEM;
112
113         for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
114                 dev->regmap[i] = devm_regmap_init_spi(spi,
115                                         &ksz9477_regmap_config[i]);
116                 if (IS_ERR(dev->regmap[i])) {
117                         ret = PTR_ERR(dev->regmap[i]);
118                         dev_err(&spi->dev,
119                                 "Failed to initialize regmap%i: %d\n",
120                                 ksz9477_regmap_config[i].val_bits, ret);
121                         return ret;
122                 }
123         }
124
125         if (spi->dev.platform_data)
126                 dev->pdata = spi->dev.platform_data;
127
128         ret = ksz9477_switch_register(dev);
129
130         /* Main DSA driver may not be started yet. */
131         if (ret)
132                 return ret;
133
134         spi_set_drvdata(spi, dev);
135
136         return 0;
137 }
138
139 static int ksz9477_spi_remove(struct spi_device *spi)
140 {
141         struct ksz_device *dev = spi_get_drvdata(spi);
142
143         if (dev)
144                 ksz_switch_remove(dev);
145
146         return 0;
147 }
148
149 static void ksz9477_spi_shutdown(struct spi_device *spi)
150 {
151         struct ksz_device *dev = spi_get_drvdata(spi);
152
153         if (dev && dev->dev_ops->shutdown)
154                 dev->dev_ops->shutdown(dev);
155 }
156
157 static const struct of_device_id ksz9477_dt_ids[] = {
158         { .compatible = "microchip,ksz9477" },
159         { .compatible = "microchip,ksz9897" },
160         { .compatible = "microchip,ksz9893" },
161         { .compatible = "microchip,ksz9563" },
162         {},
163 };
164 MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
165
166 static struct spi_driver ksz9477_spi_driver = {
167         .driver = {
168                 .name   = "ksz9477-switch",
169                 .owner  = THIS_MODULE,
170                 .of_match_table = of_match_ptr(ksz9477_dt_ids),
171         },
172         .probe  = ksz9477_spi_probe,
173         .remove = ksz9477_spi_remove,
174         .shutdown = ksz9477_spi_shutdown,
175 };
176
177 module_spi_driver(ksz9477_spi_driver);
178
179 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
180 MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch SPI access Driver");
181 MODULE_LICENSE("GPL");