blob: 8e227d187b0c214978ed9c8deb6bdee6112d7606 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Thomas Chou661ba142010-04-30 11:34:16 +08002/*
3 * Altera SPI driver
4 *
5 * based on bfin_spi.c
6 * Copyright (c) 2005-2008 Analog Devices Inc.
7 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
Thomas Chou661ba142010-04-30 11:34:16 +08008 */
Thomas Chou15a56f92015-10-14 08:33:34 +08009#include <dm.h>
10#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Thomas Chou661ba142010-04-30 11:34:16 +080012#include <malloc.h>
Thomas Chou15a56f92015-10-14 08:33:34 +080013#include <fdtdec.h>
Jagan Tekibef87ad2015-10-27 23:11:11 +053014#include <spi.h>
Thomas Chou15a56f92015-10-14 08:33:34 +080015#include <asm/io.h>
Simon Glasscd93d622020-05-10 11:40:13 -060016#include <linux/bitops.h>
Thomas Chou15a56f92015-10-14 08:33:34 +080017
Jagan Tekibef87ad2015-10-27 23:11:11 +053018#define ALTERA_SPI_STATUS_RRDY_MSK BIT(7)
19#define ALTERA_SPI_CONTROL_SSO_MSK BIT(10)
20
Tom Rinib166f042021-08-19 15:06:54 -040021#define ALTERA_SPI_IDLE_VAL 0xff
Marek Vasutcdcdad82014-10-22 21:56:04 +020022
Marek Vasuteef67022014-10-22 21:55:58 +020023struct altera_spi_regs {
24 u32 rxdata;
25 u32 txdata;
26 u32 status;
27 u32 control;
28 u32 _reserved;
29 u32 slave_sel;
30};
Thomas Chou661ba142010-04-30 11:34:16 +080031
Simon Glass8a8d24b2020-12-03 16:55:23 -070032struct altera_spi_plat {
Thomas Chou15a56f92015-10-14 08:33:34 +080033 struct altera_spi_regs *regs;
34};
Thomas Chou661ba142010-04-30 11:34:16 +080035
Thomas Chou15a56f92015-10-14 08:33:34 +080036struct altera_spi_priv {
37 struct altera_spi_regs *regs;
38};
39
Thomas Chou15a56f92015-10-14 08:33:34 +080040static void spi_cs_activate(struct udevice *dev, uint cs)
Thomas Chou661ba142010-04-30 11:34:16 +080041{
Thomas Chou15a56f92015-10-14 08:33:34 +080042 struct udevice *bus = dev->parent;
43 struct altera_spi_priv *priv = dev_get_priv(bus);
44 struct altera_spi_regs *const regs = priv->regs;
45
46 writel(1 << cs, &regs->slave_sel);
47 writel(ALTERA_SPI_CONTROL_SSO_MSK, &regs->control);
Thomas Chou661ba142010-04-30 11:34:16 +080048}
49
Thomas Chou15a56f92015-10-14 08:33:34 +080050static void spi_cs_deactivate(struct udevice *dev)
Thomas Chou661ba142010-04-30 11:34:16 +080051{
Thomas Chou15a56f92015-10-14 08:33:34 +080052 struct udevice *bus = dev->parent;
53 struct altera_spi_priv *priv = dev_get_priv(bus);
54 struct altera_spi_regs *const regs = priv->regs;
55
56 writel(0, &regs->control);
57 writel(0, &regs->slave_sel);
Thomas Chou661ba142010-04-30 11:34:16 +080058}
59
Thomas Chou15a56f92015-10-14 08:33:34 +080060static int altera_spi_claim_bus(struct udevice *dev)
Thomas Chou661ba142010-04-30 11:34:16 +080061{
Thomas Chou15a56f92015-10-14 08:33:34 +080062 struct udevice *bus = dev->parent;
63 struct altera_spi_priv *priv = dev_get_priv(bus);
64 struct altera_spi_regs *const regs = priv->regs;
Thomas Chou661ba142010-04-30 11:34:16 +080065
Thomas Chou15a56f92015-10-14 08:33:34 +080066 writel(0, &regs->control);
67 writel(0, &regs->slave_sel);
Thomas Chou661ba142010-04-30 11:34:16 +080068
Thomas Chou661ba142010-04-30 11:34:16 +080069 return 0;
70}
71
Thomas Chou15a56f92015-10-14 08:33:34 +080072static int altera_spi_release_bus(struct udevice *dev)
Thomas Chou661ba142010-04-30 11:34:16 +080073{
Thomas Chou15a56f92015-10-14 08:33:34 +080074 struct udevice *bus = dev->parent;
75 struct altera_spi_priv *priv = dev_get_priv(bus);
76 struct altera_spi_regs *const regs = priv->regs;
Thomas Chou661ba142010-04-30 11:34:16 +080077
Thomas Chou15a56f92015-10-14 08:33:34 +080078 writel(0, &regs->slave_sel);
79
80 return 0;
Thomas Chou661ba142010-04-30 11:34:16 +080081}
82
Thomas Chou15a56f92015-10-14 08:33:34 +080083static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen,
84 const void *dout, void *din, unsigned long flags)
Thomas Chou661ba142010-04-30 11:34:16 +080085{
Thomas Chou15a56f92015-10-14 08:33:34 +080086 struct udevice *bus = dev->parent;
87 struct altera_spi_priv *priv = dev_get_priv(bus);
88 struct altera_spi_regs *const regs = priv->regs;
Simon Glass8a8d24b2020-12-03 16:55:23 -070089 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
Thomas Chou15a56f92015-10-14 08:33:34 +080090
Thomas Chou661ba142010-04-30 11:34:16 +080091 /* assume spi core configured to do 8 bit transfers */
Marek Vasutbc76b822014-10-22 21:56:02 +020092 unsigned int bytes = bitlen / 8;
93 const unsigned char *txp = dout;
94 unsigned char *rxp = din;
95 uint32_t reg, data, start;
Thomas Chou661ba142010-04-30 11:34:16 +080096
97 debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
Simon Glass8b85dfc2020-12-16 21:20:07 -070098 dev_seq(bus), slave_plat->cs, bitlen, bytes, flags);
Marek Vasut37dcc132014-10-22 21:56:00 +020099
Thomas Chou661ba142010-04-30 11:34:16 +0800100 if (bitlen == 0)
101 goto done;
102
103 if (bitlen % 8) {
104 flags |= SPI_XFER_END;
105 goto done;
106 }
107
108 /* empty read buffer */
Thomas Chou15a56f92015-10-14 08:33:34 +0800109 if (readl(&regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
110 readl(&regs->rxdata);
Marek Vasut37dcc132014-10-22 21:56:00 +0200111
Thomas Chou661ba142010-04-30 11:34:16 +0800112 if (flags & SPI_XFER_BEGIN)
Thomas Chou15a56f92015-10-14 08:33:34 +0800113 spi_cs_activate(dev, slave_plat->cs);
Thomas Chou661ba142010-04-30 11:34:16 +0800114
115 while (bytes--) {
Marek Vasutbc76b822014-10-22 21:56:02 +0200116 if (txp)
117 data = *txp++;
118 else
Tom Rinib166f042021-08-19 15:06:54 -0400119 data = ALTERA_SPI_IDLE_VAL;
Marek Vasut37dcc132014-10-22 21:56:00 +0200120
Marek Vasutbc76b822014-10-22 21:56:02 +0200121 debug("%s: tx:%x ", __func__, data);
Thomas Chou15a56f92015-10-14 08:33:34 +0800122 writel(data, &regs->txdata);
Marek Vasut37dcc132014-10-22 21:56:00 +0200123
Marek Vasut80d73332014-10-22 21:56:01 +0200124 start = get_timer(0);
125 while (1) {
Thomas Chou15a56f92015-10-14 08:33:34 +0800126 reg = readl(&regs->status);
Marek Vasut80d73332014-10-22 21:56:01 +0200127 if (reg & ALTERA_SPI_STATUS_RRDY_MSK)
128 break;
129 if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
Thomas Chou15a56f92015-10-14 08:33:34 +0800130 debug("%s: Transmission timed out!\n", __func__);
131 return -1;
Marek Vasut80d73332014-10-22 21:56:01 +0200132 }
133 }
Marek Vasut37dcc132014-10-22 21:56:00 +0200134
Thomas Chou15a56f92015-10-14 08:33:34 +0800135 data = readl(&regs->rxdata);
Thomas Chou661ba142010-04-30 11:34:16 +0800136 if (rxp)
Marek Vasutbc76b822014-10-22 21:56:02 +0200137 *rxp++ = data & 0xff;
Marek Vasut37dcc132014-10-22 21:56:00 +0200138
Marek Vasutbc76b822014-10-22 21:56:02 +0200139 debug("rx:%x\n", data);
Thomas Chou661ba142010-04-30 11:34:16 +0800140 }
Marek Vasut37dcc132014-10-22 21:56:00 +0200141
142done:
Thomas Chou661ba142010-04-30 11:34:16 +0800143 if (flags & SPI_XFER_END)
Thomas Chou15a56f92015-10-14 08:33:34 +0800144 spi_cs_deactivate(dev);
Thomas Chou661ba142010-04-30 11:34:16 +0800145
146 return 0;
147}
Thomas Chou15a56f92015-10-14 08:33:34 +0800148
149static int altera_spi_set_speed(struct udevice *bus, uint speed)
150{
151 return 0;
152}
153
154static int altera_spi_set_mode(struct udevice *bus, uint mode)
155{
156 return 0;
157}
158
159static int altera_spi_probe(struct udevice *bus)
160{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700161 struct altera_spi_plat *plat = dev_get_plat(bus);
Thomas Chou15a56f92015-10-14 08:33:34 +0800162 struct altera_spi_priv *priv = dev_get_priv(bus);
163
164 priv->regs = plat->regs;
165
166 return 0;
167}
168
Simon Glassd1998a92020-12-03 16:55:21 -0700169static int altera_spi_of_to_plat(struct udevice *bus)
Thomas Chou15a56f92015-10-14 08:33:34 +0800170{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700171 struct altera_spi_plat *plat = dev_get_plat(bus);
Thomas Chou15a56f92015-10-14 08:33:34 +0800172
Masahiro Yamada25484932020-07-17 14:36:48 +0900173 plat->regs = map_physmem(dev_read_addr(bus),
Thomas Chou7313e212015-11-14 11:17:25 +0800174 sizeof(struct altera_spi_regs),
175 MAP_NOCACHE);
Thomas Chou15a56f92015-10-14 08:33:34 +0800176
177 return 0;
178}
179
180static const struct dm_spi_ops altera_spi_ops = {
181 .claim_bus = altera_spi_claim_bus,
182 .release_bus = altera_spi_release_bus,
183 .xfer = altera_spi_xfer,
184 .set_speed = altera_spi_set_speed,
185 .set_mode = altera_spi_set_mode,
186 /*
187 * cs_info is not needed, since we require all chip selects to be
188 * in the device tree explicitly
189 */
190};
191
192static const struct udevice_id altera_spi_ids[] = {
Thomas Chouddf34c22015-10-31 20:55:48 +0800193 { .compatible = "altr,spi-1.0" },
194 {}
Thomas Chou15a56f92015-10-14 08:33:34 +0800195};
196
197U_BOOT_DRIVER(altera_spi) = {
198 .name = "altera_spi",
199 .id = UCLASS_SPI,
200 .of_match = altera_spi_ids,
201 .ops = &altera_spi_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700202 .of_to_plat = altera_spi_of_to_plat,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700203 .plat_auto = sizeof(struct altera_spi_plat),
Simon Glass41575d82020-12-03 16:55:17 -0700204 .priv_auto = sizeof(struct altera_spi_priv),
Thomas Chou15a56f92015-10-14 08:33:34 +0800205 .probe = altera_spi_probe,
206};