blob: 8e227d187b0c214978ed9c8deb6bdee6112d7606 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Thomas Chou3a673f12010-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 Chou3a673f12010-04-30 11:34:16 +08008 */
Thomas Chouc5899542015-10-14 08:33:34 +08009#include <dm.h>
10#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Thomas Chou3a673f12010-04-30 11:34:16 +080012#include <malloc.h>
Thomas Chouc5899542015-10-14 08:33:34 +080013#include <fdtdec.h>
Jagan Tekia6f48752015-10-27 23:11:11 +053014#include <spi.h>
Thomas Chouc5899542015-10-14 08:33:34 +080015#include <asm/io.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Thomas Chouc5899542015-10-14 08:33:34 +080017
Jagan Tekia6f48752015-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 Rinib0f0a212021-08-19 15:06:54 -040021#define ALTERA_SPI_IDLE_VAL 0xff
Marek Vasut7bb4fc32014-10-22 21:56:04 +020022
Marek Vasut42066022014-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 Chou3a673f12010-04-30 11:34:16 +080031
Simon Glassb75b15b2020-12-03 16:55:23 -070032struct altera_spi_plat {
Thomas Chouc5899542015-10-14 08:33:34 +080033 struct altera_spi_regs *regs;
34};
Thomas Chou3a673f12010-04-30 11:34:16 +080035
Thomas Chouc5899542015-10-14 08:33:34 +080036struct altera_spi_priv {
37 struct altera_spi_regs *regs;
Thomas Chou3a673f12010-04-30 11:34:16 +080038};
Thomas Chou3a673f12010-04-30 11:34:16 +080039
Thomas Chouc5899542015-10-14 08:33:34 +080040static void spi_cs_activate(struct udevice *dev, uint cs)
Thomas Chou3a673f12010-04-30 11:34:16 +080041{
Thomas Chouc5899542015-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;
Thomas Chou3a673f12010-04-30 11:34:16 +080045
Thomas Chouc5899542015-10-14 08:33:34 +080046 writel(1 << cs, &regs->slave_sel);
47 writel(ALTERA_SPI_CONTROL_SSO_MSK, &regs->control);
Thomas Chou3a673f12010-04-30 11:34:16 +080048}
49
Thomas Chouc5899542015-10-14 08:33:34 +080050static void spi_cs_deactivate(struct udevice *dev)
Thomas Chou3a673f12010-04-30 11:34:16 +080051{
Thomas Chouc5899542015-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;
Thomas Chou3a673f12010-04-30 11:34:16 +080055
Thomas Chouc5899542015-10-14 08:33:34 +080056 writel(0, &regs->control);
57 writel(0, &regs->slave_sel);
Thomas Chou55be2b52010-12-27 09:30:17 +080058}
59
Thomas Chouc5899542015-10-14 08:33:34 +080060static int altera_spi_claim_bus(struct udevice *dev)
Thomas Chou3a673f12010-04-30 11:34:16 +080061{
Thomas Chouc5899542015-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 Chou3a673f12010-04-30 11:34:16 +080065
Thomas Chouc5899542015-10-14 08:33:34 +080066 writel(0, &regs->control);
67 writel(0, &regs->slave_sel);
Thomas Chou3a673f12010-04-30 11:34:16 +080068
Thomas Chouc5899542015-10-14 08:33:34 +080069 return 0;
Thomas Chou3a673f12010-04-30 11:34:16 +080070}
71
Thomas Chouc5899542015-10-14 08:33:34 +080072static int altera_spi_release_bus(struct udevice *dev)
Thomas Chou3a673f12010-04-30 11:34:16 +080073{
Thomas Chouc5899542015-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 Chou3a673f12010-04-30 11:34:16 +080077
Thomas Chouc5899542015-10-14 08:33:34 +080078 writel(0, &regs->slave_sel);
Thomas Chou3a673f12010-04-30 11:34:16 +080079
Thomas Chou3a673f12010-04-30 11:34:16 +080080 return 0;
81}
82
Thomas Chouc5899542015-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 Chou3a673f12010-04-30 11:34:16 +080085{
Thomas Chouc5899542015-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 Glassb75b15b2020-12-03 16:55:23 -070089 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
Thomas Chou3a673f12010-04-30 11:34:16 +080090
Thomas Chou3a673f12010-04-30 11:34:16 +080091 /* assume spi core configured to do 8 bit transfers */
Marek Vasut5c97e302014-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 Chou3a673f12010-04-30 11:34:16 +080096
97 debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
Simon Glass75e534b2020-12-16 21:20:07 -070098 dev_seq(bus), slave_plat->cs, bitlen, bytes, flags);
Marek Vasuta49ffc32014-10-22 21:56:00 +020099
Thomas Chou3a673f12010-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 Chouc5899542015-10-14 08:33:34 +0800109 if (readl(&regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
110 readl(&regs->rxdata);
Marek Vasuta49ffc32014-10-22 21:56:00 +0200111
Thomas Chou3a673f12010-04-30 11:34:16 +0800112 if (flags & SPI_XFER_BEGIN)
Thomas Chouc5899542015-10-14 08:33:34 +0800113 spi_cs_activate(dev, slave_plat->cs);
Thomas Chou3a673f12010-04-30 11:34:16 +0800114
115 while (bytes--) {
Marek Vasut5c97e302014-10-22 21:56:02 +0200116 if (txp)
117 data = *txp++;
118 else
Tom Rinib0f0a212021-08-19 15:06:54 -0400119 data = ALTERA_SPI_IDLE_VAL;
Marek Vasuta49ffc32014-10-22 21:56:00 +0200120
Marek Vasut5c97e302014-10-22 21:56:02 +0200121 debug("%s: tx:%x ", __func__, data);
Thomas Chouc5899542015-10-14 08:33:34 +0800122 writel(data, &regs->txdata);
Marek Vasuta49ffc32014-10-22 21:56:00 +0200123
Marek Vasutec6938e2014-10-22 21:56:01 +0200124 start = get_timer(0);
125 while (1) {
Thomas Chouc5899542015-10-14 08:33:34 +0800126 reg = readl(&regs->status);
Marek Vasutec6938e2014-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 Chouc5899542015-10-14 08:33:34 +0800130 debug("%s: Transmission timed out!\n", __func__);
131 return -1;
Marek Vasutec6938e2014-10-22 21:56:01 +0200132 }
133 }
Marek Vasuta49ffc32014-10-22 21:56:00 +0200134
Thomas Chouc5899542015-10-14 08:33:34 +0800135 data = readl(&regs->rxdata);
Thomas Chou3a673f12010-04-30 11:34:16 +0800136 if (rxp)
Marek Vasut5c97e302014-10-22 21:56:02 +0200137 *rxp++ = data & 0xff;
Marek Vasuta49ffc32014-10-22 21:56:00 +0200138
Marek Vasut5c97e302014-10-22 21:56:02 +0200139 debug("rx:%x\n", data);
Thomas Chou3a673f12010-04-30 11:34:16 +0800140 }
Marek Vasuta49ffc32014-10-22 21:56:00 +0200141
142done:
Thomas Chou3a673f12010-04-30 11:34:16 +0800143 if (flags & SPI_XFER_END)
Thomas Chouc5899542015-10-14 08:33:34 +0800144 spi_cs_deactivate(dev);
Thomas Chou3a673f12010-04-30 11:34:16 +0800145
146 return 0;
147}
Thomas Chouc5899542015-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 Glassb75b15b2020-12-03 16:55:23 -0700161 struct altera_spi_plat *plat = dev_get_plat(bus);
Thomas Chouc5899542015-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 Glassaad29ae2020-12-03 16:55:21 -0700169static int altera_spi_of_to_plat(struct udevice *bus)
Thomas Chouc5899542015-10-14 08:33:34 +0800170{
Simon Glassb75b15b2020-12-03 16:55:23 -0700171 struct altera_spi_plat *plat = dev_get_plat(bus);
Thomas Chouc5899542015-10-14 08:33:34 +0800172
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900173 plat->regs = map_physmem(dev_read_addr(bus),
Thomas Chou3f1f1a22015-11-14 11:17:25 +0800174 sizeof(struct altera_spi_regs),
175 MAP_NOCACHE);
Thomas Chouc5899542015-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 Chouef4b3502015-10-31 20:55:48 +0800193 { .compatible = "altr,spi-1.0" },
194 {}
Thomas Chouc5899542015-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 Glassaad29ae2020-12-03 16:55:21 -0700202 .of_to_plat = altera_spi_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700203 .plat_auto = sizeof(struct altera_spi_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700204 .priv_auto = sizeof(struct altera_spi_priv),
Thomas Chouc5899542015-10-14 08:33:34 +0800205 .probe = altera_spi_probe,
206};