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; 85*ebe33e5aSOskari Lemmela u8 bpw, 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) { 93*ebe33e5aSOskari Lemmela if (t->bits_per_word >= 8 && t->bits_per_word < 32) 94*ebe33e5aSOskari Lemmela bpw = t->bits_per_word >> 3; 95*ebe33e5aSOskari Lemmela else 96*ebe33e5aSOskari Lemmela bpw = 4; 97*ebe33e5aSOskari Lemmela 98047980c5SChuanhong Guo if (t->speed_hz) 99047980c5SChuanhong Guo div = ar934x_spi_clk_div(sp, t->speed_hz); 100047980c5SChuanhong Guo else 101047980c5SChuanhong Guo div = ar934x_spi_clk_div(sp, spi->max_speed_hz); 102047980c5SChuanhong Guo if (div < 0) { 103047980c5SChuanhong Guo stat = -EIO; 104047980c5SChuanhong Guo goto msg_done; 105047980c5SChuanhong Guo } 106047980c5SChuanhong Guo 107047980c5SChuanhong Guo reg = ioread32(sp->base + AR934X_SPI_REG_CTRL); 108047980c5SChuanhong Guo reg &= ~AR934X_SPI_CLK_MASK; 109047980c5SChuanhong Guo reg |= div; 110047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL); 111047980c5SChuanhong Guo iowrite32(0, sp->base + AR934X_SPI_DATAOUT); 112047980c5SChuanhong Guo 113*ebe33e5aSOskari Lemmela for (trx_done = 0; trx_done < t->len; trx_done += bpw) { 114047980c5SChuanhong Guo trx_cur = t->len - trx_done; 115*ebe33e5aSOskari Lemmela if (trx_cur > bpw) 116*ebe33e5aSOskari Lemmela trx_cur = bpw; 117047980c5SChuanhong Guo else if (list_is_last(&t->transfer_list, &m->transfers)) 118047980c5SChuanhong Guo term = 1; 119047980c5SChuanhong Guo 120047980c5SChuanhong Guo if (t->tx_buf) { 121047980c5SChuanhong Guo tx_buf = t->tx_buf + trx_done; 122047980c5SChuanhong Guo reg = tx_buf[0]; 123047980c5SChuanhong Guo for (i = 1; i < trx_cur; i++) 124047980c5SChuanhong Guo reg = reg << 8 | tx_buf[i]; 125047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_DATAOUT); 126047980c5SChuanhong Guo } 127047980c5SChuanhong Guo 128047980c5SChuanhong Guo reg = AR934X_SPI_SHIFT_VAL(spi->chip_select, term, 129047980c5SChuanhong Guo trx_cur * 8); 130047980c5SChuanhong Guo iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL); 131047980c5SChuanhong Guo stat = readl_poll_timeout( 132047980c5SChuanhong Guo sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg, 133047980c5SChuanhong Guo !(reg & AR934X_SPI_SHIFT_EN), 0, 5); 134047980c5SChuanhong Guo if (stat < 0) 135047980c5SChuanhong Guo goto msg_done; 136047980c5SChuanhong Guo 137047980c5SChuanhong Guo if (t->rx_buf) { 138047980c5SChuanhong Guo reg = ioread32(sp->base + AR934X_SPI_DATAIN); 139047980c5SChuanhong Guo buf = t->rx_buf + trx_done; 140047980c5SChuanhong Guo for (i = 0; i < trx_cur; i++) { 141047980c5SChuanhong Guo buf[trx_cur - i - 1] = reg & 0xff; 142047980c5SChuanhong Guo reg >>= 8; 143047980c5SChuanhong Guo } 144047980c5SChuanhong Guo } 145c7028245SOskari Lemmela spi_delay_exec(&t->word_delay, t); 146047980c5SChuanhong Guo } 147047980c5SChuanhong Guo m->actual_length += t->len; 148c7028245SOskari Lemmela spi_transfer_delay_exec(t); 149047980c5SChuanhong Guo } 150047980c5SChuanhong Guo 151047980c5SChuanhong Guo msg_done: 152047980c5SChuanhong Guo m->status = stat; 153047980c5SChuanhong Guo spi_finalize_current_message(master); 154047980c5SChuanhong Guo 155047980c5SChuanhong Guo return 0; 156047980c5SChuanhong Guo } 157047980c5SChuanhong Guo 158047980c5SChuanhong Guo static const struct of_device_id ar934x_spi_match[] = { 159047980c5SChuanhong Guo { .compatible = "qca,ar934x-spi" }, 160047980c5SChuanhong Guo {}, 161047980c5SChuanhong Guo }; 162047980c5SChuanhong Guo MODULE_DEVICE_TABLE(of, ar934x_spi_match); 163047980c5SChuanhong Guo 164047980c5SChuanhong Guo static int ar934x_spi_probe(struct platform_device *pdev) 165047980c5SChuanhong Guo { 166047980c5SChuanhong Guo struct spi_controller *ctlr; 167047980c5SChuanhong Guo struct ar934x_spi *sp; 168047980c5SChuanhong Guo void __iomem *base; 169047980c5SChuanhong Guo struct clk *clk; 170047980c5SChuanhong Guo int ret; 171047980c5SChuanhong Guo 172047980c5SChuanhong Guo base = devm_platform_ioremap_resource(pdev, 0); 173047980c5SChuanhong Guo if (IS_ERR(base)) 174047980c5SChuanhong Guo return PTR_ERR(base); 175047980c5SChuanhong Guo 176047980c5SChuanhong Guo clk = devm_clk_get(&pdev->dev, NULL); 177047980c5SChuanhong Guo if (IS_ERR(clk)) { 178047980c5SChuanhong Guo dev_err(&pdev->dev, "failed to get clock\n"); 179047980c5SChuanhong Guo return PTR_ERR(clk); 180047980c5SChuanhong Guo } 181047980c5SChuanhong Guo 182047980c5SChuanhong Guo ret = clk_prepare_enable(clk); 183047980c5SChuanhong Guo if (ret) 184047980c5SChuanhong Guo return ret; 185047980c5SChuanhong Guo 186236924eeSLukas Wunner ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp)); 187047980c5SChuanhong Guo if (!ctlr) { 188047980c5SChuanhong Guo dev_info(&pdev->dev, "failed to allocate spi controller\n"); 189236924eeSLukas Wunner ret = -ENOMEM; 190236924eeSLukas Wunner goto err_clk_disable; 191047980c5SChuanhong Guo } 192047980c5SChuanhong Guo 193047980c5SChuanhong Guo /* disable flash mapping and expose spi controller registers */ 194047980c5SChuanhong Guo iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS); 195047980c5SChuanhong Guo /* restore pins to default state: CSn=1 DO=CLK=0 */ 196047980c5SChuanhong Guo iowrite32(AR934X_SPI_IOC_INITVAL, base + AR934X_SPI_REG_IOC); 197047980c5SChuanhong Guo 198047980c5SChuanhong Guo ctlr->mode_bits = SPI_LSB_FIRST; 199047980c5SChuanhong Guo ctlr->setup = ar934x_spi_setup; 200047980c5SChuanhong Guo ctlr->transfer_one_message = ar934x_spi_transfer_one_message; 201*ebe33e5aSOskari Lemmela ctlr->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | 202*ebe33e5aSOskari Lemmela SPI_BPW_MASK(16) | SPI_BPW_MASK(8); 203047980c5SChuanhong Guo ctlr->dev.of_node = pdev->dev.of_node; 204047980c5SChuanhong Guo ctlr->num_chipselect = 3; 205047980c5SChuanhong Guo 206047980c5SChuanhong Guo dev_set_drvdata(&pdev->dev, ctlr); 207047980c5SChuanhong Guo 208047980c5SChuanhong Guo sp = spi_controller_get_devdata(ctlr); 209047980c5SChuanhong Guo sp->base = base; 210047980c5SChuanhong Guo sp->clk = clk; 211047980c5SChuanhong Guo sp->clk_freq = clk_get_rate(clk); 212047980c5SChuanhong Guo sp->ctlr = ctlr; 213047980c5SChuanhong Guo 214236924eeSLukas Wunner ret = spi_register_controller(ctlr); 215236924eeSLukas Wunner if (!ret) 216236924eeSLukas Wunner return 0; 217236924eeSLukas Wunner 218236924eeSLukas Wunner err_clk_disable: 219236924eeSLukas Wunner clk_disable_unprepare(clk); 220236924eeSLukas Wunner return ret; 221047980c5SChuanhong Guo } 222047980c5SChuanhong Guo 223047980c5SChuanhong Guo static int ar934x_spi_remove(struct platform_device *pdev) 224047980c5SChuanhong Guo { 225047980c5SChuanhong Guo struct spi_controller *ctlr; 226047980c5SChuanhong Guo struct ar934x_spi *sp; 227047980c5SChuanhong Guo 228047980c5SChuanhong Guo ctlr = dev_get_drvdata(&pdev->dev); 229047980c5SChuanhong Guo sp = spi_controller_get_devdata(ctlr); 230047980c5SChuanhong Guo 231236924eeSLukas Wunner spi_unregister_controller(ctlr); 232047980c5SChuanhong Guo clk_disable_unprepare(sp->clk); 233047980c5SChuanhong Guo 234047980c5SChuanhong Guo return 0; 235047980c5SChuanhong Guo } 236047980c5SChuanhong Guo 237047980c5SChuanhong Guo static struct platform_driver ar934x_spi_driver = { 238047980c5SChuanhong Guo .driver = { 239047980c5SChuanhong Guo .name = DRIVER_NAME, 240047980c5SChuanhong Guo .of_match_table = ar934x_spi_match, 241047980c5SChuanhong Guo }, 242047980c5SChuanhong Guo .probe = ar934x_spi_probe, 243047980c5SChuanhong Guo .remove = ar934x_spi_remove, 244047980c5SChuanhong Guo }; 245047980c5SChuanhong Guo 246047980c5SChuanhong Guo module_platform_driver(ar934x_spi_driver); 247047980c5SChuanhong Guo 248047980c5SChuanhong Guo MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx"); 249047980c5SChuanhong Guo MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>"); 250047980c5SChuanhong Guo MODULE_LICENSE("GPL v2"); 251047980c5SChuanhong Guo MODULE_ALIAS("platform:" DRIVER_NAME); 252