ath79: add Mikrotik rb4xx series drivers
[oweals/openwrt.git] / target / linux / ath79 / files / drivers / mfd / rb4xx-cpld.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * CPLD driver for the MikroTik RouterBoard 4xx series
4  *
5  * This driver provides access to a CPLD that interfaces between the SoC SPI bus
6  * and other devices. Behind the CPLD there is a NAND flash chip and five LEDs.
7  *
8  * The CPLD supports SPI two-wire mode, in which two bits are transferred per
9  * SPI clock cycle. The second bit is transmitted with the SoC's CS2 pin.
10  *
11  * The CPLD also acts as a GPIO expander.
12  *
13  * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
14  * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
15  * Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
16  * Copyright (C) 2020 Christopher Hill <ch6574@gmail.com>
17  *
18  * This file was based on the driver for Linux 2.6.22 published by
19  * MikroTik for their RouterBoard 4xx series devices.
20 */
21 #include <linux/mfd/core.h>
22 #include <linux/spi/spi.h>
23 #include <linux/module.h>
24 #include <linux/of_platform.h>
25
26 #include <mfd/rb4xx-cpld.h>
27
28 /* CPLD commands */
29 #define CPLD_CMD_WRITE_NAND     0x08 /* send cmd, n x send data, send idle */
30 #define CPLD_CMD_WRITE_CFG      0x09 /* send cmd, n x send cfg */
31 #define CPLD_CMD_READ_NAND      0x0a /* send cmd, send idle, n x read data */
32 #define CPLD_CMD_READ_FAST      0x0b /* send cmd, 4 x idle, n x read data */
33 #define CPLD_CMD_GPIO8_HIGH     0x0c /* send cmd */
34 #define CPLD_CMD_GPIO8_LOW      0x0d /* send cmd */
35
36 static int rb4xx_cpld_write_nand(struct rb4xx_cpld *cpld, const void *tx_buf,
37                                  unsigned int len)
38 {
39         struct spi_message m;
40         static const u8 cmd = CPLD_CMD_WRITE_NAND;
41         struct spi_transfer t[3] = {
42                 {
43                         .tx_buf = &cmd,
44                         .len = sizeof(cmd),
45                 }, {
46                         .tx_buf = tx_buf,
47                         .len = len,
48                         .tx_nbits = SPI_NBITS_DUAL,
49                 }, {
50                         .len = 1,
51                         .tx_nbits = SPI_NBITS_DUAL,
52                 },
53         };
54
55         spi_message_init(&m);
56         spi_message_add_tail(&t[0], &m);
57         spi_message_add_tail(&t[1], &m);
58         spi_message_add_tail(&t[2], &m);
59         return spi_sync(cpld->spi, &m);
60 }
61
62 static int rb4xx_cpld_read_nand(struct rb4xx_cpld *cpld, void *rx_buf,
63                                 unsigned int len)
64 {
65         struct spi_message m;
66         static const u8 cmd[2] = {
67                 CPLD_CMD_READ_NAND, 0
68         };
69         struct spi_transfer t[2] = {
70                 {
71                         .tx_buf = &cmd,
72                         .len = sizeof(cmd),
73                 }, {
74                         .rx_buf = rx_buf,
75                         .len = len,
76                 },
77         };
78
79         spi_message_init(&m);
80         spi_message_add_tail(&t[0], &m);
81         spi_message_add_tail(&t[1], &m);
82         return spi_sync(cpld->spi, &m);
83 }
84
85 static int rb4xx_cpld_cmd(struct rb4xx_cpld *cpld, const void *tx_buf,
86                           unsigned int len)
87 {
88         struct spi_message m;
89         struct spi_transfer t = {
90                 .tx_buf = tx_buf,
91                 .len = len,
92         };
93
94         spi_message_init(&m);
95         spi_message_add_tail(&t, &m);
96         return spi_sync(cpld->spi, &m);
97 }
98
99 static int rb4xx_cpld_gpio_set_0_7(struct rb4xx_cpld *cpld, u8 values)
100 {
101         /* GPIO 0-7 change can be sent via command + bitfield */
102         u8 cmd[2] = {
103                 CPLD_CMD_WRITE_CFG, values
104         };
105         return rb4xx_cpld_cmd(cpld, &cmd, 2);
106 }
107
108 static int rb4xx_cpld_gpio_set_8(struct rb4xx_cpld *cpld, u8 value)
109 {
110         /* GPIO 8 uses dedicated high/low commands */
111         u8 cmd = CPLD_CMD_GPIO8_HIGH | !!(value);
112         return rb4xx_cpld_cmd(cpld, &cmd, 1);
113 }
114
115 static const struct mfd_cell rb4xx_cpld_cells[] = {
116         {
117                 .name = "mikrotik,rb4xx-gpio",
118                 .of_compatible = "mikrotik,rb4xx-gpio",
119         }, {
120                 .name = "mikrotik,rb4xx-nand",
121                 .of_compatible = "mikrotik,rb4xx-nand",
122         },
123 };
124
125 static int rb4xx_cpld_probe(struct spi_device *spi)
126 {
127         struct device *dev = &spi->dev;
128         struct rb4xx_cpld *cpld;
129         int ret;
130
131         cpld = devm_kzalloc(dev, sizeof(*cpld), GFP_KERNEL);
132         if (!cpld)
133                 return -ENOMEM;
134
135         dev_set_drvdata(dev, cpld);
136
137         cpld->spi               = spi;
138         cpld->write_nand        = rb4xx_cpld_write_nand;
139         cpld->read_nand         = rb4xx_cpld_read_nand;
140         cpld->gpio_set_0_7      = rb4xx_cpld_gpio_set_0_7;
141         cpld->gpio_set_8        = rb4xx_cpld_gpio_set_8;
142
143         spi->mode = SPI_MODE_0 | SPI_TX_DUAL;
144         ret = spi_setup(spi);
145         if (ret)
146                 return ret;
147
148         return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
149                                     rb4xx_cpld_cells,
150                                     ARRAY_SIZE(rb4xx_cpld_cells),
151                                     NULL, 0, NULL);
152 }
153
154 static int rb4xx_cpld_remove(struct spi_device *spi)
155 {
156         return 0;
157 }
158
159 static const struct of_device_id rb4xx_cpld_dt_match[] = {
160         { .compatible = "mikrotik,rb4xx-cpld", },
161         { },
162 };
163 MODULE_DEVICE_TABLE(of, rb4xx_cpld_dt_match);
164
165 static struct spi_driver rb4xx_cpld_driver = {
166         .probe = rb4xx_cpld_probe,
167         .remove = rb4xx_cpld_remove,
168         .driver = {
169                 .name = "rb4xx-cpld",
170                 .bus = &spi_bus_type,
171                 .of_match_table = of_match_ptr(rb4xx_cpld_dt_match),
172         },
173 };
174
175 module_spi_driver(rb4xx_cpld_driver);
176
177 MODULE_DESCRIPTION("Mikrotik RB4xx CPLD driver");
178 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
179 MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
180 MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
181 MODULE_AUTHOR("Christopher Hill <ch6574@gmail.com");
182 MODULE_LICENSE("GPL v2");