1047980c5SChuanhong Guo // SPDX-License-Identifier: GPL-2.0 2047980c5SChuanhong Guo // 3047980c5SChuanhong Guo // SPI controller driver for Qualcomm Atheros AR934x/QCA95xx SoCs 4047980c5SChuanhong Guo // 5047980c5SChuanhong Guo // Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com> 6047980c5SChuanhong Guo // 7047980c5SChuanhong Guo // Based on spi-mt7621.c: 8047980c5SChuanhong Guo // Copyright (C) 2011 Sergiy <piratfm@gmail.com> 9047980c5SChuanhong Guo // Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> 10047980c5SChuanhong Guo // Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> 11047980c5SChuanhong Guo 12047980c5SChuanhong Guo #include <linux/clk.h> 13047980c5SChuanhong Guo #include <linux/io.h> 14047980c5SChuanhong Guo #include <linux/iopoll.h> 15047980c5SChuanhong Guo #include <linux/kernel.h> 16047980c5SChuanhong Guo #include <linux/module.h> 17047980c5SChuanhong Guo #include <linux/of_device.h> 18047980c5SChuanhong Guo #include <linux/spi/spi.h> 19047980c5SChuanhong Guo 20047980c5SChuanhong Guo #define DRIVER_NAME "spi-ar934x" 21047980c5SChuanhong Guo 22047980c5SChuanhong Guo #define AR934X_SPI_REG_FS 0x00 23047980c5SChuanhong Guo #define AR934X_SPI_ENABLE BIT(0) 24047980c5SChuanhong Guo 25047980c5SChuanhong Guo #define AR934X_SPI_REG_IOC 0x08 26047980c5SChuanhong Guo #define AR934X_SPI_IOC_INITVAL 0x70000 27047980c5SChuanhong Guo 28047980c5SChuanhong Guo #define AR934X_SPI_REG_CTRL 0x04 29047980c5SChuanhong Guo #define AR934X_SPI_CLK_MASK GENMASK(5, 0) 30047980c5SChuanhong Guo 31047980c5SChuanhong Guo #define AR934X_SPI_DATAOUT 0x10 32047980c5SChuanhong Guo 33047980c5SChuanhong Guo #define AR934X_SPI_REG_SHIFT_CTRL 0x14 34047980c5SChuanhong Guo #define AR934X_SPI_SHIFT_EN BIT(31) 35047980c5SChuanhong Guo #define AR934X_SPI_SHIFT_CS(n) BIT(28 + (n)) 36047980c5SChuanhong Guo #define AR934X_SPI_SHIFT_TERM 26 37047980c5SChuanhong Guo #define AR934X_SPI_SHIFT_VAL(cs, term, count) \ 38047980c5SChuanhong Guo (AR934X_SPI_SHIFT_EN | AR934X_SPI_SHIFT_CS(cs) | \ 39047980c5SChuanhong Guo (term) << AR934X_SPI_SHIFT_TERM | (count)) 40047980c5SChuanhong Guo 41047980c5SChuanhong Guo #define AR934X_SPI_DATAIN 0x18 42047980c5SChuanhong Guo 43047980c5SChuanhong Guo struct ar934x_spi { 44047980c5SChuanhong Guo struct spi_controller *ctlr; 45047980c5SChuanhong Guo void __iomem *base; 46047980c5SChuanhong Guo struct clk *clk; 47047980c5SChuanhong Guo unsigned int clk_freq; 48047980c5SChuanhong Guo }; 49047980c5SChuanhong Guo 50047980c5SChuanhong Guo static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq) 51047980c5SChuanhong Guo { 52047980c5SChuanhong Guo int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1; 53047980c5SChuanhong Guo 54047980c5SChuanhong Guo if (div < 0) 55047980c5SChuanhong Guo return 0; 56047980c5SChuanhong Guo else if (div > AR934X_SPI_CLK_MASK) 57047980c5SChuanhong Guo return -EINVAL; 58047980c5SChuanhong Guo else 59047980c5SChuanhong Guo return div; 60047980c5SChuanhong Guo } 61047980c5SChuanhong Guo 62047980c5SChuanhong Guo static int ar934x_spi_setup(struct spi_device *spi) 63047980c5SChuanhong Guo { 64047980c5SChuanhong Guo struct ar934x_spi *sp = spi_controller_get_devdata(spi->master); 65047980c5SChuanhong Guo 66047980c5SChuanhong Guo if ((spi->max_speed_hz == 0) || 67047980c5SChuanhong Guo (spi->max_speed_hz > (sp->clk_freq / 2))) { 68047980c5SChuanhong Guo spi->max_speed_hz = sp->clk_freq / 2; 69047980c5SChuanhong Guo } else if (spi->max_speed_hz < (sp->clk_freq / 128)) { 70047980c5SChuanhong Guo dev_err(&spi->dev, "spi clock is too low\n"); 71047980c5SChuanhong Guo return -EINVAL; 72047980c5SChuanhong Guo } 73047980c5SChuanhong Guo 74047980c5SChuanhong Guo return 0; 75047980c5SChuanhong Guo } 76047980c5SChuanhong Guo 77047980c5SChuanhong Guo static int ar934x_spi_transfer_one_message(struct spi_controller *master, 78047980c5SChuanhong Guo struct spi_message *m) 79047980c5SChuanhong Guo { 80047980c5SChuanhong Guo struct ar934x_spi *sp = spi_controller_get_devdata(master); 81047980c5SChuanhong Guo struct spi_transfer *t = NULL; 82047980c5SChuanhong Guo struct spi_device *spi = m->spi; 83047980c5SChuanhong Guo unsigned long trx_done, trx_cur; 84047980c5SChuanhong Guo int stat = 0; 85047980c5SChuanhong Guo u8 term = 0; 86047980c5SChuanhong Guo int div, i; 87047980c5SChuanhong Guo u32 reg; 88047980c5SChuanhong Guo const u8 *tx_buf; 89047980c5SChuanhong Guo u8 *buf; 90047980c5SChuanhong Guo 91047980c5SChuanhong Guo m->actual_length = 0; 92047980c5SChuanhong Guo list_for_each_entry(t, &m->transfers, transfer_list) { 93047980c5SChuanhong Guo if (t->speed_hz) 94047980c5SChuanhong Guo div = ar934x_spi_clk_div(sp, t->speed_hz); 95047980c5SChuanhong Guo else 96047980c5SChuanhong Guo div = ar934x_spi_clk_div(sp, spi->max_speed_hz); 97047980c5SChuanhong Guo if (div < 0) { 98047980c5SChuanhong Guo stat = -EIO; 99047980c5SChuanhong Guo goto msg_done; 100047980c5SChuanhong Guo } 101047980c5SChuanhong Guo 102047980c5SChuanhong Guo reg = ioread32(sp->base + AR934X_SPI_REG_CTRL); 103047980c5SChuanhong Guo reg &= ~AR934X_SPI_CLK_MASK; 104047980c5SChuanhong Guo reg |= div; 105047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL); 106047980c5SChuanhong Guo iowrite32(0, sp->base + AR934X_SPI_DATAOUT); 107047980c5SChuanhong Guo 108047980c5SChuanhong Guo for (trx_done = 0; trx_done < t->len; trx_done += 4) { 109047980c5SChuanhong Guo trx_cur = t->len - trx_done; 110047980c5SChuanhong Guo if (trx_cur > 4) 111047980c5SChuanhong Guo trx_cur = 4; 112047980c5SChuanhong Guo else if (list_is_last(&t->transfer_list, &m->transfers)) 113047980c5SChuanhong Guo term = 1; 114047980c5SChuanhong Guo 115047980c5SChuanhong Guo if (t->tx_buf) { 116047980c5SChuanhong Guo tx_buf = t->tx_buf + trx_done; 117047980c5SChuanhong Guo reg = tx_buf[0]; 118047980c5SChuanhong Guo for (i = 1; i < trx_cur; i++) 119047980c5SChuanhong Guo reg = reg << 8 | tx_buf[i]; 120047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_DATAOUT); 121047980c5SChuanhong Guo } 122047980c5SChuanhong Guo 123047980c5SChuanhong Guo reg = AR934X_SPI_SHIFT_VAL(spi->chip_select, term, 124047980c5SChuanhong Guo trx_cur * 8); 125047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL); 126047980c5SChuanhong Guo stat = readl_poll_timeout( 127047980c5SChuanhong Guo sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg, 128047980c5SChuanhong Guo !(reg & AR934X_SPI_SHIFT_EN), 0, 5); 129047980c5SChuanhong Guo if (stat < 0) 130047980c5SChuanhong Guo goto msg_done; 131047980c5SChuanhong Guo 132047980c5SChuanhong Guo if (t->rx_buf) { 133047980c5SChuanhong Guo reg = ioread32(sp->base + AR934X_SPI_DATAIN); 134047980c5SChuanhong Guo buf = t->rx_buf + trx_done; 135047980c5SChuanhong Guo for (i = 0; i < trx_cur; i++) { 136047980c5SChuanhong Guo buf[trx_cur - i - 1] = reg & 0xff; 137047980c5SChuanhong Guo reg >>= 8; 138047980c5SChuanhong Guo } 139047980c5SChuanhong Guo } 140*c7028245SOskari Lemmela spi_delay_exec(&t->word_delay, t); 141047980c5SChuanhong Guo } 142047980c5SChuanhong Guo m->actual_length += t->len; 143*c7028245SOskari Lemmela spi_transfer_delay_exec(t); 144047980c5SChuanhong Guo } 145047980c5SChuanhong Guo 146047980c5SChuanhong Guo msg_done: 147047980c5SChuanhong Guo m->status = stat; 148047980c5SChuanhong Guo spi_finalize_current_message(master); 149047980c5SChuanhong Guo 150047980c5SChuanhong Guo return 0; 151047980c5SChuanhong Guo } 152047980c5SChuanhong Guo 153047980c5SChuanhong Guo static const struct of_device_id ar934x_spi_match[] = { 154047980c5SChuanhong Guo { .compatible = "qca,ar934x-spi" }, 155047980c5SChuanhong Guo {}, 156047980c5SChuanhong Guo }; 157047980c5SChuanhong Guo MODULE_DEVICE_TABLE(of, ar934x_spi_match); 158047980c5SChuanhong Guo 159047980c5SChuanhong Guo static int ar934x_spi_probe(struct platform_device *pdev) 160047980c5SChuanhong Guo { 161047980c5SChuanhong Guo struct spi_controller *ctlr; 162047980c5SChuanhong Guo struct ar934x_spi *sp; 163047980c5SChuanhong Guo void __iomem *base; 164047980c5SChuanhong Guo struct clk *clk; 165047980c5SChuanhong Guo int ret; 166047980c5SChuanhong Guo 167047980c5SChuanhong Guo base = devm_platform_ioremap_resource(pdev, 0); 168047980c5SChuanhong Guo if (IS_ERR(base)) 169047980c5SChuanhong Guo return PTR_ERR(base); 170047980c5SChuanhong Guo 171047980c5SChuanhong Guo clk = devm_clk_get(&pdev->dev, NULL); 172047980c5SChuanhong Guo if (IS_ERR(clk)) { 173047980c5SChuanhong Guo dev_err(&pdev->dev, "failed to get clock\n"); 174047980c5SChuanhong Guo return PTR_ERR(clk); 175047980c5SChuanhong Guo } 176047980c5SChuanhong Guo 177047980c5SChuanhong Guo ret = clk_prepare_enable(clk); 178047980c5SChuanhong Guo if (ret) 179047980c5SChuanhong Guo return ret; 180047980c5SChuanhong Guo 181236924eeSLukas Wunner ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp)); 182047980c5SChuanhong Guo if (!ctlr) { 183047980c5SChuanhong Guo dev_info(&pdev->dev, "failed to allocate spi controller\n"); 184236924eeSLukas Wunner ret = -ENOMEM; 185236924eeSLukas Wunner goto err_clk_disable; 186047980c5SChuanhong Guo } 187047980c5SChuanhong Guo 188047980c5SChuanhong Guo /* disable flash mapping and expose spi controller registers */ 189047980c5SChuanhong Guo iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS); 190047980c5SChuanhong Guo /* restore pins to default state: CSn=1 DO=CLK=0 */ 191047980c5SChuanhong Guo iowrite32(AR934X_SPI_IOC_INITVAL, base + AR934X_SPI_REG_IOC); 192047980c5SChuanhong Guo 193047980c5SChuanhong Guo ctlr->mode_bits = SPI_LSB_FIRST; 194047980c5SChuanhong Guo ctlr->setup = ar934x_spi_setup; 195047980c5SChuanhong Guo ctlr->transfer_one_message = ar934x_spi_transfer_one_message; 196047980c5SChuanhong Guo ctlr->bits_per_word_mask = SPI_BPW_MASK(8); 197047980c5SChuanhong Guo ctlr->dev.of_node = pdev->dev.of_node; 198047980c5SChuanhong Guo ctlr->num_chipselect = 3; 199047980c5SChuanhong Guo 200047980c5SChuanhong Guo dev_set_drvdata(&pdev->dev, ctlr); 201047980c5SChuanhong Guo 202047980c5SChuanhong Guo sp = spi_controller_get_devdata(ctlr); 203047980c5SChuanhong Guo sp->base = base; 204047980c5SChuanhong Guo sp->clk = clk; 205047980c5SChuanhong Guo sp->clk_freq = clk_get_rate(clk); 206047980c5SChuanhong Guo sp->ctlr = ctlr; 207047980c5SChuanhong Guo 208236924eeSLukas Wunner ret = spi_register_controller(ctlr); 209236924eeSLukas Wunner if (!ret) 210236924eeSLukas Wunner return 0; 211236924eeSLukas Wunner 212236924eeSLukas Wunner err_clk_disable: 213236924eeSLukas Wunner clk_disable_unprepare(clk); 214236924eeSLukas Wunner return ret; 215047980c5SChuanhong Guo } 216047980c5SChuanhong Guo 217047980c5SChuanhong Guo static int ar934x_spi_remove(struct platform_device *pdev) 218047980c5SChuanhong Guo { 219047980c5SChuanhong Guo struct spi_controller *ctlr; 220047980c5SChuanhong Guo struct ar934x_spi *sp; 221047980c5SChuanhong Guo 222047980c5SChuanhong Guo ctlr = dev_get_drvdata(&pdev->dev); 223047980c5SChuanhong Guo sp = spi_controller_get_devdata(ctlr); 224047980c5SChuanhong Guo 225236924eeSLukas Wunner spi_unregister_controller(ctlr); 226047980c5SChuanhong Guo clk_disable_unprepare(sp->clk); 227047980c5SChuanhong Guo 228047980c5SChuanhong Guo return 0; 229047980c5SChuanhong Guo } 230047980c5SChuanhong Guo 231047980c5SChuanhong Guo static struct platform_driver ar934x_spi_driver = { 232047980c5SChuanhong Guo .driver = { 233047980c5SChuanhong Guo .name = DRIVER_NAME, 234047980c5SChuanhong Guo .of_match_table = ar934x_spi_match, 235047980c5SChuanhong Guo }, 236047980c5SChuanhong Guo .probe = ar934x_spi_probe, 237047980c5SChuanhong Guo .remove = ar934x_spi_remove, 238047980c5SChuanhong Guo }; 239047980c5SChuanhong Guo 240047980c5SChuanhong Guo module_platform_driver(ar934x_spi_driver); 241047980c5SChuanhong Guo 242047980c5SChuanhong Guo MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx"); 243047980c5SChuanhong Guo MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>"); 244047980c5SChuanhong Guo MODULE_LICENSE("GPL v2"); 245047980c5SChuanhong Guo MODULE_ALIAS("platform:" DRIVER_NAME); 246