142421Syokota// SPDX-License-Identifier: GPL-2.0-only 242421Syokota/* 342421Syokota * SPI controller driver for the Mikrotik RB4xx boards 442421Syokota * 542421Syokota * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> 642421Syokota * Copyright (C) 2015 Bert Vermeulen <bert@biot.com> 742421Syokota * 842421Syokota * This file was based on the patches for Linux 2.6.27.39 published by 942421Syokota * MikroTik for their RouterBoard 4xx series devices. 1042421Syokota */ 1142421Syokota 1242421Syokota#include <linux/kernel.h> 1342421Syokota#include <linux/module.h> 1442421Syokota#include <linux/platform_device.h> 1542421Syokota#include <linux/clk.h> 1642421Syokota#include <linux/spi/spi.h> 1742421Syokota#include <linux/of.h> 1842421Syokota 1942421Syokota#include <asm/mach-ath79/ar71xx_regs.h> 2042421Syokota 2142421Syokotastruct rb4xx_spi { 2242421Syokota void __iomem *base; 2342421Syokota struct clk *clk; 2442421Syokota}; 2542421Syokota 2642421Syokotastatic inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg) 2742421Syokota{ 2842421Syokota return __raw_readl(rbspi->base + reg); 2942421Syokota} 3050477Speter 3142421Syokotastatic inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value) 3242421Syokota{ 3342421Syokota __raw_writel(value, rbspi->base + reg); 3442421Syokota} 3542421Syokota 3642421Syokotastatic inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value) 37105181Sphk{ 38105181Sphk u32 regval; 3942421Syokota 4042421Syokota regval = spi_ioc; 4142421Syokota if (value & BIT(0)) 4242421Syokota regval |= AR71XX_SPI_IOC_DO; 4342421Syokota 4442421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); 4542421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); 4642421Syokota} 4742421Syokota 4842421Syokotastatic void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) 4942421Syokota{ 5042421Syokota int i; 5142421Syokota 5242421Syokota for (i = 7; i >= 0; i--) 5342421Syokota do_spi_clk(rbspi, spi_ioc, byte >> i); 5442421Syokota} 5542421Syokota 5642421Syokota/* The CS2 pin is used to clock in a second bit per clock cycle. */ 5742421Syokotastatic inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc, 5842421Syokota u8 value) 5942421Syokota{ 6042421Syokota u32 regval; 6142421Syokota 6242421Syokota regval = spi_ioc; 6342421Syokota if (value & BIT(1)) 6442421Syokota regval |= AR71XX_SPI_IOC_DO; 6542421Syokota if (value & BIT(0)) 6642421Syokota regval |= AR71XX_SPI_IOC_CS2; 6742421Syokota 6842421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval); 6942421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK); 7042421Syokota} 7142421Syokota 7242421Syokota/* Two bits at a time, msb first */ 7342421Syokotastatic void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte) 7442421Syokota{ 7542421Syokota do_spi_clk_two(rbspi, spi_ioc, byte >> 6); 7642421Syokota do_spi_clk_two(rbspi, spi_ioc, byte >> 4); 7742421Syokota do_spi_clk_two(rbspi, spi_ioc, byte >> 2); 7842421Syokota do_spi_clk_two(rbspi, spi_ioc, byte >> 0); 7942421Syokota} 8042421Syokota 8142421Syokotastatic void rb4xx_set_cs(struct spi_device *spi, bool enable) 8242421Syokota{ 8342421Syokota struct rb4xx_spi *rbspi = spi_controller_get_devdata(spi->controller); 8442421Syokota 8542421Syokota /* 8642421Syokota * Setting CS is done along with bitbanging the actual values, 8742421Syokota * since it's all on the same hardware register. However the 8842421Syokota * CPLD needs CS deselected after every command. 8942421Syokota */ 9042421Syokota if (enable) 9142421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, 9242421Syokota AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1); 9342421Syokota} 9442421Syokota 9542421Syokotastatic int rb4xx_transfer_one(struct spi_controller *host, 9642421Syokota struct spi_device *spi, struct spi_transfer *t) 9742421Syokota{ 9842421Syokota struct rb4xx_spi *rbspi = spi_controller_get_devdata(host); 9942421Syokota int i; 10042421Syokota u32 spi_ioc; 10142421Syokota u8 *rx_buf; 10242421Syokota const u8 *tx_buf; 10342421Syokota 10442421Syokota /* 10542421Syokota * Prime the SPI register with the SPI device selected. The m25p80 boot 10642421Syokota * flash and CPLD share the CS0 pin. This works because the CPLD's 10742421Syokota * command set was designed to almost not clash with that of the 10842421Syokota * boot flash. 10942421Syokota */ 11042421Syokota if (spi_get_chipselect(spi, 0) == 2) 11142421Syokota /* MMC */ 11242421Syokota spi_ioc = AR71XX_SPI_IOC_CS0; 11342421Syokota else 11442421Syokota /* Boot flash and CPLD */ 11542421Syokota spi_ioc = AR71XX_SPI_IOC_CS1; 11642421Syokota 11742421Syokota tx_buf = t->tx_buf; 11842421Syokota rx_buf = t->rx_buf; 11942421Syokota for (i = 0; i < t->len; ++i) { 12042421Syokota if (t->tx_nbits == SPI_NBITS_DUAL) 12142421Syokota /* CPLD can use two-wire transfers */ 12242421Syokota do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]); 12342421Syokota else 12442421Syokota do_spi_byte(rbspi, spi_ioc, tx_buf[i]); 12542421Syokota if (!rx_buf) 12642421Syokota continue; 12742421Syokota rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS); 12842421Syokota } 12942421Syokota spi_finalize_current_transfer(host); 13042421Syokota 13142421Syokota return 0; 13242421Syokota} 13342421Syokota 13442421Syokotastatic int rb4xx_spi_probe(struct platform_device *pdev) 13542421Syokota{ 13642421Syokota struct spi_controller *host; 13758230Syokota struct clk *ahb_clk; 13858230Syokota struct rb4xx_spi *rbspi; 13958230Syokota int err; 14042421Syokota void __iomem *spi_base; 14155205Speter 14242421Syokota spi_base = devm_platform_ioremap_resource(pdev, 0); 14342421Syokota if (IS_ERR(spi_base)) 14442421Syokota return PTR_ERR(spi_base); 14542421Syokota 14642421Syokota host = devm_spi_alloc_host(&pdev->dev, sizeof(*rbspi)); 14742421Syokota if (!host) 14842421Syokota return -ENOMEM; 14942421Syokota 15042421Syokota ahb_clk = devm_clk_get(&pdev->dev, "ahb"); 15142421Syokota if (IS_ERR(ahb_clk)) 15242421Syokota return PTR_ERR(ahb_clk); 15342421Syokota 15442421Syokota host->dev.of_node = pdev->dev.of_node; 15542421Syokota host->bus_num = 0; 15642421Syokota host->num_chipselect = 3; 15742421Syokota host->mode_bits = SPI_TX_DUAL; 15842421Syokota host->bits_per_word_mask = SPI_BPW_MASK(8); 15942421Syokota host->flags = SPI_CONTROLLER_MUST_TX; 16042421Syokota host->transfer_one = rb4xx_transfer_one; 16142421Syokota host->set_cs = rb4xx_set_cs; 16242421Syokota 16342421Syokota rbspi = spi_controller_get_devdata(host); 16442421Syokota rbspi->base = spi_base; 16542421Syokota rbspi->clk = ahb_clk; 16642421Syokota platform_set_drvdata(pdev, rbspi); 16742421Syokota 16842421Syokota err = devm_spi_register_controller(&pdev->dev, host); 16942421Syokota if (err) { 17042421Syokota dev_err(&pdev->dev, "failed to register SPI host\n"); 17142421Syokota return err; 17242421Syokota } 17342421Syokota 17442421Syokota err = clk_prepare_enable(ahb_clk); 17542421Syokota if (err) 17642421Syokota return err; 17742421Syokota 17842421Syokota /* Enable SPI */ 17942421Syokota rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); 18042421Syokota 18142421Syokota return 0; 18242421Syokota} 18342421Syokota 18442421Syokotastatic void rb4xx_spi_remove(struct platform_device *pdev) 18542421Syokota{ 18642421Syokota struct rb4xx_spi *rbspi = platform_get_drvdata(pdev); 18742421Syokota 18842421Syokota clk_disable_unprepare(rbspi->clk); 18958271Syokota} 19058271Syokota 19142421Syokotastatic const struct of_device_id rb4xx_spi_dt_match[] = { 19258271Syokota { .compatible = "mikrotik,rb4xx-spi" }, 19358271Syokota { }, 19458271Syokota}; 19558271SyokotaMODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match); 19658271Syokota 19742421Syokotastatic struct platform_driver rb4xx_spi_drv = { 19842421Syokota .probe = rb4xx_spi_probe, 19942421Syokota .remove_new = rb4xx_spi_remove, 20042421Syokota .driver = { 20142421Syokota .name = "rb4xx-spi", 20242421Syokota .of_match_table = of_match_ptr(rb4xx_spi_dt_match), 20342421Syokota }, 20442421Syokota}; 20558271Syokota 20658271Syokotamodule_platform_driver(rb4xx_spi_drv); 20758271Syokota 20858271SyokotaMODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver"); 20942421SyokotaMODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); 21042421SyokotaMODULE_AUTHOR("Bert Vermeulen <bert@biot.com>"); 21142421SyokotaMODULE_LICENSE("GPL v2"); 21242421Syokota