blob: bd9ac6541135275ba5f7e25c64267634b0ab9b19 [file] [log] [blame]
Jim Liuc1dc8472022-05-31 18:14:02 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2021 Nuvoton Technology.
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <spi.h>
9#include <clk.h>
10#include <asm/gpio.h>
11#include <linux/iopoll.h>
12
13#define MAX_DIV 127
14
15/* Register offsets */
16#define PSPI_DATA 0
17#define PSPI_CTL1 2
18#define PSPI_STAT 4
19
20/* PSPI_CTL1 fields */
21#define PSPI_CTL1_SPIEN BIT(0)
22#define PSPI_CTL1_SCM BIT(7)
23#define PSPI_CTL1_SCIDL BIT(8)
24#define PSPI_CTL1_SCDV_MASK GENMASK(15, 9)
25#define PSPI_CTL1_SCDV_SHIFT 9
26
27/* PSPI_STAT fields */
28#define PSPI_STAT_BSY BIT(0)
29#define PSPI_STAT_RBF BIT(1)
30
31struct npcm_pspi_priv {
32 void __iomem *base;
33 struct clk clk;
34 struct gpio_desc cs_gpio;
35 u32 max_hz;
36};
37
38static inline void spi_cs_activate(struct udevice *dev)
39{
40 struct udevice *bus = dev->parent;
41 struct npcm_pspi_priv *priv = dev_get_priv(bus);
42
43 dm_gpio_set_value(&priv->cs_gpio, 0);
44}
45
46static inline void spi_cs_deactivate(struct udevice *dev)
47{
48 struct udevice *bus = dev->parent;
49 struct npcm_pspi_priv *priv = dev_get_priv(bus);
50
51 dm_gpio_set_value(&priv->cs_gpio, 1);
52}
53
54static inline void npcm_pspi_enable(struct npcm_pspi_priv *priv)
55{
56 u16 val;
57
58 val = readw(priv->base + PSPI_CTL1);
59 val |= PSPI_CTL1_SPIEN;
60 writew(val, priv->base + PSPI_CTL1);
61}
62
63static inline void npcm_pspi_disable(struct npcm_pspi_priv *priv)
64{
65 u16 val;
66
67 val = readw(priv->base + PSPI_CTL1);
68 val &= ~PSPI_CTL1_SPIEN;
69 writew(val, priv->base + PSPI_CTL1);
70}
71
72static int npcm_pspi_xfer(struct udevice *dev, unsigned int bitlen,
73 const void *dout, void *din, unsigned long flags)
74{
75 struct udevice *bus = dev->parent;
76 struct npcm_pspi_priv *priv = dev_get_priv(bus);
77 void __iomem *base = priv->base;
78 const u8 *tx = dout;
79 u8 *rx = din;
80 u32 bytes = bitlen / 8;
81 u8 tmp;
82 u32 val;
83 int i, ret = 0;
84
85 npcm_pspi_enable(priv);
86
87 if (flags & SPI_XFER_BEGIN)
88 spi_cs_activate(dev);
89
90 for (i = 0; i < bytes; i++) {
91 /* Making sure we can write */
92 ret = readb_poll_timeout(base + PSPI_STAT, val,
93 !(val & PSPI_STAT_BSY),
94 1000000);
95 if (ret < 0)
96 break;
97
98 if (tx)
99 writeb(*tx++, base + PSPI_DATA);
100 else
101 writeb(0, base + PSPI_DATA);
102
103 /* Wait till write completed */
104 ret = readb_poll_timeout(base + PSPI_STAT, val,
105 !(val & PSPI_STAT_BSY),
106 1000000);
107 if (ret < 0)
108 break;
109
110 /* Wait till read buffer full */
111 ret = readb_poll_timeout(base + PSPI_STAT, val,
112 (val & PSPI_STAT_RBF),
113 1000000);
114 if (ret < 0)
115 break;
116
117 tmp = readb(base + PSPI_DATA);
118 if (rx)
119 *rx++ = tmp;
120 }
121
122 if (flags & SPI_XFER_END)
123 spi_cs_deactivate(dev);
124
125 npcm_pspi_disable(priv);
126
127 return ret;
128}
129
130static int npcm_pspi_set_speed(struct udevice *bus, uint speed)
131{
132 struct npcm_pspi_priv *priv = dev_get_priv(bus);
133 ulong apb_clock;
134 u32 divisor;
135 u16 val;
136
137 apb_clock = clk_get_rate(&priv->clk);
138 if (!apb_clock)
139 return -EINVAL;
140
141 if (speed > priv->max_hz)
142 speed = priv->max_hz;
143
144 divisor = DIV_ROUND_CLOSEST(apb_clock, (2 * speed) - 1);
145 if (divisor > MAX_DIV)
146 divisor = MAX_DIV;
147
148 val = readw(priv->base + PSPI_CTL1);
149 val &= ~PSPI_CTL1_SCDV_MASK;
150 val |= divisor << PSPI_CTL1_SCDV_SHIFT;
151 writew(val, priv->base + PSPI_CTL1);
152
153 debug("%s: apb_clock=%lu speed=%d divisor=%u\n",
154 __func__, apb_clock, speed, divisor);
155
156 return 0;
157}
158
159static int npcm_pspi_set_mode(struct udevice *bus, uint mode)
160{
161 struct npcm_pspi_priv *priv = dev_get_priv(bus);
162 u16 pspi_mode, val;
163
164 switch (mode & (SPI_CPOL | SPI_CPHA)) {
165 case SPI_MODE_0:
166 pspi_mode = 0;
167 break;
168 case SPI_MODE_1:
169 pspi_mode = PSPI_CTL1_SCM;
170 break;
171 case SPI_MODE_2:
172 pspi_mode = PSPI_CTL1_SCIDL;
173 break;
174 case SPI_MODE_3:
175 pspi_mode = PSPI_CTL1_SCIDL | PSPI_CTL1_SCM;
176 break;
177 default:
178 break;
179 }
180
181 val = readw(priv->base + PSPI_CTL1);
182 val &= ~(PSPI_CTL1_SCIDL | PSPI_CTL1_SCM);
183 val |= pspi_mode;
184 writew(val, priv->base + PSPI_CTL1);
185
186 return 0;
187}
188
189static int npcm_pspi_probe(struct udevice *bus)
190{
191 struct npcm_pspi_priv *priv = dev_get_priv(bus);
192 int node = dev_of_offset(bus);
193 int ret;
194
195 ret = clk_get_by_index(bus, 0, &priv->clk);
196 if (ret < 0)
197 return ret;
198
199 priv->base = dev_read_addr_ptr(bus);
200 priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0);
201 gpio_request_by_name_nodev(offset_to_ofnode(node), "cs-gpios", 0,
202 &priv->cs_gpio, GPIOD_IS_OUT);
203
204 return 0;
205}
206
207static const struct dm_spi_ops npcm_pspi_ops = {
208 .xfer = npcm_pspi_xfer,
209 .set_speed = npcm_pspi_set_speed,
210 .set_mode = npcm_pspi_set_mode,
211};
212
213static const struct udevice_id npcm_pspi_ids[] = {
214 { .compatible = "nuvoton,npcm845-pspi"},
215 { .compatible = "nuvoton,npcm750-pspi"},
216 { }
217};
218
219U_BOOT_DRIVER(npcm_pspi) = {
220 .name = "npcm_pspi",
221 .id = UCLASS_SPI,
222 .of_match = npcm_pspi_ids,
223 .ops = &npcm_pspi_ops,
224 .priv_auto = sizeof(struct npcm_pspi_priv),
225 .probe = npcm_pspi_probe,
226};