brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 5ba9887 Raw
235 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// SPI controller driver for Qualcomm Atheros AR934x/QCA95xx SoCs4//5// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com>6//7// Based on spi-mt7621.c:8// Copyright (C) 2011 Sergiy <piratfm@gmail.com>9// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>10// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>11 12#include <linux/clk.h>13#include <linux/io.h>14#include <linux/iopoll.h>15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/platform_device.h>19#include <linux/spi/spi.h>20 21#define DRIVER_NAME "spi-ar934x"22 23#define AR934X_SPI_REG_FS		0x0024#define AR934X_SPI_ENABLE		BIT(0)25 26#define AR934X_SPI_REG_IOC		0x0827#define AR934X_SPI_IOC_INITVAL		0x7000028 29#define AR934X_SPI_REG_CTRL		0x0430#define AR934X_SPI_CLK_MASK		GENMASK(5, 0)31 32#define AR934X_SPI_DATAOUT		0x1033 34#define AR934X_SPI_REG_SHIFT_CTRL	0x1435#define AR934X_SPI_SHIFT_EN		BIT(31)36#define AR934X_SPI_SHIFT_CS(n)		BIT(28 + (n))37#define AR934X_SPI_SHIFT_TERM		2638#define AR934X_SPI_SHIFT_VAL(cs, term, count)			\39	(AR934X_SPI_SHIFT_EN | AR934X_SPI_SHIFT_CS(cs) |	\40	(term) << AR934X_SPI_SHIFT_TERM | (count))41 42#define AR934X_SPI_DATAIN 0x1843 44struct ar934x_spi {45	struct spi_controller *ctlr;46	void __iomem *base;47	struct clk *clk;48	unsigned int clk_freq;49};50 51static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq)52{53	int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1;54 55	if (div < 0)56		return 0;57	else if (div > AR934X_SPI_CLK_MASK)58		return -EINVAL;59	else60		return div;61}62 63static int ar934x_spi_setup(struct spi_device *spi)64{65	struct ar934x_spi *sp = spi_controller_get_devdata(spi->controller);66 67	if ((spi->max_speed_hz == 0) ||68	    (spi->max_speed_hz > (sp->clk_freq / 2))) {69		spi->max_speed_hz = sp->clk_freq / 2;70	} else if (spi->max_speed_hz < (sp->clk_freq / 128)) {71		dev_err(&spi->dev, "spi clock is too low\n");72		return -EINVAL;73	}74 75	return 0;76}77 78static int ar934x_spi_transfer_one_message(struct spi_controller *ctlr,79					   struct spi_message *m)80{81	struct ar934x_spi *sp = spi_controller_get_devdata(ctlr);82	struct spi_transfer *t = NULL;83	struct spi_device *spi = m->spi;84	unsigned long trx_done, trx_cur;85	int stat = 0;86	u8 bpw, term = 0;87	int div, i;88	u32 reg;89	const u8 *tx_buf;90	u8 *buf;91 92	m->actual_length = 0;93	list_for_each_entry(t, &m->transfers, transfer_list) {94		if (t->bits_per_word >= 8 && t->bits_per_word < 32)95			bpw = t->bits_per_word >> 3;96		else97			bpw = 4;98 99		if (t->speed_hz)100			div = ar934x_spi_clk_div(sp, t->speed_hz);101		else102			div = ar934x_spi_clk_div(sp, spi->max_speed_hz);103		if (div < 0) {104			stat = -EIO;105			goto msg_done;106		}107 108		reg = ioread32(sp->base + AR934X_SPI_REG_CTRL);109		reg &= ~AR934X_SPI_CLK_MASK;110		reg |= div;111		iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);112		iowrite32(0, sp->base + AR934X_SPI_DATAOUT);113 114		for (trx_done = 0; trx_done < t->len; trx_done += bpw) {115			trx_cur = t->len - trx_done;116			if (trx_cur > bpw)117				trx_cur = bpw;118			else if (list_is_last(&t->transfer_list, &m->transfers))119				term = 1;120 121			if (t->tx_buf) {122				tx_buf = t->tx_buf + trx_done;123				reg = tx_buf[0];124				for (i = 1; i < trx_cur; i++)125					reg = reg << 8 | tx_buf[i];126				iowrite32(reg, sp->base + AR934X_SPI_DATAOUT);127			}128 129			reg = AR934X_SPI_SHIFT_VAL(spi_get_chipselect(spi, 0), term,130						   trx_cur * 8);131			iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL);132			stat = readl_poll_timeout(133				sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg,134				!(reg & AR934X_SPI_SHIFT_EN), 0, 5);135			if (stat < 0)136				goto msg_done;137 138			if (t->rx_buf) {139				reg = ioread32(sp->base + AR934X_SPI_DATAIN);140				buf = t->rx_buf + trx_done;141				for (i = 0; i < trx_cur; i++) {142					buf[trx_cur - i - 1] = reg & 0xff;143					reg >>= 8;144				}145			}146			spi_delay_exec(&t->word_delay, t);147		}148		m->actual_length += t->len;149		spi_transfer_delay_exec(t);150	}151 152msg_done:153	m->status = stat;154	spi_finalize_current_message(ctlr);155 156	return 0;157}158 159static const struct of_device_id ar934x_spi_match[] = {160	{ .compatible = "qca,ar934x-spi" },161	{},162};163MODULE_DEVICE_TABLE(of, ar934x_spi_match);164 165static int ar934x_spi_probe(struct platform_device *pdev)166{167	struct spi_controller *ctlr;168	struct ar934x_spi *sp;169	void __iomem *base;170	struct clk *clk;171 172	base = devm_platform_ioremap_resource(pdev, 0);173	if (IS_ERR(base))174		return PTR_ERR(base);175 176	clk = devm_clk_get_enabled(&pdev->dev, NULL);177	if (IS_ERR(clk)) {178		dev_err(&pdev->dev, "failed to get clock\n");179		return PTR_ERR(clk);180	}181 182	ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*sp));183	if (!ctlr) {184		dev_info(&pdev->dev, "failed to allocate spi controller\n");185		return -ENOMEM;186	}187 188	/* disable flash mapping and expose spi controller registers */189	iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS);190	/* restore pins to default state: CSn=1 DO=CLK=0 */191	iowrite32(AR934X_SPI_IOC_INITVAL, base + AR934X_SPI_REG_IOC);192 193	ctlr->mode_bits = SPI_LSB_FIRST;194	ctlr->setup = ar934x_spi_setup;195	ctlr->transfer_one_message = ar934x_spi_transfer_one_message;196	ctlr->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |197				   SPI_BPW_MASK(16) | SPI_BPW_MASK(8);198	ctlr->dev.of_node = pdev->dev.of_node;199	ctlr->num_chipselect = 3;200 201	dev_set_drvdata(&pdev->dev, ctlr);202 203	sp = spi_controller_get_devdata(ctlr);204	sp->base = base;205	sp->clk = clk;206	sp->clk_freq = clk_get_rate(clk);207	sp->ctlr = ctlr;208 209	return spi_register_controller(ctlr);210}211 212static void ar934x_spi_remove(struct platform_device *pdev)213{214	struct spi_controller *ctlr;215 216	ctlr = dev_get_drvdata(&pdev->dev);217	spi_unregister_controller(ctlr);218}219 220static struct platform_driver ar934x_spi_driver = {221	.driver = {222		.name = DRIVER_NAME,223		.of_match_table = ar934x_spi_match,224	},225	.probe = ar934x_spi_probe,226	.remove_new = ar934x_spi_remove,227};228 229module_platform_driver(ar934x_spi_driver);230 231MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx");232MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");233MODULE_LICENSE("GPL v2");234MODULE_ALIAS("platform:" DRIVER_NAME);235