brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 7af0979 Raw
224 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Altera SPI driver4 *5 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>6 *7 * Based on spi_s3c24xx.c, which is:8 * Copyright (c) 2006 Ben Dooks9 * Copyright (c) 2006 Simtec Electronics10 *	Ben Dooks <ben@simtec.co.uk>11 */12 13#include <linux/errno.h>14#include <linux/module.h>15#include <linux/platform_device.h>16#include <linux/spi/altera.h>17#include <linux/spi/spi.h>18#include <linux/io.h>19#include <linux/of.h>20 21#define DRV_NAME "spi_altera"22 23#define ALTERA_SPI_RXDATA	024#define ALTERA_SPI_TXDATA	425#define ALTERA_SPI_STATUS	826#define ALTERA_SPI_CONTROL	1227#define ALTERA_SPI_TARGET_SEL	2028 29#define ALTERA_SPI_STATUS_ROE_MSK	0x830#define ALTERA_SPI_STATUS_TOE_MSK	0x1031#define ALTERA_SPI_STATUS_TMT_MSK	0x2032#define ALTERA_SPI_STATUS_TRDY_MSK	0x4033#define ALTERA_SPI_STATUS_RRDY_MSK	0x8034#define ALTERA_SPI_STATUS_E_MSK		0x10035 36#define ALTERA_SPI_CONTROL_IROE_MSK	0x837#define ALTERA_SPI_CONTROL_ITOE_MSK	0x1038#define ALTERA_SPI_CONTROL_ITRDY_MSK	0x4039#define ALTERA_SPI_CONTROL_IRRDY_MSK	0x8040#define ALTERA_SPI_CONTROL_IE_MSK	0x10041#define ALTERA_SPI_CONTROL_SSO_MSK	0x40042 43static int altr_spi_writel(struct altera_spi *hw, unsigned int reg,44			   unsigned int val)45{46	int ret;47 48	ret = regmap_write(hw->regmap, hw->regoff + reg, val);49	if (ret)50		dev_err(hw->dev, "fail to write reg 0x%x val 0x%x: %d\n",51			reg, val, ret);52 53	return ret;54}55 56static int altr_spi_readl(struct altera_spi *hw, unsigned int reg,57			  unsigned int *val)58{59	int ret;60 61	ret = regmap_read(hw->regmap, hw->regoff + reg, val);62	if (ret)63		dev_err(hw->dev, "fail to read reg 0x%x: %d\n", reg, ret);64 65	return ret;66}67 68static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)69{70	return spi_controller_get_devdata(sdev->controller);71}72 73static void altera_spi_set_cs(struct spi_device *spi, bool is_high)74{75	struct altera_spi *hw = altera_spi_to_hw(spi);76 77	if (is_high) {78		hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;79		altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);80		altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL, 0);81	} else {82		altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL,83				BIT(spi_get_chipselect(spi, 0)));84		hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;85		altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);86	}87}88 89static void altera_spi_tx_word(struct altera_spi *hw)90{91	unsigned int txd = 0;92 93	if (hw->tx) {94		switch (hw->bytes_per_word) {95		case 1:96			txd = hw->tx[hw->count];97			break;98		case 2:99			txd = (hw->tx[hw->count * 2]100				| (hw->tx[hw->count * 2 + 1] << 8));101			break;102		case 4:103			txd = (hw->tx[hw->count * 4]104				| (hw->tx[hw->count * 4 + 1] << 8)105				| (hw->tx[hw->count * 4 + 2] << 16)106				| (hw->tx[hw->count * 4 + 3] << 24));107			break;108 109		}110	}111 112	altr_spi_writel(hw, ALTERA_SPI_TXDATA, txd);113}114 115static void altera_spi_rx_word(struct altera_spi *hw)116{117	unsigned int rxd;118 119	altr_spi_readl(hw, ALTERA_SPI_RXDATA, &rxd);120	if (hw->rx) {121		switch (hw->bytes_per_word) {122		case 1:123			hw->rx[hw->count] = rxd;124			break;125		case 2:126			hw->rx[hw->count * 2] = rxd;127			hw->rx[hw->count * 2 + 1] = rxd >> 8;128			break;129		case 4:130			hw->rx[hw->count * 4] = rxd;131			hw->rx[hw->count * 4 + 1] = rxd >> 8;132			hw->rx[hw->count * 4 + 2] = rxd >> 16;133			hw->rx[hw->count * 4 + 3] = rxd >> 24;134			break;135 136		}137	}138 139	hw->count++;140}141 142static int altera_spi_txrx(struct spi_controller *host,143	struct spi_device *spi, struct spi_transfer *t)144{145	struct altera_spi *hw = spi_controller_get_devdata(host);146	u32 val;147 148	hw->tx = t->tx_buf;149	hw->rx = t->rx_buf;150	hw->count = 0;151	hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);152	hw->len = t->len / hw->bytes_per_word;153 154	if (hw->irq >= 0) {155		/* enable receive interrupt */156		hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;157		altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);158 159		/* send the first byte */160		altera_spi_tx_word(hw);161 162		return 1;163	}164 165	while (hw->count < hw->len) {166		altera_spi_tx_word(hw);167 168		for (;;) {169			altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);170			if (val & ALTERA_SPI_STATUS_RRDY_MSK)171				break;172 173			cpu_relax();174		}175 176		altera_spi_rx_word(hw);177	}178	spi_finalize_current_transfer(host);179 180	return 0;181}182 183irqreturn_t altera_spi_irq(int irq, void *dev)184{185	struct spi_controller *host = dev;186	struct altera_spi *hw = spi_controller_get_devdata(host);187 188	altera_spi_rx_word(hw);189 190	if (hw->count < hw->len) {191		altera_spi_tx_word(hw);192	} else {193		/* disable receive interrupt */194		hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;195		altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);196 197		spi_finalize_current_transfer(host);198	}199 200	return IRQ_HANDLED;201}202EXPORT_SYMBOL_GPL(altera_spi_irq);203 204void altera_spi_init_host(struct spi_controller *host)205{206	struct altera_spi *hw = spi_controller_get_devdata(host);207	u32 val;208 209	host->transfer_one = altera_spi_txrx;210	host->set_cs = altera_spi_set_cs;211 212	/* program defaults into the registers */213	hw->imr = 0;		/* disable spi interrupts */214	altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);215	altr_spi_writel(hw, ALTERA_SPI_STATUS, 0);	/* clear status reg */216	altr_spi_readl(hw, ALTERA_SPI_STATUS, &val);217	if (val & ALTERA_SPI_STATUS_RRDY_MSK)218		altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */219}220EXPORT_SYMBOL_GPL(altera_spi_init_host);221 222MODULE_DESCRIPTION("Altera SPI Controller driver core");223MODULE_LICENSE("GPL");224