cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spi-sh-sci.c (4784B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * SH SCI SPI interface
      4 *
      5 * Copyright (c) 2008 Magnus Damm
      6 *
      7 * Based on S3C24XX GPIO based SPI driver, which is:
      8 *   Copyright (c) 2006 Ben Dooks
      9 *   Copyright (c) 2006 Simtec Electronics
     10 */
     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_TXD
     37#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 we
     46	 * use sp->val to keep track of the latest register value.
     47	 */
     48
     49	if (on)
     50		sp->val |= bits;
     51	else
     52		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_master_get_devdata(dev->master), PIN_SCK, on);
     60}
     61
     62static inline void setmosi(struct spi_device *dev, int on)
     63{
     64	setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
     65}
     66
     67static inline u32 getmiso(struct spi_device *dev)
     68{
     69	struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
     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_master_get_devdata(dev->master);
    109
    110	if (sp->info->chip_select)
    111		(sp->info->chip_select)(sp->info, dev->chip_select, value);
    112}
    113
    114static int sh_sci_spi_probe(struct platform_device *dev)
    115{
    116	struct resource	*r;
    117	struct spi_master *master;
    118	struct sh_sci_spi *sp;
    119	int ret;
    120
    121	master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
    122	if (master == NULL) {
    123		dev_err(&dev->dev, "failed to allocate spi master\n");
    124		ret = -ENOMEM;
    125		goto err0;
    126	}
    127
    128	sp = spi_master_get_devdata(master);
    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.master = master;
    140	sp->bitbang.master->bus_num = sp->info->bus_num;
    141	sp->bitbang.master->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_master_put(sp->bitbang.master);
    170 err0:
    171	return ret;
    172}
    173
    174static int 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_master_put(sp->bitbang.master);
    182	return 0;
    183}
    184
    185static struct platform_driver sh_sci_spi_drv = {
    186	.probe		= sh_sci_spi_probe,
    187	.remove		= sh_sci_spi_remove,
    188	.driver		= {
    189		.name	= "spi_sh_sci",
    190	},
    191};
    192module_platform_driver(sh_sci_spi_drv);
    193
    194MODULE_DESCRIPTION("SH SCI SPI Driver");
    195MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
    196MODULE_LICENSE("GPL");
    197MODULE_ALIAS("platform:spi_sh_sci");