^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * SH SCI SPI interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2008 Magnus Damm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on S3C24XX GPIO based SPI driver, which is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (c) 2006 Ben Dooks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 2006 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/spi/spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/spi/spi_bitbang.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct sh_sci_spi {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct spi_bitbang bitbang;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void __iomem *membase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct sh_spi_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct platform_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define SCSPTR(sp) (sp->membase + 0x1c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define PIN_SCK (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define PIN_TXD (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define PIN_RXD PIN_TXD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * We are the only user of SCSPTR so no locking is required.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Reading bit 2 and 0 in SCSPTR gives pin state as input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Writing the same bits sets the output value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * This makes regular read-modify-write difficult so we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * use sp->val to keep track of the latest register value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) sp->val |= bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) sp->val &= ~bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) iowrite8(sp->val, SCSPTR(sp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static inline void setsck(struct spi_device *dev, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static inline void setmosi(struct spi_device *dev, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static inline u32 getmiso(struct spi_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define spidelay(x) ndelay(x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #include "spi-bitbang-txrx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) unsigned nsecs, u32 word, u8 bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) unsigned nsecs, u32 word, u8 bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned nsecs, u32 word, u8 bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) unsigned flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned nsecs, u32 word, u8 bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) unsigned flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (sp->info->chip_select)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) (sp->info->chip_select)(sp->info, dev->chip_select, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static int sh_sci_spi_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct resource *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct spi_master *master;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct sh_sci_spi *sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (master == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) dev_err(&dev->dev, "failed to allocate spi master\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) goto err0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) sp = spi_master_get_devdata(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) platform_set_drvdata(dev, sp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) sp->info = dev_get_platdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!sp->info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) dev_err(&dev->dev, "platform data is missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* setup spi bitbang adaptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) sp->bitbang.master = master;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) sp->bitbang.master->bus_num = sp->info->bus_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) sp->bitbang.chipselect = sh_sci_spi_chipselect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) r = platform_get_resource(dev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (r == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) sp->membase = ioremap(r->start, resource_size(r));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!sp->membase) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) sp->val = ioread8(SCSPTR(sp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) setbits(sp, PIN_INIT, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) ret = spi_bitbang_start(&sp->bitbang);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) setbits(sp, PIN_INIT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) iounmap(sp->membase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) err1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) spi_master_put(sp->bitbang.master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) err0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int sh_sci_spi_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct sh_sci_spi *sp = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) spi_bitbang_stop(&sp->bitbang);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) setbits(sp, PIN_INIT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) iounmap(sp->membase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) spi_master_put(sp->bitbang.master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static struct platform_driver sh_sci_spi_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .probe = sh_sci_spi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .remove = sh_sci_spi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .name = "spi_sh_sci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) module_platform_driver(sh_sci_spi_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) MODULE_DESCRIPTION("SH SCI SPI Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) MODULE_ALIAS("platform:spi_sh_sci");