1ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely/* 27fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * Copyright (c) 2006 Ben Dooks 3bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Copyright 2006-2009 Simtec Electronics 47fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * Ben Dooks <ben@simtec.co.uk> 57fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * 67fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * This program is free software; you can redistribute it and/or modify 77fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * it under the terms of the GNU General Public License version 2 as 87fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * published by the Free Software Foundation. 97fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * 107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks*/ 117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spinlock.h> 137fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/interrupt.h> 147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/delay.h> 157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/errno.h> 167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/err.h> 177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/clk.h> 187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/platform_device.h> 19ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks#include <linux/gpio.h> 201a0c220f791be9e15fd897adee257e72ed4134f8Ben Dooks#include <linux/io.h> 215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spi/spi.h> 247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spi/spi_bitbang.h> 25f35ef7cab2db0a8b577bef59122b59220efdac44Heiko Stuebner#include <linux/spi/s3c24xx.h> 26d7614de422c0b55db0c1013a6c72330187536004Paul Gortmaker#include <linux/module.h> 277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 2813622708725990b01fbc6d59d54d93820a726d7cBen Dooks#include <plat/regs-spi.h> 297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 30bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#include <asm/fiq.h> 31bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 32ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely#include "spi-s3c24xx-fiq.h" 33bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 34570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks/** 35570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * s3c24xx_spi_devstate - per device data 36570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @hz: Last frequency calculated for @sppre field. 37570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @mode: Last mode setting for the @spcon field. 38570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @spcon: Value to write to the SPCON register. 39570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @sppre: Value to write to the SPPRE register. 40570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks */ 41570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstruct s3c24xx_spi_devstate { 42570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks unsigned int hz; 43570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks unsigned int mode; 44570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks u8 spcon; 45570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks u8 sppre; 46570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks}; 47570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 48bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksenum spi_fiq_mode { 49bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks FIQ_MODE_NONE = 0, 50bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks FIQ_MODE_TX = 1, 51bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks FIQ_MODE_RX = 2, 52bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks FIQ_MODE_TXRX = 3, 53bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}; 54bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 557fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstruct s3c24xx_spi { 567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* bitbang has to be first */ 577fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct spi_bitbang bitbang; 587fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct completion done; 597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks void __iomem *regs; 617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks int irq; 627fba53402eb0fb4209c74469814c583b6455e096Ben Dooks int len; 637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks int count; 647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 65bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks struct fiq_handler fiq_handler; 66bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks enum spi_fiq_mode fiq_mode; 67bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks unsigned char fiq_inuse; 68bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks unsigned char fiq_claimed; 69bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 706c912a3d3356e5e51917941ce8505531c6fab003Arnaud Patard void (*set_cs)(struct s3c2410_spi_info *spi, 718736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks int cs, int pol); 728736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks 737fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* data buffers */ 747fba53402eb0fb4209c74469814c583b6455e096Ben Dooks const unsigned char *tx; 757fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned char *rx; 767fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 777fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct clk *clk; 787fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct spi_master *master; 797fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct spi_device *curdev; 807fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct device *dev; 817fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c2410_spi_info *pdata; 827fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}; 837fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 847fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) 857fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) 867fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 877fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) 887fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 897fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return spi_master_get_devdata(sdev->master); 907fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 917fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 928736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooksstatic void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) 938736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks{ 94ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks gpio_set_value(spi->pin_cs, pol); 958736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks} 968736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks 977fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic void s3c24xx_spi_chipsel(struct spi_device *spi, int value) 987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 99570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi_devstate *cs = spi->controller_state; 1007fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw = to_hw(spi); 1017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; 102570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 103570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks /* change the chipselect state and the state of the spi engine clock */ 1047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 1057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks switch (value) { 1067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks case BITBANG_CS_INACTIVE: 1073d2c5b415ccd6c322e18adaed3a5b21f7ec555efBen Dooks hw->set_cs(hw->pdata, spi->chip_select, cspol^1); 108570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks writeb(cs->spcon, hw->regs + S3C2410_SPCON); 1097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks break; 1107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 1117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks case BITBANG_CS_ACTIVE: 112570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks writeb(cs->spcon | S3C2410_SPCON_ENSCK, 113570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks hw->regs + S3C2410_SPCON); 1143d2c5b415ccd6c322e18adaed3a5b21f7ec555efBen Dooks hw->set_cs(hw->pdata, spi->chip_select, cspol); 1157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks break; 1167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 1177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 1187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 119570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstatic int s3c24xx_spi_update_state(struct spi_device *spi, 120570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct spi_transfer *t) 1217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 1227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw = to_hw(spi); 123570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi_devstate *cs = spi->controller_state; 1247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned int hz; 1257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned int div; 126b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks unsigned long clk; 1277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 1287fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hz = t ? t->speed_hz : spi->max_speed_hz; 1297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 130191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks if (!hz) 131191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks hz = spi->max_speed_hz; 132191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks 133570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (spi->mode != cs->mode) { 134bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; 135570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 136570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (spi->mode & SPI_CPHA) 137570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks spcon |= S3C2410_SPCON_CPHA_FMTB; 1387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 139570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (spi->mode & SPI_CPOL) 140570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks spcon |= S3C2410_SPCON_CPOL_HIGH; 1417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 142570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->mode = spi->mode; 143570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->spcon = spcon; 144570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks } 145b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks 146570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (cs->hz != hz) { 147570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks clk = clk_get_rate(hw->clk); 148570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks div = DIV_ROUND_UP(clk, hz * 2) - 1; 149b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks 150570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (div > 255) 151570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks div = 255; 1527fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 153570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n", 154570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks div, hz, clk / (2 * (div + 1))); 155570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 156570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->hz = hz; 157570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->sppre = div; 1587fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 1597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 1607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return 0; 1617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 1627fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 163570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstatic int s3c24xx_spi_setupxfer(struct spi_device *spi, 164570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct spi_transfer *t) 165570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks{ 166570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi_devstate *cs = spi->controller_state; 167570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi *hw = to_hw(spi); 168570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks int ret; 169570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 170570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks ret = s3c24xx_spi_update_state(spi, t); 171570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (!ret) 172570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks writeb(cs->sppre, hw->regs + S3C2410_SPPRE); 173570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 174570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks return ret; 175570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks} 176570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 1777fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic int s3c24xx_spi_setup(struct spi_device *spi) 1787fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 179570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi_devstate *cs = spi->controller_state; 180570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks struct s3c24xx_spi *hw = to_hw(spi); 1817fba53402eb0fb4209c74469814c583b6455e096Ben Dooks int ret; 1827fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 183570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks /* allocate settings on the first call */ 184570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (!cs) { 185c586feba880d78cab1882e1faee0395bba2b884fAxel Lin cs = devm_kzalloc(&spi->dev, 186c586feba880d78cab1882e1faee0395bba2b884fAxel Lin sizeof(struct s3c24xx_spi_devstate), 187c586feba880d78cab1882e1faee0395bba2b884fAxel Lin GFP_KERNEL); 1880375cff5d8c9da86787167da2740b6e5c50963daJingoo Han if (!cs) 189570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks return -ENOMEM; 190570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 191570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->spcon = SPCON_DEFAULT; 192570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks cs->hz = -1; 193570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks spi->controller_state = cs; 194570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks } 195570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 196570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks /* initialise the state from the device */ 197570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks ret = s3c24xx_spi_update_state(spi, NULL); 198570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (ret) 1997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return ret; 200570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 201570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks spin_lock(&hw->bitbang.lock); 202570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks if (!hw->bitbang.busy) { 203570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); 204570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks /* need to ndelay for 0.5 clocktick ? */ 2057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 206570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks spin_unlock(&hw->bitbang.lock); 2077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 2087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return 0; 2097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 2107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 2117fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) 2127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 2134b1badf5d9ddfc46ad075ca5bfc465972c85cc7cDavid Brownell return hw->tx ? hw->tx[count] : 0; 2147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 2157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 216bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#ifdef CONFIG_SPI_S3C24XX_FIQ 217bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/* Support for FIQ based pseudo-DMA to improve the transfer speed. 218bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 219bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * This code uses the assembly helper in spi_s3c24xx_spi.S which is 220bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * used by the FIQ core to move data between main memory and the peripheral 221bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * block. Since this is code running on the processor, there is no problem 222bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * with cache coherency of the buffers, so we can use any buffer we like. 223bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 224bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 225bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 226bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * struct spi_fiq_code - FIQ code and header 227bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @length: The length of the code fragment, excluding this header. 228bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at. 229bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @data: The code itself to install as a FIQ handler. 230bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 231bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstruct spi_fiq_code { 232bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks u32 length; 233bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks u32 ack_offset; 234bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks u8 data[0]; 235bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}; 236bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 237bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_txrx; 238bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_tx; 239bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_rx; 240bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 241bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 242bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * ack_bit - turn IRQ into IRQ acknowledgement bit 243bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @irq: The interrupt number 244bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 245bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Returns the bit to write to the interrupt acknowledge register. 246bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 247bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline u32 ack_bit(unsigned int irq) 248bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 249bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks return 1 << (irq - IRQ_EINT0); 250bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 251bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 252bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 253bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer 254bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state. 255bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 256bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Claim the FIQ handler (only one can be active at any one time) and 257bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * then setup the correct transfer code for this transfer. 258bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 2593ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack * This call updates all the necessary state information if successful, 260bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * so the caller does not need to do anything more than start the transfer 261bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * as normal, since the IRQ will have been re-routed to the FIQ handler. 262bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks*/ 263cfeb33127bfd5c248c8633715d75c04186d8fca9Sachin Kamatstatic void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) 264bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 265bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks struct pt_regs regs; 266bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks enum spi_fiq_mode mode; 267bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks struct spi_fiq_code *code; 268bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks int ret; 269bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 270bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (!hw->fiq_claimed) { 271bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks /* try and claim fiq if we haven't got it, and if not 272bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * then return and simply use another transfer method */ 273bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 274bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks ret = claim_fiq(&hw->fiq_handler); 275bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (ret) 276bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks return; 277bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } 278bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 279bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (hw->tx && !hw->rx) 280bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks mode = FIQ_MODE_TX; 281bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks else if (hw->rx && !hw->tx) 282bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks mode = FIQ_MODE_RX; 283bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks else 284bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks mode = FIQ_MODE_TXRX; 285bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 286bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks regs.uregs[fiq_rspi] = (long)hw->regs; 287bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks regs.uregs[fiq_rrx] = (long)hw->rx; 288bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks regs.uregs[fiq_rtx] = (long)hw->tx + 1; 289bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks regs.uregs[fiq_rcount] = hw->len - 1; 290bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ; 291bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 292bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks set_fiq_regs(®s); 293bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 294bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (hw->fiq_mode != mode) { 295bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks u32 *ack_ptr; 296bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 297bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_mode = mode; 298bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 299bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks switch (mode) { 300bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks case FIQ_MODE_TX: 301bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks code = &s3c24xx_spi_fiq_tx; 302bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks break; 303bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks case FIQ_MODE_RX: 304bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks code = &s3c24xx_spi_fiq_rx; 305bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks break; 306bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks case FIQ_MODE_TXRX: 307bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks code = &s3c24xx_spi_fiq_txrx; 308bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks break; 309bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks default: 310bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks code = NULL; 311bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } 312bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 313bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks BUG_ON(!code); 314bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 315bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks ack_ptr = (u32 *)&code->data[code->ack_offset]; 316bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *ack_ptr = ack_bit(hw->irq); 317bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 318bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks set_fiq_handler(&code->data, code->length); 319bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } 320bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 321bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks s3c24xx_set_fiq(hw->irq, true); 322bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 323bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_mode = mode; 324bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_inuse = 1; 325bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 326bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 327bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 328bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_fiqop - FIQ core code callback 329bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @pw: Data registered with the handler 330bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @release: Whether this is a release or a return. 331bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 332bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Called by the FIQ code when another module wants to use the FIQ, so 333bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * return whether we are currently using this or not and then update our 334bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * internal state. 335bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 336bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic int s3c24xx_spi_fiqop(void *pw, int release) 337bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 338bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks struct s3c24xx_spi *hw = pw; 339bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks int ret = 0; 340bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 341bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (release) { 342bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (hw->fiq_inuse) 343bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks ret = -EBUSY; 344bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 345bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks /* note, we do not need to unroute the FIQ, as the FIQ 346bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * vector code de-routes it to signal the end of transfer */ 347bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 348bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_mode = FIQ_MODE_NONE; 349bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_claimed = 0; 350bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } else { 351bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_claimed = 1; 352bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } 353bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 354bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks return ret; 355bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 356bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 357bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 358bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_initfiq - setup the information for the FIQ core 359bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state. 360bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 361bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Setup the fiq_handler block to pass to the FIQ core. 362bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 363bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw) 364bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 365bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_handler.dev_id = hw; 366bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_handler.name = dev_name(hw->dev); 367bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop; 368bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 369bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 370bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 371bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_usefiq - return if we should be using FIQ. 372bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state. 373bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 374bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Return true if the platform data specifies whether this channel is 375bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * allowed to use the FIQ. 376bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 377bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw) 378bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 379bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks return hw->pdata->use_fiq; 380bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 381bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 382bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/** 383bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_usingfiq - return if channel is using FIQ 384bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @spi: The hardware state. 385bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * 386bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Return whether the channel is currently using the FIQ (separate from 387bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * whether the FIQ is claimed). 388bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */ 389bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi) 390bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{ 391bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks return spi->fiq_inuse; 392bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks} 393bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#else 394bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 395bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { } 396bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { } 397bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; } 398bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; } 399bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 400bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#endif /* CONFIG_SPI_S3C24XX_FIQ */ 401bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 4027fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) 4037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 4047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw = to_hw(spi); 4057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->tx = t->tx_buf; 4077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->rx = t->rx_buf; 4087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->len = t->len; 4097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->count = 0; 4107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4114bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks init_completion(&hw->done); 4124bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks 413bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_inuse = 0; 414bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (s3c24xx_spi_usefiq(hw) && t->len >= 3) 415bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks s3c24xx_spi_tryfiq(hw); 416bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 4177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* send the first byte */ 4187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); 4194bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks 4207fba53402eb0fb4209c74469814c583b6455e096Ben Dooks wait_for_completion(&hw->done); 4217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return hw->count; 4227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 4237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4247d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t s3c24xx_spi_irq(int irq, void *dev) 4257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 4267fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw = dev; 4277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); 4287fba53402eb0fb4209c74469814c583b6455e096Ben Dooks unsigned int count = hw->count; 4297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4307fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (spsta & S3C2410_SPSTA_DCOL) { 4317fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_dbg(hw->dev, "data-collision\n"); 4327fba53402eb0fb4209c74469814c583b6455e096Ben Dooks complete(&hw->done); 4337fba53402eb0fb4209c74469814c583b6455e096Ben Dooks goto irq_done; 4347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 4357fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4367fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (!(spsta & S3C2410_SPSTA_READY)) { 4377fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_dbg(hw->dev, "spi not ready for tx?\n"); 4387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks complete(&hw->done); 4397fba53402eb0fb4209c74469814c583b6455e096Ben Dooks goto irq_done; 4407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 4417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 442bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (!s3c24xx_spi_usingfiq(hw)) { 443bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->count++; 4447fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 445bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (hw->rx) 446bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); 4477fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 448bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks count++; 449bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 450bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (count < hw->len) 451bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); 452bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks else 453bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks complete(&hw->done); 454bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } else { 455bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->count = hw->len; 456bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->fiq_inuse = 0; 457bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 458bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks if (hw->rx) 459bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT); 4607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks complete(&hw->done); 462bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks } 4637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks irq_done: 4657fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return IRQ_HANDLED; 4667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 4677fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4685aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooksstatic void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) 4695aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks{ 4705aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks /* for the moment, permanently enable the clock */ 4715aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks 4725aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks clk_enable(hw->clk); 4735aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks 4745aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks /* program defaults into the registers */ 4755aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks 4765aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks writeb(0xff, hw->regs + S3C2410_SPPRE); 4775aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); 4785aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); 479cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks 480ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks if (hw->pdata) { 481ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks if (hw->set_cs == s3c24xx_spi_gpiocs) 482ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks gpio_direction_output(hw->pdata->pin_cs, 1); 483ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks 484ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks if (hw->pdata->gpio_setup) 485ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks hw->pdata->gpio_setup(hw->pdata, 1); 486ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks } 4875aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks} 4885aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks 489fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int s3c24xx_spi_probe(struct platform_device *pdev) 4907fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 49150f426b55d919dd017af35bb6a08753d1f262920Ben Dooks struct s3c2410_spi_info *pdata; 4927fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw; 4937fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct spi_master *master; 4947fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct resource *res; 4957fba53402eb0fb4209c74469814c583b6455e096Ben Dooks int err = 0; 4967fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 4977fba53402eb0fb4209c74469814c583b6455e096Ben Dooks master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); 4987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (master == NULL) { 4997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "No memory for spi_master\n"); 500c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han return -ENOMEM; 5017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5027fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw = spi_master_get_devdata(master); 5047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks memset(hw, 0, sizeof(struct s3c24xx_spi)); 5057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 50694c69f765f1b4a658d96905ec59928e3e3e07e6aAxel Lin hw->master = master; 5078074cf063e410a2c0cf1704c3b31002e21f5df7cJingoo Han hw->pdata = pdata = dev_get_platdata(&pdev->dev); 5087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->dev = &pdev->dev; 5097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 51050f426b55d919dd017af35bb6a08753d1f262920Ben Dooks if (pdata == NULL) { 5117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "No platform data supplied\n"); 5127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err = -ENOENT; 5137fba53402eb0fb4209c74469814c583b6455e096Ben Dooks goto err_no_pdata; 5147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks platform_set_drvdata(pdev, hw); 5177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks init_completion(&hw->done); 5187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 519bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks /* initialise fiq handler */ 520bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 521bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks s3c24xx_spi_initfiq(hw); 522bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks 523d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks /* setup the master state. */ 524d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks 525e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell /* the spi->mode bits understood by this driver: */ 526e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; 527e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell 528d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks master->num_chipselect = hw->pdata->num_cs; 529cb1d0a7a5d2e537f2f6ada22883abee1762e94b2Ben Dooks master->bus_num = pdata->bus_num; 53008850fa94831d374f4d827a85088f6087836dfc8Axel Lin master->bits_per_word_mask = SPI_BPW_MASK(8); 531d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks 5327fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* setup the state for the bitbang driver */ 5337fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->bitbang.master = hw->master; 5357fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; 5367fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->bitbang.chipselect = s3c24xx_spi_chipsel; 5377fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; 538570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks 539570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks hw->master->setup = s3c24xx_spi_setup; 5407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); 5427fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5437fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* find and map our resources */ 5447fba53402eb0fb4209c74469814c583b6455e096Ben Dooks res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 545c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han hw->regs = devm_ioremap_resource(&pdev->dev, res); 546c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han if (IS_ERR(hw->regs)) { 547c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han err = PTR_ERR(hw->regs); 548c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han goto err_no_pdata; 5497fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5507fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5517fba53402eb0fb4209c74469814c583b6455e096Ben Dooks hw->irq = platform_get_irq(pdev, 0); 5527fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (hw->irq < 0) { 5537fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "No IRQ specified\n"); 5547fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err = -ENOENT; 555c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han goto err_no_pdata; 5567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5577fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 558c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0, 559c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han pdev->name, hw); 5607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (err) { 5617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "Cannot claim IRQ\n"); 562c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han goto err_no_pdata; 5637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 565c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han hw->clk = devm_clk_get(&pdev->dev, "spi"); 5667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (IS_ERR(hw->clk)) { 5677fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "No clock for device\n"); 5687fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err = PTR_ERR(hw->clk); 569c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han goto err_no_pdata; 5707fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 5717fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5727fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* setup any gpio we can */ 5737fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 57450f426b55d919dd017af35bb6a08753d1f262920Ben Dooks if (!pdata->set_cs) { 575ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks if (pdata->pin_cs < 0) { 576ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks dev_err(&pdev->dev, "No chipselect pin\n"); 577b2af045c70aa60f7231b22a363d74a1ab5a6297bJulia Lawall err = -EINVAL; 578ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks goto err_register; 579ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks } 5808736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks 581c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han err = devm_gpio_request(&pdev->dev, pdata->pin_cs, 582c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han dev_name(&pdev->dev)); 583ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks if (err) { 584ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks dev_err(&pdev->dev, "Failed to get gpio for cs\n"); 585ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks goto err_register; 586ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks } 587ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks 588ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks hw->set_cs = s3c24xx_spi_gpiocs; 589ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks gpio_direction_output(pdata->pin_cs, 1); 5908736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks } else 59150f426b55d919dd017af35bb6a08753d1f262920Ben Dooks hw->set_cs = pdata->set_cs; 5927fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 593ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks s3c24xx_spi_initialsetup(hw); 594ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks 5957fba53402eb0fb4209c74469814c583b6455e096Ben Dooks /* register our spi controller */ 5967fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 5977fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err = spi_bitbang_start(&hw->bitbang); 5987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks if (err) { 5997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks dev_err(&pdev->dev, "Failed to register SPI master\n"); 6007fba53402eb0fb4209c74469814c583b6455e096Ben Dooks goto err_register; 6017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks } 6027fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return 0; 6047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err_register: 6067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks clk_disable(hw->clk); 6077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err_no_pdata: 609a419aef8b858a2bdb98df60336063d28df4b272fJoe Perches spi_master_put(hw->master); 6107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return err; 6117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 6127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 613fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int s3c24xx_spi_remove(struct platform_device *dev) 6147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 6157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks struct s3c24xx_spi *hw = platform_get_drvdata(dev); 6167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 617c6e7b8cb11632a3b3968c6f64e179c7619eb70c0Axel Lin spi_bitbang_stop(&hw->bitbang); 6187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks clk_disable(hw->clk); 6197fba53402eb0fb4209c74469814c583b6455e096Ben Dooks spi_master_put(hw->master); 6207fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return 0; 6217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 6227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#ifdef CONFIG_PM 6257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6266d61320707ac2960bc820616bd5921885b874780Ben Dooksstatic int s3c24xx_spi_suspend(struct device *dev) 6277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 628a1216394e620d0dfbb03c712ae3210e7b77c9e11Axel Lin struct s3c24xx_spi *hw = dev_get_drvdata(dev); 629380603712072145785f19040b9791f4f6cde414eAxel Lin int ret; 630380603712072145785f19040b9791f4f6cde414eAxel Lin 631380603712072145785f19040b9791f4f6cde414eAxel Lin ret = spi_master_suspend(hw->master); 632380603712072145785f19040b9791f4f6cde414eAxel Lin if (ret) 633380603712072145785f19040b9791f4f6cde414eAxel Lin return ret; 6347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 635cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks if (hw->pdata && hw->pdata->gpio_setup) 636cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks hw->pdata->gpio_setup(hw->pdata, 0); 637cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks 6387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks clk_disable(hw->clk); 6397fba53402eb0fb4209c74469814c583b6455e096Ben Dooks return 0; 6407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 6417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6426d61320707ac2960bc820616bd5921885b874780Ben Dooksstatic int s3c24xx_spi_resume(struct device *dev) 6437fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{ 644a1216394e620d0dfbb03c712ae3210e7b77c9e11Axel Lin struct s3c24xx_spi *hw = dev_get_drvdata(dev); 6457fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6465aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks s3c24xx_spi_initialsetup(hw); 647380603712072145785f19040b9791f4f6cde414eAxel Lin return spi_master_resume(hw->master); 6487fba53402eb0fb4209c74469814c583b6455e096Ben Dooks} 6497fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 650471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops s3c24xx_spi_pmops = { 6516d61320707ac2960bc820616bd5921885b874780Ben Dooks .suspend = s3c24xx_spi_suspend, 6526d61320707ac2960bc820616bd5921885b874780Ben Dooks .resume = s3c24xx_spi_resume, 6536d61320707ac2960bc820616bd5921885b874780Ben Dooks}; 6546d61320707ac2960bc820616bd5921885b874780Ben Dooks 6556d61320707ac2960bc820616bd5921885b874780Ben Dooks#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops 6567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#else 6576d61320707ac2960bc820616bd5921885b874780Ben Dooks#define S3C24XX_SPI_PMOPS NULL 6586d61320707ac2960bc820616bd5921885b874780Ben Dooks#endif /* CONFIG_PM */ 6597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6607e38c3c4453bdb5ffdf8bf0ff0d9a760540f0893Kay SieversMODULE_ALIAS("platform:s3c2410-spi"); 66142cde4309b8f2671610be049352df2f8716e8809Ben Dooksstatic struct platform_driver s3c24xx_spi_driver = { 662940ab88962bc1aff3273a8356d64577a6e386736Grant Likely .probe = s3c24xx_spi_probe, 663fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likely .remove = s3c24xx_spi_remove, 6647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks .driver = { 6657fba53402eb0fb4209c74469814c583b6455e096Ben Dooks .name = "s3c2410-spi", 6667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks .owner = THIS_MODULE, 6676d61320707ac2960bc820616bd5921885b874780Ben Dooks .pm = S3C24XX_SPI_PMOPS, 6687fba53402eb0fb4209c74469814c583b6455e096Ben Dooks }, 6697fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}; 670940ab88962bc1aff3273a8356d64577a6e386736Grant Likelymodule_platform_driver(s3c24xx_spi_driver); 6717fba53402eb0fb4209c74469814c583b6455e096Ben Dooks 6727fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_DESCRIPTION("S3C24XX SPI Driver"); 6737fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); 6747fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_LICENSE("GPL"); 675