brintos

brintos / linux-shallow public Read only

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