add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

292
kernel/drivers/spi/Kconfig Normal file
View File

@@ -0,0 +1,292 @@
#
# SPI driver configuration
#
# NOTE: the reason this doesn't show SPI slave support is mostly that
# nobody's needed a slave side API yet. The master-role API is not
# fully appropriate there, so it'd need some thought to do well.
#
menuconfig SPI
bool "SPI support"
depends on HAS_IOMEM
help
The "Serial Peripheral Interface" is a low level synchronous
protocol. Chips that support SPI can have data transfer rates
up to several tens of Mbit/sec. Chips are addressed with a
controller and a chipselect. Most SPI slaves don't support
dynamic device discovery; some are even write-only or read-only.
SPI is widely used by microcontrollers to talk with sensors,
eeprom and flash memory, codecs and various other controller
chips, analog to digital (and d-to-a) converters, and more.
MMC and SD cards can be accessed using SPI protocol; and for
DataFlash cards used in MMC sockets, SPI must always be used.
SPI is one of a family of similar protocols using a four wire
interface (select, clock, data in, data out) including Microwire
(half duplex), SSP, SSI, and PSP. This driver framework should
work with most such devices and controllers.
if SPI
config SPI_DEBUG
boolean "Debug support for SPI drivers"
depends on DEBUG_KERNEL
help
Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
sysfs, and debugfs support in SPI controller and protocol drivers.
#
# MASTER side ... talking to discrete SPI slave chips including microcontrollers
#
config SPI_MASTER
# boolean "SPI Master Support"
boolean
default SPI
help
If your system has an master-capable SPI controller (which
provides the clock and chipselect), you can enable that
controller and the protocol drivers for the SPI slave chips
that are connected.
if SPI_MASTER
comment "SPI Master Controller Drivers"
config SPI_ATMEL
tristate "Atmel SPI Controller"
depends on (ARCH_AT91 || AVR32)
help
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
config SPI_BFIN
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN
help
This is the SPI controller master driver for Blackfin 5xx processor.
config SPI_AU1550
tristate "Au1550/Au12x0 SPI Controller"
depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
select SPI_BITBANG
help
If you say yes to this option, support will be included for the
Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
This driver can also be built as a module. If so, the module
will be called au1550_spi.
config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters"
help
With a few GPIO pins, your system can bitbang the SPI protocol.
Select this to get SPI support through I/O pins (GPIO, parallel
port, etc). Or, some systems' SPI master controller drivers use
this code to manage the per-word or per-transfer accesses to the
hardware shift registers.
This is library code, and is automatically selected by drivers that
need it. You only need to select this explicitly to support driver
modules that aren't part of this kernel tree.
config SPI_BUTTERFLY
tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
depends on PARPORT
select SPI_BITBANG
help
This uses a custom parallel port cable to connect to an AVR
Butterfly <http://www.atmel.com/products/avr/butterfly>, an
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
depends on GENERIC_GPIO
select SPI_BITBANG
help
This simple GPIO bitbanging SPI master uses the arch-neutral GPIO
interface to manage MOSI, MISO, SCK, and chipselect signals. SPI
slaves connected to a bus using this driver are configured as usual,
except that the spi_board_info.controller_data holds the GPIO number
for the chipselect used by this controller driver.
Note that this driver often won't achieve even 1 Mbit/sec speeds,
making it unusually slow for SPI. If your platform can inline
GPIO operations, you should be able to leverage that for better
speed with a custom version of this driver; see the source code.
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC
select SPI_BITBANG
help
This enables using the Freescale i.MX SPI controllers in master
mode.
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
depends on PARPORT && EXPERIMENTAL
select SPI_BITBANG
help
This driver supports the NS LM70 LLP Evaluation Board,
which interfaces to an LM70 temperature sensor using
a parallel port.
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on PPC_MPC52xx && EXPERIMENTAL
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
config SPI_MPC8xxx
tristate "Freescale MPC8xxx SPI controller"
depends on FSL_SOC
help
This enables using the Freescale MPC8xxx SPI controllers in master
mode.
This driver uses a simple set of shift registers for data (opposed
to the CPM based descriptor model).
config SPI_OMAP_UWIRE
tristate "OMAP1 MicroWire"
depends on ARCH_OMAP1
select SPI_BITBANG
help
This hooks up to the MicroWire controller on OMAP1 chips.
config SPI_OMAP24XX
tristate "McSPI driver for OMAP24xx/OMAP34xx"
depends on ARCH_OMAP24XX || ARCH_OMAP34XX
help
SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.
config SPI_ORION
tristate "Orion SPI master (EXPERIMENTAL)"
depends on PLAT_ORION && EXPERIMENTAL
help
This enables using the SPI master controller on the Orion chips.
config SPI_PL022
tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
depends on ARM_AMBA && EXPERIMENTAL
default y if MACH_U300
default y if ARCH_REALVIEW
default y if INTEGRATOR_IMPD1
default y if ARCH_VERSATILE
help
This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP
controller. If you have an embedded system with an AMBA(R)
bus and a PL022 controller, say Y or M here.
config SPI_PPC4xx
tristate "PPC4xx SPI Controller"
depends on PPC32 && 4xx && SPI_MASTER
select SPI_BITBANG
help
This selects a driver for the PPC4xx SPI Controller.
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA && EXPERIMENTAL
select PXA_SSP
help
This enables using a PXA2xx SSP port as a SPI master controller.
The driver can be configured to use any SSP port and additional
documentation can be found a Documentation/spi/pxa2xx.
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs using
GPIO lines to provide the SPI bus. This can be used where
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
config SPI_SH_SCI
tristate "SuperH SCI SPI controller"
depends on SUPERH
select SPI_BITBANG
help
SPI driver for SuperH SCI blocks.
config SPI_STMP3XXX
tristate "Freescale STMP37xx/378x SPI/SSP controller"
depends on ARCH_STMP3XXX && SPI_MASTER
help
SPI driver for Freescale STMP37xx/378x SoC SSP interface
config SPI_STM
tristate "STMicroelectronics SPI SSC-based driver"
depends on CPU_SUBTYPE_ST40
select SPI_BITBANG
help
STMicroelectronics SoCs support for SPI.
If you say yes to this option, support will be included for the
SSC driven SPI.
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
depends on GENERIC_GPIO && CPU_TX49XX
help
SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_XILINX
tristate "Xilinx SPI controller"
depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
select SPI_BITBANG
help
This exposes the SPI controller IP from the Xilinx EDK.
See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
Product Specification document (DS464) for hardware details.
#
# Add new SPI master controllers in alphabetical order above this line
#
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
#
comment "SPI Protocol Masters"
config SPI_SPIDEV
tristate "User mode SPI device driver support"
depends on EXPERIMENTAL
help
This supports user mode SPI protocol drivers.
Note that this application programming interface is EXPERIMENTAL
and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
depends on SYSFS
help
SPI driver for Infineon TLE62X0 series line driver chips,
such as the TLE6220, TLE6230 and TLE6240. This provides a
sysfs interface, with each line presented as a kind of GPIO
exposing both switch control and diagnostic feedback.
#
# Add new SPI protocol masters in alphabetical order above this line
#
endif # SPI_MASTER
# (slave support would go here)
endif # SPI

View File

@@ -0,0 +1,48 @@
#
# Makefile for kernel SPI drivers.
#
ifeq ($(CONFIG_SPI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
# small core, mostly translating board-specific
# config declarations into driver model code
obj-$(CONFIG_SPI_MASTER) += spi.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_STM) += spi_stm.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
# ... add above this line ...
# SPI slave drivers (protocol for that link)
# ... add above this line ...

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,923 @@
/*
* Driver for Atmel AT32 and AT91 SPI Controllers
*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <asm/io.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/cpu.h>
#include "atmel_spi.h"
/*
* The core SPI transfer engine just talks to a register bank to set up
* DMA transfers; transfer queue progress is driven by IRQs. The clock
* framework provides the base clock, subdivided for each spi_device.
*/
struct atmel_spi {
spinlock_t lock;
void __iomem *regs;
int irq;
struct clk *clk;
struct platform_device *pdev;
struct spi_device *stay;
u8 stopping;
struct list_head queue;
struct spi_transfer *current_transfer;
unsigned long current_remaining_bytes;
struct spi_transfer *next_transfer;
unsigned long next_remaining_bytes;
void *buffer;
dma_addr_t buffer_dma;
};
/* Controller-specific per-slave state */
struct atmel_spi_device {
unsigned int npcs_pin;
u32 csr;
};
#define BUFFER_SIZE PAGE_SIZE
#define INVALID_DMA_ADDRESS 0xffffffff
/*
* Version 2 of the SPI controller has
* - CR.LASTXFER
* - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
* - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
* - SPI_CSRx.CSAAT
* - SPI_CSRx.SBCR allows faster clocking
*
* We can determine the controller version by reading the VERSION
* register, but I haven't checked that it exists on all chips, and
* this is cheaper anyway.
*/
static bool atmel_spi_is_v2(void)
{
return !cpu_is_at91rm9200();
}
/*
* Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
* they assume that spi slave device state will not change on deselect, so
* that automagic deselection is OK. ("NPCSx rises if no data is to be
* transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
* controllers have CSAAT and friends.
*
* Since the CSAAT functionality is a bit weird on newer controllers as
* well, we use GPIO to control nCSx pins on all controllers, updating
* MR.PCS to avoid confusing the controller. Using GPIOs also lets us
* support active-high chipselects despite the controller's belief that
* only active-low devices/systems exists.
*
* However, at91rm9200 has a second erratum whereby nCS0 doesn't work
* right when driven with GPIO. ("Mode Fault does not allow more than one
* Master on Chip Select 0.") No workaround exists for that ... so for
* nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
* and (c) will trigger that first erratum in some cases.
*
* TODO: Test if the atmel_spi_is_v2() branch below works on
* AT91RM9200 if we use some other register than CSR0. However, don't
* do this unconditionally since AP7000 has an errata where the BITS
* field in CSR0 overrides all other CSRs.
*/
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;
if (atmel_spi_is_v2()) {
/*
* Always use CSR0. This ensures that the clock
* switches to the correct idle polarity before we
* toggle the CS.
*/
spi_writel(as, CSR0, asd->csr);
spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS)
| SPI_BIT(MSTR));
mr = spi_readl(as, MR);
gpio_set_value(asd->npcs_pin, active);
} else {
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
int i;
u32 csr;
/* Make sure clock polarity is correct */
for (i = 0; i < spi->master->num_chipselect; i++) {
csr = spi_readl(as, CSR0 + 4 * i);
if ((csr ^ cpol) & SPI_BIT(CPOL))
spi_writel(as, CSR0 + 4 * i,
csr ^ SPI_BIT(CPOL));
}
mr = spi_readl(as, MR);
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
if (spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, active);
spi_writel(as, MR, mr);
}
dev_dbg(&spi->dev, "activate %u%s, mr %08x\n",
asd->npcs_pin, active ? " (high)" : "",
mr);
}
static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;
/* only deactivate *this* device; sometimes transfers to
* another device may be active when this routine is called.
*/
mr = spi_readl(as, MR);
if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
mr = SPI_BFINS(PCS, 0xf, mr);
spi_writel(as, MR, mr);
}
dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n",
asd->npcs_pin, active ? " (low)" : "",
mr);
if (atmel_spi_is_v2() || spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, !active);
}
static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
struct spi_transfer *xfer)
{
return msg->transfers.prev == &xfer->transfer_list;
}
static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
{
return xfer->delay_usecs == 0 && !xfer->cs_change;
}
static void atmel_spi_next_xfer_data(struct spi_master *master,
struct spi_transfer *xfer,
dma_addr_t *tx_dma,
dma_addr_t *rx_dma,
u32 *plen)
{
struct atmel_spi *as = spi_master_get_devdata(master);
u32 len = *plen;
/* use scratch buffer only when rx or tx data is unspecified */
if (xfer->rx_buf)
*rx_dma = xfer->rx_dma + xfer->len - len;
else {
*rx_dma = as->buffer_dma;
if (len > BUFFER_SIZE)
len = BUFFER_SIZE;
}
if (xfer->tx_buf)
*tx_dma = xfer->tx_dma + xfer->len - len;
else {
*tx_dma = as->buffer_dma;
if (len > BUFFER_SIZE)
len = BUFFER_SIZE;
memset(as->buffer, 0, len);
dma_sync_single_for_device(&as->pdev->dev,
as->buffer_dma, len, DMA_TO_DEVICE);
}
*plen = len;
}
/*
* Submit next transfer for DMA.
* lock is held, spi irq is blocked
*/
static void atmel_spi_next_xfer(struct spi_master *master,
struct spi_message *msg)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_transfer *xfer;
u32 len, remaining;
u32 ieval;
dma_addr_t tx_dma, rx_dma;
if (!as->current_transfer)
xfer = list_entry(msg->transfers.next,
struct spi_transfer, transfer_list);
else if (!as->next_transfer)
xfer = list_entry(as->current_transfer->transfer_list.next,
struct spi_transfer, transfer_list);
else
xfer = NULL;
if (xfer) {
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
len = xfer->len;
atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
remaining = xfer->len - len;
spi_writel(as, RPR, rx_dma);
spi_writel(as, TPR, tx_dma);
if (msg->spi->bits_per_word > 8)
len >>= 1;
spi_writel(as, RCR, len);
spi_writel(as, TCR, len);
dev_dbg(&msg->spi->dev,
" start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma);
} else {
xfer = as->next_transfer;
remaining = as->next_remaining_bytes;
}
as->current_transfer = xfer;
as->current_remaining_bytes = remaining;
if (remaining > 0)
len = remaining;
else if (!atmel_spi_xfer_is_last(msg, xfer)
&& atmel_spi_xfer_can_be_chained(xfer)) {
xfer = list_entry(xfer->transfer_list.next,
struct spi_transfer, transfer_list);
len = xfer->len;
} else
xfer = NULL;
as->next_transfer = xfer;
if (xfer) {
u32 total;
total = len;
atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
as->next_remaining_bytes = total - len;
spi_writel(as, RNPR, rx_dma);
spi_writel(as, TNPR, tx_dma);
if (msg->spi->bits_per_word > 8)
len >>= 1;
spi_writel(as, RNCR, len);
spi_writel(as, TNCR, len);
dev_dbg(&msg->spi->dev,
" next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma);
ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES);
} else {
spi_writel(as, RNCR, 0);
spi_writel(as, TNCR, 0);
ieval = SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) | SPI_BIT(OVRES);
}
/* REVISIT: We're waiting for ENDRX before we start the next
* transfer because we need to handle some difficult timing
* issues otherwise. If we wait for ENDTX in one transfer and
* then starts waiting for ENDRX in the next, it's difficult
* to tell the difference between the ENDRX interrupt we're
* actually waiting for and the ENDRX interrupt of the
* previous transfer.
*
* It should be doable, though. Just not now...
*/
spi_writel(as, IER, ieval);
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
static void atmel_spi_next_message(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
struct spi_device *spi;
BUG_ON(as->current_transfer);
msg = list_entry(as->queue.next, struct spi_message, queue);
spi = msg->spi;
dev_dbg(master->dev.parent, "start message %p for %s\n",
msg, dev_name(&spi->dev));
/* select chip if it's not still active */
if (as->stay) {
if (as->stay != spi) {
cs_deactivate(as, as->stay);
cs_activate(as, spi);
}
as->stay = NULL;
} else
cs_activate(as, spi);
atmel_spi_next_xfer(master, msg);
}
/*
* For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
* - The buffer is either valid for CPU access, else NULL
* - If the buffer is valid, so is its DMA addresss
*
* This driver manages the dma addresss unless message->is_dma_mapped.
*/
static int
atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
{
struct device *dev = &as->pdev->dev;
xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
if (xfer->tx_buf) {
xfer->tx_dma = dma_map_single(dev,
(void *) xfer->tx_buf, xfer->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma))
return -ENOMEM;
}
if (xfer->rx_buf) {
xfer->rx_dma = dma_map_single(dev,
xfer->rx_buf, xfer->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, xfer->rx_dma)) {
if (xfer->tx_buf)
dma_unmap_single(dev,
xfer->tx_dma, xfer->len,
DMA_TO_DEVICE);
return -ENOMEM;
}
}
return 0;
}
static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
struct spi_transfer *xfer)
{
if (xfer->tx_dma != INVALID_DMA_ADDRESS)
dma_unmap_single(master->dev.parent, xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
if (xfer->rx_dma != INVALID_DMA_ADDRESS)
dma_unmap_single(master->dev.parent, xfer->rx_dma,
xfer->len, DMA_FROM_DEVICE);
}
static void
atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
struct spi_message *msg, int status, int stay)
{
if (!stay || status < 0)
cs_deactivate(as, msg->spi);
else
as->stay = msg->spi;
list_del(&msg->queue);
msg->status = status;
dev_dbg(master->dev.parent,
"xfer complete: %u bytes transferred\n",
msg->actual_length);
spin_unlock(&as->lock);
msg->complete(msg->context);
spin_lock(&as->lock);
as->current_transfer = NULL;
as->next_transfer = NULL;
/* continue if needed */
if (list_empty(&as->queue) || as->stopping)
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
else
atmel_spi_next_message(master);
}
static irqreturn_t
atmel_spi_interrupt(int irq, void *dev_id)
{
struct spi_master *master = dev_id;
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
struct spi_transfer *xfer;
u32 status, pending, imr;
int ret = IRQ_NONE;
spin_lock(&as->lock);
xfer = as->current_transfer;
msg = list_entry(as->queue.next, struct spi_message, queue);
imr = spi_readl(as, IMR);
status = spi_readl(as, SR);
pending = status & imr;
if (pending & SPI_BIT(OVRES)) {
int timeout;
ret = IRQ_HANDLED;
spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX)
| SPI_BIT(OVRES)));
/*
* When we get an overrun, we disregard the current
* transfer. Data will not be copied back from any
* bounce buffer and msg->actual_len will not be
* updated with the last xfer.
*
* We will also not process any remaning transfers in
* the message.
*
* First, stop the transfer and unmap the DMA buffers.
*/
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
if (!msg->is_dma_mapped)
atmel_spi_dma_unmap_xfer(master, xfer);
/* REVISIT: udelay in irq is unfriendly */
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
dev_warn(master->dev.parent, "overrun (%u/%u remaining)\n",
spi_readl(as, TCR), spi_readl(as, RCR));
/*
* Clean up DMA registers and make sure the data
* registers are empty.
*/
spi_writel(as, RNCR, 0);
spi_writel(as, TNCR, 0);
spi_writel(as, RCR, 0);
spi_writel(as, TCR, 0);
for (timeout = 1000; timeout; timeout--)
if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
break;
if (!timeout)
dev_warn(master->dev.parent,
"timeout waiting for TXEMPTY");
while (spi_readl(as, SR) & SPI_BIT(RDRF))
spi_readl(as, RDR);
/* Clear any overrun happening while cleaning up */
spi_readl(as, SR);
atmel_spi_msg_done(master, as, msg, -EIO, 0);
} else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
ret = IRQ_HANDLED;
spi_writel(as, IDR, pending);
if (as->current_remaining_bytes == 0) {
msg->actual_length += xfer->len;
if (!msg->is_dma_mapped)
atmel_spi_dma_unmap_xfer(master, xfer);
/* REVISIT: udelay in irq is unfriendly */
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
atmel_spi_msg_done(master, as, msg, 0,
xfer->cs_change);
} else {
if (xfer->cs_change) {
cs_deactivate(as, msg->spi);
udelay(1);
cs_activate(as, msg->spi);
}
/*
* Not done yet. Submit the next transfer.
*
* FIXME handle protocol options for xfer
*/
atmel_spi_next_xfer(master, msg);
}
} else {
/*
* Keep going, we still have data to send in
* the current transfer.
*/
atmel_spi_next_xfer(master, msg);
}
}
spin_unlock(&as->lock);
return ret;
}
static int atmel_spi_setup(struct spi_device *spi)
{
struct atmel_spi *as;
struct atmel_spi_device *asd;
u32 scbr, csr;
unsigned int bits = spi->bits_per_word;
unsigned long bus_hz;
unsigned int npcs_pin;
int ret;
as = spi_master_get_devdata(spi->master);
if (as->stopping)
return -ESHUTDOWN;
if (spi->chip_select > spi->master->num_chipselect) {
dev_dbg(&spi->dev,
"setup: invalid chipselect %u (%u defined)\n",
spi->chip_select, spi->master->num_chipselect);
return -EINVAL;
}
if (bits < 8 || bits > 16) {
dev_dbg(&spi->dev,
"setup: invalid bits_per_word %u (8 to 16)\n",
bits);
return -EINVAL;
}
/* see notes above re chipselect */
if (!atmel_spi_is_v2()
&& spi->chip_select == 0
&& (spi->mode & SPI_CS_HIGH)) {
dev_dbg(&spi->dev, "setup: can't be active-high\n");
return -EINVAL;
}
/* v1 chips start out at half the peripheral bus speed. */
bus_hz = clk_get_rate(as->clk);
if (!atmel_spi_is_v2())
bus_hz /= 2;
if (spi->max_speed_hz) {
/*
* Calculate the lowest divider that satisfies the
* constraint, assuming div32/fdiv/mbz == 0.
*/
scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz);
/*
* If the resulting divider doesn't fit into the
* register bitfield, we can't satisfy the constraint.
*/
if (scbr >= (1 << SPI_SCBR_SIZE)) {
dev_dbg(&spi->dev,
"setup: %d Hz too slow, scbr %u; min %ld Hz\n",
spi->max_speed_hz, scbr, bus_hz/255);
return -EINVAL;
}
} else
/* speed zero means "as slow as possible" */
scbr = 0xff;
csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
if (spi->mode & SPI_CPOL)
csr |= SPI_BIT(CPOL);
if (!(spi->mode & SPI_CPHA))
csr |= SPI_BIT(NCPHA);
/* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
*
* DLYBCT would add delays between words, slowing down transfers.
* It could potentially be useful to cope with DMA bottlenecks, but
* in those cases it's probably best to just use a lower bitrate.
*/
csr |= SPI_BF(DLYBS, 0);
csr |= SPI_BF(DLYBCT, 0);
/* chipselect must have been muxed as GPIO (e.g. in board setup) */
npcs_pin = (unsigned int)spi->controller_data;
asd = spi->controller_state;
if (!asd) {
asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
if (!asd)
return -ENOMEM;
ret = gpio_request(npcs_pin, dev_name(&spi->dev));
if (ret) {
kfree(asd);
return ret;
}
asd->npcs_pin = npcs_pin;
spi->controller_state = asd;
gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
} else {
unsigned long flags;
spin_lock_irqsave(&as->lock, flags);
if (as->stay == spi)
as->stay = NULL;
cs_deactivate(as, spi);
spin_unlock_irqrestore(&as->lock, flags);
}
asd->csr = csr;
dev_dbg(&spi->dev,
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
if (!atmel_spi_is_v2())
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
return 0;
}
static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct atmel_spi *as;
struct spi_transfer *xfer;
unsigned long flags;
struct device *controller = spi->master->dev.parent;
as = spi_master_get_devdata(spi->master);
dev_dbg(controller, "new message %p submitted for %s\n",
msg, dev_name(&spi->dev));
if (unlikely(list_empty(&msg->transfers)))
return -EINVAL;
if (as->stopping)
return -ESHUTDOWN;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
dev_dbg(&spi->dev, "missing rx or tx buf\n");
return -EINVAL;
}
/* FIXME implement these protocol options!! */
if (xfer->bits_per_word || xfer->speed_hz) {
dev_dbg(&spi->dev, "no protocol options yet\n");
return -ENOPROTOOPT;
}
/*
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting. This is a DMA-only driver.
*
* NOTE that if dma_unmap_single() ever starts to do work on
* platforms supported by this driver, we would need to clean
* up mappings for previously-mapped transfers.
*/
if (!msg->is_dma_mapped) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
}
#ifdef VERBOSE
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(controller,
" xfer %p: len %u tx %p/%08x rx %p/%08x\n",
xfer, xfer->len,
xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma);
}
#endif
msg->status = -EINPROGRESS;
msg->actual_length = 0;
spin_lock_irqsave(&as->lock, flags);
list_add_tail(&msg->queue, &as->queue);
if (!as->current_transfer)
atmel_spi_next_message(spi->master);
spin_unlock_irqrestore(&as->lock, flags);
return 0;
}
static void atmel_spi_cleanup(struct spi_device *spi)
{
struct atmel_spi *as = spi_master_get_devdata(spi->master);
struct atmel_spi_device *asd = spi->controller_state;
unsigned gpio = (unsigned) spi->controller_data;
unsigned long flags;
if (!asd)
return;
spin_lock_irqsave(&as->lock, flags);
if (as->stay == spi) {
as->stay = NULL;
cs_deactivate(as, spi);
}
spin_unlock_irqrestore(&as->lock, flags);
spi->controller_state = NULL;
gpio_free(gpio);
kfree(asd);
}
/*-------------------------------------------------------------------------*/
static int __init atmel_spi_probe(struct platform_device *pdev)
{
struct resource *regs;
int irq;
struct clk *clk;
int ret;
struct spi_master *master;
struct atmel_spi *as;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
clk = clk_get(&pdev->dev, "spi_clk");
if (IS_ERR(clk))
return PTR_ERR(clk);
/* setup spi core then atmel-specific driver state */
ret = -ENOMEM;
master = spi_alloc_master(&pdev->dev, sizeof *as);
if (!master)
goto out_free;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bus_num = pdev->id;
master->num_chipselect = 4;
master->setup = atmel_spi_setup;
master->transfer = atmel_spi_transfer;
master->cleanup = atmel_spi_cleanup;
platform_set_drvdata(pdev, master);
as = spi_master_get_devdata(master);
/*
* Scratch buffer is used for throwaway rx and tx data.
* It's coherent to minimize dcache pollution.
*/
as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
&as->buffer_dma, GFP_KERNEL);
if (!as->buffer)
goto out_free;
spin_lock_init(&as->lock);
INIT_LIST_HEAD(&as->queue);
as->pdev = pdev;
as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
if (!as->regs)
goto out_free_buffer;
as->irq = irq;
as->clk = clk;
ret = request_irq(irq, atmel_spi_interrupt, 0,
dev_name(&pdev->dev), master);
if (ret)
goto out_unmap_regs;
/* Initialize the hardware */
clk_enable(clk);
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
spi_writel(as, CR, SPI_BIT(SPIEN));
/* go! */
dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
(unsigned long)regs->start, irq);
ret = spi_register_master(master);
if (ret)
goto out_reset_hw;
return 0;
out_reset_hw:
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
clk_disable(clk);
free_irq(irq, master);
out_unmap_regs:
iounmap(as->regs);
out_free_buffer:
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
out_free:
clk_put(clk);
spi_master_put(master);
return ret;
}
static int __exit atmel_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
/* reset the hardware and block queue progress */
spin_lock_irq(&as->lock);
as->stopping = 1;
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_readl(as, SR);
spin_unlock_irq(&as->lock);
/* Terminate remaining queued transfers */
list_for_each_entry(msg, &as->queue, queue) {
/* REVISIT unmapping the dma is a NOP on ARM and AVR32
* but we shouldn't depend on that...
*/
msg->status = -ESHUTDOWN;
msg->complete(msg->context);
}
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
clk_disable(as->clk);
clk_put(as->clk);
free_irq(as->irq, master);
iounmap(as->regs);
spi_unregister_master(master);
return 0;
}
#ifdef CONFIG_PM
static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
clk_disable(as->clk);
return 0;
}
static int atmel_spi_resume(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
clk_enable(as->clk);
return 0;
}
#else
#define atmel_spi_suspend NULL
#define atmel_spi_resume NULL
#endif
static struct platform_driver atmel_spi_driver = {
.driver = {
.name = "atmel_spi",
.owner = THIS_MODULE,
},
.suspend = atmel_spi_suspend,
.resume = atmel_spi_resume,
.remove = __exit_p(atmel_spi_remove),
};
static int __init atmel_spi_init(void)
{
return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
}
module_init(atmel_spi_init);
static void __exit atmel_spi_exit(void)
{
platform_driver_unregister(&atmel_spi_driver);
}
module_exit(atmel_spi_exit);
MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:atmel_spi");

View File

@@ -0,0 +1,167 @@
/*
* Register definitions for Atmel Serial Peripheral Interface (SPI)
*
* Copyright (C) 2006 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ATMEL_SPI_H__
#define __ATMEL_SPI_H__
/* SPI register offsets */
#define SPI_CR 0x0000
#define SPI_MR 0x0004
#define SPI_RDR 0x0008
#define SPI_TDR 0x000c
#define SPI_SR 0x0010
#define SPI_IER 0x0014
#define SPI_IDR 0x0018
#define SPI_IMR 0x001c
#define SPI_CSR0 0x0030
#define SPI_CSR1 0x0034
#define SPI_CSR2 0x0038
#define SPI_CSR3 0x003c
#define SPI_RPR 0x0100
#define SPI_RCR 0x0104
#define SPI_TPR 0x0108
#define SPI_TCR 0x010c
#define SPI_RNPR 0x0110
#define SPI_RNCR 0x0114
#define SPI_TNPR 0x0118
#define SPI_TNCR 0x011c
#define SPI_PTCR 0x0120
#define SPI_PTSR 0x0124
/* Bitfields in CR */
#define SPI_SPIEN_OFFSET 0
#define SPI_SPIEN_SIZE 1
#define SPI_SPIDIS_OFFSET 1
#define SPI_SPIDIS_SIZE 1
#define SPI_SWRST_OFFSET 7
#define SPI_SWRST_SIZE 1
#define SPI_LASTXFER_OFFSET 24
#define SPI_LASTXFER_SIZE 1
/* Bitfields in MR */
#define SPI_MSTR_OFFSET 0
#define SPI_MSTR_SIZE 1
#define SPI_PS_OFFSET 1
#define SPI_PS_SIZE 1
#define SPI_PCSDEC_OFFSET 2
#define SPI_PCSDEC_SIZE 1
#define SPI_FDIV_OFFSET 3
#define SPI_FDIV_SIZE 1
#define SPI_MODFDIS_OFFSET 4
#define SPI_MODFDIS_SIZE 1
#define SPI_LLB_OFFSET 7
#define SPI_LLB_SIZE 1
#define SPI_PCS_OFFSET 16
#define SPI_PCS_SIZE 4
#define SPI_DLYBCS_OFFSET 24
#define SPI_DLYBCS_SIZE 8
/* Bitfields in RDR */
#define SPI_RD_OFFSET 0
#define SPI_RD_SIZE 16
/* Bitfields in TDR */
#define SPI_TD_OFFSET 0
#define SPI_TD_SIZE 16
/* Bitfields in SR */
#define SPI_RDRF_OFFSET 0
#define SPI_RDRF_SIZE 1
#define SPI_TDRE_OFFSET 1
#define SPI_TDRE_SIZE 1
#define SPI_MODF_OFFSET 2
#define SPI_MODF_SIZE 1
#define SPI_OVRES_OFFSET 3
#define SPI_OVRES_SIZE 1
#define SPI_ENDRX_OFFSET 4
#define SPI_ENDRX_SIZE 1
#define SPI_ENDTX_OFFSET 5
#define SPI_ENDTX_SIZE 1
#define SPI_RXBUFF_OFFSET 6
#define SPI_RXBUFF_SIZE 1
#define SPI_TXBUFE_OFFSET 7
#define SPI_TXBUFE_SIZE 1
#define SPI_NSSR_OFFSET 8
#define SPI_NSSR_SIZE 1
#define SPI_TXEMPTY_OFFSET 9
#define SPI_TXEMPTY_SIZE 1
#define SPI_SPIENS_OFFSET 16
#define SPI_SPIENS_SIZE 1
/* Bitfields in CSR0 */
#define SPI_CPOL_OFFSET 0
#define SPI_CPOL_SIZE 1
#define SPI_NCPHA_OFFSET 1
#define SPI_NCPHA_SIZE 1
#define SPI_CSAAT_OFFSET 3
#define SPI_CSAAT_SIZE 1
#define SPI_BITS_OFFSET 4
#define SPI_BITS_SIZE 4
#define SPI_SCBR_OFFSET 8
#define SPI_SCBR_SIZE 8
#define SPI_DLYBS_OFFSET 16
#define SPI_DLYBS_SIZE 8
#define SPI_DLYBCT_OFFSET 24
#define SPI_DLYBCT_SIZE 8
/* Bitfields in RCR */
#define SPI_RXCTR_OFFSET 0
#define SPI_RXCTR_SIZE 16
/* Bitfields in TCR */
#define SPI_TXCTR_OFFSET 0
#define SPI_TXCTR_SIZE 16
/* Bitfields in RNCR */
#define SPI_RXNCR_OFFSET 0
#define SPI_RXNCR_SIZE 16
/* Bitfields in TNCR */
#define SPI_TXNCR_OFFSET 0
#define SPI_TXNCR_SIZE 16
/* Bitfields in PTCR */
#define SPI_RXTEN_OFFSET 0
#define SPI_RXTEN_SIZE 1
#define SPI_RXTDIS_OFFSET 1
#define SPI_RXTDIS_SIZE 1
#define SPI_TXTEN_OFFSET 8
#define SPI_TXTEN_SIZE 1
#define SPI_TXTDIS_OFFSET 9
#define SPI_TXTDIS_SIZE 1
/* Constants for BITS */
#define SPI_BITS_8_BPT 0
#define SPI_BITS_9_BPT 1
#define SPI_BITS_10_BPT 2
#define SPI_BITS_11_BPT 3
#define SPI_BITS_12_BPT 4
#define SPI_BITS_13_BPT 5
#define SPI_BITS_14_BPT 6
#define SPI_BITS_15_BPT 7
#define SPI_BITS_16_BPT 8
/* Bit manipulation macros */
#define SPI_BIT(name) \
(1 << SPI_##name##_OFFSET)
#define SPI_BF(name,value) \
(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
#define SPI_BFEXT(name,value) \
(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
#define SPI_BFINS(name,value,old) \
( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
| SPI_BF(name,value))
/* Register access macros */
#define spi_readl(port,reg) \
__raw_readl((port)->regs + SPI_##reg)
#define spi_writel(port,reg,value) \
__raw_writel((value), (port)->regs + SPI_##reg)
#endif /* __ATMEL_SPI_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,531 @@
/*
* MPC52xx PSC in SPI mode driver.
*
* Maintainer: Dragos Carp
*
* Copyright (C) 2006 TOPTICA Photonics AG.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#define MCLK 20000000 /* PSC port MClk in hz */
struct mpc52xx_psc_spi {
/* fsl_spi_platform data */
void (*cs_control)(struct spi_device *spi, bool on);
u32 sysclk;
/* driver internal data */
struct mpc52xx_psc __iomem *psc;
struct mpc52xx_psc_fifo __iomem *fifo;
unsigned int irq;
u8 bits_per_word;
u8 busy;
struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
spinlock_t lock;
struct completion done;
};
/* controller state */
struct mpc52xx_psc_spi_cs {
int bits_per_word;
int speed_hz;
};
/* set clock freq, clock ramp, bits per work
* if t is NULL then reset the values to the default values
*/
static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
struct spi_transfer *t)
{
struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
cs->speed_hz = (t && t->speed_hz)
? t->speed_hz : spi->max_speed_hz;
cs->bits_per_word = (t && t->bits_per_word)
? t->bits_per_word : spi->bits_per_word;
cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
return 0;
}
static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
{
struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr;
u16 ccr;
sicr = in_be32(&psc->sicr);
/* Set clock phase and polarity */
if (spi->mode & SPI_CPHA)
sicr |= 0x00001000;
else
sicr &= ~0x00001000;
if (spi->mode & SPI_CPOL)
sicr |= 0x00002000;
else
sicr &= ~0x00002000;
if (spi->mode & SPI_LSB_FIRST)
sicr |= 0x10000000;
else
sicr &= ~0x10000000;
out_be32(&psc->sicr, sicr);
/* Set clock frequency and bits per word
* Because psc->ccr is defined as 16bit register instead of 32bit
* just set the lower byte of BitClkDiv
*/
ccr = in_be16((u16 __iomem *)&psc->ccr);
ccr &= 0xFF00;
if (cs->speed_hz)
ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
else /* by default SPI Clk 1MHz */
ccr |= (MCLK / 1000000 - 1) & 0xFF;
out_be16((u16 __iomem *)&psc->ccr, ccr);
mps->bits_per_word = cs->bits_per_word;
if (mps->cs_control)
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
}
static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
if (mps->cs_control)
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
}
#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
/* wake up when 80% fifo full */
#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
struct spi_transfer *t)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
unsigned rb = 0; /* number of bytes receieved */
unsigned sb = 0; /* number of bytes sent */
unsigned char *rx_buf = (unsigned char *)t->rx_buf;
unsigned char *tx_buf = (unsigned char *)t->tx_buf;
unsigned rfalarm;
unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
unsigned recv_at_once;
int last_block = 0;
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
/* enable transmiter/receiver */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
while (rb < t->len) {
if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
rfalarm = MPC52xx_PSC_RFALARM;
last_block = 0;
} else {
send_at_once = t->len - sb;
rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
last_block = 1;
}
dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
for (; send_at_once; sb++, send_at_once--) {
/* set EOF flag before the last word is sent */
if (send_at_once == 1 && last_block)
out_8(&psc->ircr2, 0x01);
if (tx_buf)
out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
else
out_8(&psc->mpc52xx_psc_buffer_8, 0);
}
/* enable interrupts and wait for wake up
* if just one byte is expected the Rx FIFO genererates no
* FFULL interrupt, so activate the RxRDY interrupt
*/
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
if (t->len - rb == 1) {
out_8(&psc->mode, 0);
} else {
out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
out_be16(&fifo->rfalarm, rfalarm);
}
out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
wait_for_completion(&mps->done);
recv_at_once = in_be16(&fifo->rfnum);
dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
send_at_once = recv_at_once;
if (rx_buf) {
for (; recv_at_once; rb++, recv_at_once--)
rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
} else {
for (; recv_at_once; rb++, recv_at_once--)
in_8(&psc->mpc52xx_psc_buffer_8);
}
}
/* disable transmiter/receiver */
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
return 0;
}
static void mpc52xx_psc_spi_work(struct work_struct *work)
{
struct mpc52xx_psc_spi *mps =
container_of(work, struct mpc52xx_psc_spi, work);
spin_lock_irq(&mps->lock);
mps->busy = 1;
while (!list_empty(&mps->queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
unsigned cs_change;
int status;
m = container_of(mps->queue.next, struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&mps->lock);
spi = m->spi;
cs_change = 1;
status = 0;
list_for_each_entry (t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
status = mpc52xx_psc_spi_transfer_setup(spi, t);
if (status < 0)
break;
}
if (cs_change)
mpc52xx_psc_spi_activate_cs(spi);
cs_change = t->cs_change;
status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
if (status)
break;
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (cs_change)
mpc52xx_psc_spi_deactivate_cs(spi);
}
m->status = status;
m->complete(m->context);
if (status || !cs_change)
mpc52xx_psc_spi_deactivate_cs(spi);
mpc52xx_psc_spi_transfer_setup(spi, NULL);
spin_lock_irq(&mps->lock);
}
mps->busy = 0;
spin_unlock_irq(&mps->lock);
}
static int mpc52xx_psc_spi_setup(struct spi_device *spi)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
unsigned long flags;
if (spi->bits_per_word%8)
return -EINVAL;
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
cs->bits_per_word = spi->bits_per_word;
cs->speed_hz = spi->max_speed_hz;
spin_lock_irqsave(&mps->lock, flags);
if (!mps->busy)
mpc52xx_psc_spi_deactivate_cs(spi);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
}
static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&mps->lock, flags);
list_add_tail(&m->queue, &mps->queue);
queue_work(mps->workqueue, &mps->work);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
}
static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
{
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
u32 mclken_div;
int ret = 0;
/* default sysclk is 512MHz */
mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK;
mpc52xx_set_psc_clkdiv(psc_id, mclken_div);
/* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX);
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable interrupts, interrupts are based on alarm level */
out_be16(&psc->mpc52xx_psc_imr, 0);
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&fifo->rfcntl, 0);
out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
/* Configure 8bit codec mode as a SPI master and use EOF flags */
/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
out_be32(&psc->sicr, 0x0180C800);
out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
/* Set 2ms DTL delay */
out_8(&psc->ctur, 0x00);
out_8(&psc->ctlr, 0x84);
mps->bits_per_word = 8;
return ret;
}
static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
{
struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
struct mpc52xx_psc __iomem *psc = mps->psc;
/* disable interrupt and wake up the work queue */
if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
out_be16(&psc->mpc52xx_psc_imr, 0);
complete(&mps->done);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/* bus_num is used only for the case dev->platform_data == NULL */
static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq, s16 bus_num)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct mpc52xx_psc_spi *mps;
struct spi_master *master;
int ret;
master = spi_alloc_master(dev, sizeof *mps);
if (master == NULL)
return -ENOMEM;
dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
mps->irq = irq;
if (pdata == NULL) {
dev_warn(dev, "probe called without platform data, no "
"cs_control function will be called\n");
mps->cs_control = NULL;
mps->sysclk = 0;
master->bus_num = bus_num;
master->num_chipselect = 255;
} else {
mps->cs_control = pdata->cs_control;
mps->sysclk = pdata->sysclk;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
}
master->setup = mpc52xx_psc_spi_setup;
master->transfer = mpc52xx_psc_spi_transfer;
master->cleanup = mpc52xx_psc_spi_cleanup;
mps->psc = ioremap(regaddr, size);
if (!mps->psc) {
dev_err(dev, "could not ioremap I/O port range\n");
ret = -EFAULT;
goto free_master;
}
/* On the 5200, fifo regs are immediately ajacent to the psc regs */
mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc);
ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
mps);
if (ret)
goto free_master;
ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
if (ret < 0)
goto free_irq;
spin_lock_init(&mps->lock);
init_completion(&mps->done);
INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
INIT_LIST_HEAD(&mps->queue);
mps->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (mps->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
ret = spi_register_master(master);
if (ret < 0)
goto unreg_master;
return ret;
unreg_master:
destroy_workqueue(mps->workqueue);
free_irq:
free_irq(mps->irq, mps);
free_master:
if (mps->psc)
iounmap(mps->psc);
spi_master_put(master);
return ret;
}
static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
flush_workqueue(mps->workqueue);
destroy_workqueue(mps->workqueue);
spi_unregister_master(master);
free_irq(mps->irq, mps);
if (mps->psc)
iounmap(mps->psc);
return 0;
}
static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
const struct of_device_id *match)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
s16 id = -1;
regaddr_p = of_get_address(op->node, 0, &size64, NULL);
if (!regaddr_p) {
printk(KERN_ERR "Invalid PSC address\n");
return -EINVAL;
}
regaddr64 = of_translate_address(op->node, regaddr_p);
/* get PSC id (1..6, used by port_config) */
if (op->dev.platform_data == NULL) {
const u32 *psc_nump;
psc_nump = of_get_property(op->node, "cell-index", NULL);
if (!psc_nump || *psc_nump > 5) {
printk(KERN_ERR "mpc52xx_psc_spi: Device node %s has invalid "
"cell-index property\n", op->node->full_name);
return -EINVAL;
}
id = *psc_nump + 1;
}
return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
irq_of_parse_and_map(op->node, 0), id);
}
static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
{
return mpc52xx_psc_spi_do_remove(&op->dev);
}
static struct of_device_id mpc52xx_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5200-psc-spi", },
{ .compatible = "mpc5200-psc-spi", }, /* old */
{}
};
MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
.owner = THIS_MODULE,
.name = "mpc52xx-psc-spi",
.match_table = mpc52xx_psc_spi_of_match,
.probe = mpc52xx_psc_spi_of_probe,
.remove = __exit_p(mpc52xx_psc_spi_of_remove),
.driver = {
.name = "mpc52xx-psc-spi",
.owner = THIS_MODULE,
},
};
static int __init mpc52xx_psc_spi_init(void)
{
return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);
}
module_init(mpc52xx_psc_spi_init);
static void __exit mpc52xx_psc_spi_exit(void)
{
of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);
}
module_exit(mpc52xx_psc_spi_exit);
MODULE_AUTHOR("Dragos Carp");
MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,592 @@
/*
* omap_uwire.c -- MicroWire interface driver for OMAP
*
* Copyright 2003 MontaVista Software Inc. <source@mvista.com>
*
* Ported to 2.6 OMAP uwire interface.
* Copyright (C) 2004 Texas Instruments.
*
* Generalization patches by Juha Yrjola <juha.yrjola@nokia.com>
*
* Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
* Copyright (C) 2006 Nokia
*
* Many updates by Imre Deak <imre.deak@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <mach/mux.h>
#include <mach/omap730.h> /* OMAP730_IO_CONF registers */
/* FIXME address is now a platform device resource,
* and irqs should show there too...
*/
#define UWIRE_BASE_PHYS 0xFFFB3000
/* uWire Registers: */
#define UWIRE_IO_SIZE 0x20
#define UWIRE_TDR 0x00
#define UWIRE_RDR 0x00
#define UWIRE_CSR 0x01
#define UWIRE_SR1 0x02
#define UWIRE_SR2 0x03
#define UWIRE_SR3 0x04
#define UWIRE_SR4 0x05
#define UWIRE_SR5 0x06
/* CSR bits */
#define RDRB (1 << 15)
#define CSRB (1 << 14)
#define START (1 << 13)
#define CS_CMD (1 << 12)
/* SR1 or SR2 bits */
#define UWIRE_READ_FALLING_EDGE 0x0001
#define UWIRE_READ_RISING_EDGE 0x0000
#define UWIRE_WRITE_FALLING_EDGE 0x0000
#define UWIRE_WRITE_RISING_EDGE 0x0002
#define UWIRE_CS_ACTIVE_LOW 0x0000
#define UWIRE_CS_ACTIVE_HIGH 0x0004
#define UWIRE_FREQ_DIV_2 0x0000
#define UWIRE_FREQ_DIV_4 0x0008
#define UWIRE_FREQ_DIV_8 0x0010
#define UWIRE_CHK_READY 0x0020
#define UWIRE_CLK_INVERTED 0x0040
struct uwire_spi {
struct spi_bitbang bitbang;
struct clk *ck;
};
struct uwire_state {
unsigned bits_per_word;
unsigned div1_idx;
};
/* REVISIT compile time constant for idx_shift? */
/*
* Or, put it in a structure which is used throughout the driver;
* that avoids having to issue two loads for each bit of static data.
*/
static unsigned int uwire_idx_shift;
static void __iomem *uwire_base;
static inline void uwire_write_reg(int idx, u16 val)
{
__raw_writew(val, uwire_base + (idx << uwire_idx_shift));
}
static inline u16 uwire_read_reg(int idx)
{
return __raw_readw(uwire_base + (idx << uwire_idx_shift));
}
static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
{
u16 w, val = 0;
int shift, reg;
if (flags & UWIRE_CLK_INVERTED)
val ^= 0x03;
val = flags & 0x3f;
if (cs & 1)
shift = 6;
else
shift = 0;
if (cs <= 1)
reg = UWIRE_SR1;
else
reg = UWIRE_SR2;
w = uwire_read_reg(reg);
w &= ~(0x3f << shift);
w |= val << shift;
uwire_write_reg(reg, w);
}
static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
{
u16 w;
int c = 0;
unsigned long max_jiffies = jiffies + HZ;
for (;;) {
w = uwire_read_reg(UWIRE_CSR);
if ((w & mask) == val)
break;
if (time_after(jiffies, max_jiffies)) {
printk(KERN_ERR "%s: timeout. reg=%#06x "
"mask=%#06x val=%#06x\n",
__func__, w, mask, val);
return -1;
}
c++;
if (might_not_catch && c > 64)
break;
}
return 0;
}
static void uwire_set_clk1_div(int div1_idx)
{
u16 w;
w = uwire_read_reg(UWIRE_SR3);
w &= ~(0x03 << 1);
w |= div1_idx << 1;
uwire_write_reg(UWIRE_SR3, w);
}
static void uwire_chipselect(struct spi_device *spi, int value)
{
struct uwire_state *ust = spi->controller_state;
u16 w;
int old_cs;
BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
w = uwire_read_reg(UWIRE_CSR);
old_cs = (w >> 10) & 0x03;
if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
/* Deselect this CS, or the previous CS */
w &= ~CS_CMD;
uwire_write_reg(UWIRE_CSR, w);
}
/* activate specfied chipselect */
if (value == BITBANG_CS_ACTIVE) {
uwire_set_clk1_div(ust->div1_idx);
/* invert clock? */
if (spi->mode & SPI_CPOL)
uwire_write_reg(UWIRE_SR4, 1);
else
uwire_write_reg(UWIRE_SR4, 0);
w = spi->chip_select << 10;
w |= CS_CMD;
uwire_write_reg(UWIRE_CSR, w);
}
}
static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct uwire_state *ust = spi->controller_state;
unsigned len = t->len;
unsigned bits = ust->bits_per_word;
unsigned bytes;
u16 val, w;
int status = 0;
if (!t->tx_buf && !t->rx_buf)
return 0;
/* Microwire doesn't read and write concurrently */
if (t->tx_buf && t->rx_buf)
return -EPERM;
w = spi->chip_select << 10;
w |= CS_CMD;
if (t->tx_buf) {
const u8 *buf = t->tx_buf;
/* NOTE: DMA could be used for TX transfers */
/* write one or two bytes at a time */
while (len >= 1) {
/* tx bit 15 is first sent; we byteswap multibyte words
* (msb-first) on the way out from memory.
*/
val = *buf++;
if (bits > 8) {
bytes = 2;
val |= *buf++ << 8;
} else
bytes = 1;
val <<= 16 - bits;
#ifdef VERBOSE
pr_debug("%s: write-%d =%04x\n",
dev_name(&spi->dev), bits, val);
#endif
if (wait_uwire_csr_flag(CSRB, 0, 0))
goto eio;
uwire_write_reg(UWIRE_TDR, val);
/* start write */
val = START | w | (bits << 5);
uwire_write_reg(UWIRE_CSR, val);
len -= bytes;
/* Wait till write actually starts.
* This is needed with MPU clock 60+ MHz.
* REVISIT: we may not have time to catch it...
*/
if (wait_uwire_csr_flag(CSRB, CSRB, 1))
goto eio;
status += bytes;
}
/* REVISIT: save this for later to get more i/o overlap */
if (wait_uwire_csr_flag(CSRB, 0, 0))
goto eio;
} else if (t->rx_buf) {
u8 *buf = t->rx_buf;
/* read one or two bytes at a time */
while (len) {
if (bits > 8) {
bytes = 2;
} else
bytes = 1;
/* start read */
val = START | w | (bits << 0);
uwire_write_reg(UWIRE_CSR, val);
len -= bytes;
/* Wait till read actually starts */
(void) wait_uwire_csr_flag(CSRB, CSRB, 1);
if (wait_uwire_csr_flag(RDRB | CSRB,
RDRB, 0))
goto eio;
/* rx bit 0 is last received; multibyte words will
* be properly byteswapped on the way to memory.
*/
val = uwire_read_reg(UWIRE_RDR);
val &= (1 << bits) - 1;
*buf++ = (u8) val;
if (bytes == 2)
*buf++ = val >> 8;
status += bytes;
#ifdef VERBOSE
pr_debug("%s: read-%d =%04x\n",
dev_name(&spi->dev), bits, val);
#endif
}
}
return status;
eio:
return -EIO;
}
static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct uwire_state *ust = spi->controller_state;
struct uwire_spi *uwire;
unsigned flags = 0;
unsigned bits;
unsigned hz;
unsigned long rate;
int div1_idx;
int div1;
int div2;
int status;
uwire = spi_master_get_devdata(spi->master);
if (spi->chip_select > 3) {
pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
status = -ENODEV;
goto done;
}
bits = spi->bits_per_word;
if (t != NULL && t->bits_per_word)
bits = t->bits_per_word;
if (bits > 16) {
pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
status = -ENODEV;
goto done;
}
ust->bits_per_word = bits;
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
* don't treat DI=high as "not ready"
*/
if (spi->mode & SPI_CS_HIGH)
flags |= UWIRE_CS_ACTIVE_HIGH;
if (spi->mode & SPI_CPOL)
flags |= UWIRE_CLK_INVERTED;
switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
case SPI_MODE_0:
case SPI_MODE_3:
flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
break;
case SPI_MODE_1:
case SPI_MODE_2:
flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE;
break;
}
/* assume it's already enabled */
rate = clk_get_rate(uwire->ck);
hz = spi->max_speed_hz;
if (t != NULL && t->speed_hz)
hz = t->speed_hz;
if (!hz) {
pr_debug("%s: zero speed?\n", dev_name(&spi->dev));
status = -EINVAL;
goto done;
}
/* F_INT = mpu_xor_clk / DIV1 */
for (div1_idx = 0; div1_idx < 4; div1_idx++) {
switch (div1_idx) {
case 0:
div1 = 2;
break;
case 1:
div1 = 4;
break;
case 2:
div1 = 7;
break;
default:
case 3:
div1 = 10;
break;
}
div2 = (rate / div1 + hz - 1) / hz;
if (div2 <= 8)
break;
}
if (div1_idx == 4) {
pr_debug("%s: lowest clock %ld, need %d\n",
dev_name(&spi->dev), rate / 10 / 8, hz);
status = -EDOM;
goto done;
}
/* we have to cache this and reset in uwire_chipselect as this is a
* global parameter and another uwire device can change it under
* us */
ust->div1_idx = div1_idx;
uwire_set_clk1_div(div1_idx);
rate /= div1;
switch (div2) {
case 0:
case 1:
case 2:
flags |= UWIRE_FREQ_DIV_2;
rate /= 2;
break;
case 3:
case 4:
flags |= UWIRE_FREQ_DIV_4;
rate /= 4;
break;
case 5:
case 6:
case 7:
case 8:
flags |= UWIRE_FREQ_DIV_8;
rate /= 8;
break;
}
omap_uwire_configure_mode(spi->chip_select, flags);
pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n",
__func__, flags,
clk_get_rate(uwire->ck) / 1000,
rate / 1000);
status = 0;
done:
return status;
}
static int uwire_setup(struct spi_device *spi)
{
struct uwire_state *ust = spi->controller_state;
if (ust == NULL) {
ust = kzalloc(sizeof(*ust), GFP_KERNEL);
if (ust == NULL)
return -ENOMEM;
spi->controller_state = ust;
}
return uwire_setup_transfer(spi, NULL);
}
static void uwire_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static void uwire_off(struct uwire_spi *uwire)
{
uwire_write_reg(UWIRE_SR3, 0);
clk_disable(uwire->ck);
clk_put(uwire->ck);
spi_master_put(uwire->bitbang.master);
}
static int __init uwire_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct uwire_spi *uwire;
int status;
master = spi_alloc_master(&pdev->dev, sizeof *uwire);
if (!master)
return -ENODEV;
uwire = spi_master_get_devdata(master);
uwire_base = ioremap(UWIRE_BASE_PHYS, UWIRE_IO_SIZE);
if (!uwire_base) {
dev_dbg(&pdev->dev, "can't ioremap UWIRE\n");
spi_master_put(master);
return -ENOMEM;
}
dev_set_drvdata(&pdev->dev, uwire);
uwire->ck = clk_get(&pdev->dev, "fck");
if (IS_ERR(uwire->ck)) {
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
spi_master_put(master);
return status;
}
clk_enable(uwire->ck);
if (cpu_is_omap730())
uwire_idx_shift = 1;
else
uwire_idx_shift = 2;
uwire_write_reg(UWIRE_SR3, 1);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
master->num_chipselect = 4;
master->setup = uwire_setup;
master->cleanup = uwire_cleanup;
uwire->bitbang.master = master;
uwire->bitbang.chipselect = uwire_chipselect;
uwire->bitbang.setup_transfer = uwire_setup_transfer;
uwire->bitbang.txrx_bufs = uwire_txrx;
status = spi_bitbang_start(&uwire->bitbang);
if (status < 0) {
uwire_off(uwire);
iounmap(uwire_base);
}
return status;
}
static int __exit uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
int status;
// FIXME remove all child devices, somewhere ...
status = spi_bitbang_stop(&uwire->bitbang);
uwire_off(uwire);
iounmap(uwire_base);
return status;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:omap_uwire");
static struct platform_driver uwire_driver = {
.driver = {
.name = "omap_uwire",
.owner = THIS_MODULE,
},
.remove = __exit_p(uwire_remove),
// suspend ... unuse ck
// resume ... use ck
};
static int __init omap_uwire_init(void)
{
/* FIXME move these into the relevant board init code. also, include
* H3 support; it uses tsc2101 like H2 (on a different chipselect).
*/
if (machine_is_omap_h2()) {
/* defaults: W21 SDO, U18 SDI, V19 SCL */
omap_cfg_reg(N14_1610_UWIRE_CS0);
omap_cfg_reg(N15_1610_UWIRE_CS1);
}
if (machine_is_omap_perseus2()) {
/* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
}
return platform_driver_probe(&uwire_driver, uwire_probe);
}
static void __exit omap_uwire_exit(void)
{
platform_driver_unregister(&uwire_driver);
}
subsys_initcall(omap_uwire_init);
module_exit(omap_uwire_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,573 @@
/*
* orion_spi.c -- Marvell Orion SPI controller driver
*
* Author: Shadi Ammouri <shadi@marvell.com>
* Copyright (C) 2007-2008 Marvell Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/spi/orion_spi.h>
#include <asm/unaligned.h>
#define DRIVER_NAME "orion_spi"
#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/
#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
#define ORION_SPI_IF_CTRL_REG 0x00
#define ORION_SPI_IF_CONFIG_REG 0x04
#define ORION_SPI_DATA_OUT_REG 0x08
#define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10
#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
struct orion_spi {
struct work_struct work;
/* Lock access to transfer list. */
spinlock_t lock;
struct list_head msg_queue;
struct spi_master *master;
void __iomem *base;
unsigned int max_speed;
unsigned int min_speed;
struct orion_spi_info *spi_info;
};
static struct workqueue_struct *orion_spi_wq;
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
{
return orion_spi->base + reg;
}
static inline void
orion_spi_setbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
{
void __iomem *reg_addr = spi_reg(orion_spi, reg);
u32 val;
val = readl(reg_addr);
val |= mask;
writel(val, reg_addr);
}
static inline void
orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
{
void __iomem *reg_addr = spi_reg(orion_spi, reg);
u32 val;
val = readl(reg_addr);
val &= ~mask;
writel(val, reg_addr);
}
static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
{
if (size == 16) {
orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
} else if (size == 8) {
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
} else {
pr_debug("Bad bits per word value %d (only 8 or 16 are "
"allowed).\n", size);
return -EINVAL;
}
return 0;
}
static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
u32 tclk_hz;
u32 rate;
u32 prescale;
u32 reg;
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
tclk_hz = orion_spi->spi_info->tclk;
/*
* the supported rates are: 4,6,8...30
* round up as we look for equal or less speed
*/
rate = DIV_ROUND_UP(tclk_hz, speed);
rate = roundup(rate, 2);
/* check if requested speed is too small */
if (rate > 30)
return -EINVAL;
if (rate < 4)
rate = 4;
/* Convert the rate to SPI clock divisor value. */
prescale = 0x10 + rate/2;
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale);
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
return 0;
}
/*
* called only when no transfer is active on the bus
*/
static int
orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct orion_spi *orion_spi;
unsigned int speed = spi->max_speed_hz;
unsigned int bits_per_word = spi->bits_per_word;
int rc;
orion_spi = spi_master_get_devdata(spi->master);
if ((t != NULL) && t->speed_hz)
speed = t->speed_hz;
if ((t != NULL) && t->bits_per_word)
bits_per_word = t->bits_per_word;
rc = orion_spi_baudrate_set(spi, speed);
if (rc)
return rc;
return orion_spi_set_transfer_size(orion_spi, bits_per_word);
}
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
{
if (enable)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
else
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
}
static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
{
int i;
for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) {
if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG)))
return 1;
else
udelay(1);
}
return -1;
}
static inline int
orion_spi_write_read_8bit(struct spi_device *spi,
const u8 **tx_buf, u8 **rx_buf)
{
void __iomem *tx_reg, *rx_reg, *int_reg;
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
/* clear the interrupt cause register */
writel(0x0, int_reg);
if (tx_buf && *tx_buf)
writel(*(*tx_buf)++, tx_reg);
else
writel(0, tx_reg);
if (orion_spi_wait_till_ready(orion_spi) < 0) {
dev_err(&spi->dev, "TXS timed out\n");
return -1;
}
if (rx_buf && *rx_buf)
*(*rx_buf)++ = readl(rx_reg);
return 1;
}
static inline int
orion_spi_write_read_16bit(struct spi_device *spi,
const u16 **tx_buf, u16 **rx_buf)
{
void __iomem *tx_reg, *rx_reg, *int_reg;
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
/* clear the interrupt cause register */
writel(0x0, int_reg);
if (tx_buf && *tx_buf)
writel(__cpu_to_le16(get_unaligned((*tx_buf)++)), tx_reg);
else
writel(0, tx_reg);
if (orion_spi_wait_till_ready(orion_spi) < 0) {
dev_err(&spi->dev, "TXS timed out\n");
return -1;
}
if (rx_buf && *rx_buf)
put_unaligned(__le16_to_cpu(readl(rx_reg)), (*rx_buf)++);
return 1;
}
static unsigned int
orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
struct orion_spi *orion_spi;
unsigned int count;
int word_len;
orion_spi = spi_master_get_devdata(spi->master);
word_len = spi->bits_per_word;
count = xfer->len;
if (word_len == 8) {
const u8 *tx = xfer->tx_buf;
u8 *rx = xfer->rx_buf;
do {
if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
goto out;
count--;
} while (count);
} else if (word_len == 16) {
const u16 *tx = xfer->tx_buf;
u16 *rx = xfer->rx_buf;
do {
if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
goto out;
count -= 2;
} while (count);
}
out:
return xfer->len - count;
}
static void orion_spi_work(struct work_struct *work)
{
struct orion_spi *orion_spi =
container_of(work, struct orion_spi, work);
spin_lock_irq(&orion_spi->lock);
while (!list_empty(&orion_spi->msg_queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
int par_override = 0;
int status = 0;
int cs_active = 0;
m = container_of(orion_spi->msg_queue.next, struct spi_message,
queue);
list_del_init(&m->queue);
spin_unlock_irq(&orion_spi->lock);
spi = m->spi;
/* Load defaults */
status = orion_spi_setup_transfer(spi, NULL);
if (status < 0)
goto msg_done;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (par_override || t->speed_hz || t->bits_per_word) {
par_override = 1;
status = orion_spi_setup_transfer(spi, t);
if (status < 0)
break;
if (!t->speed_hz && !t->bits_per_word)
par_override = 0;
}
if (!cs_active) {
orion_spi_set_cs(orion_spi, 1);
cs_active = 1;
}
if (t->len)
m->actual_length +=
orion_spi_write_read(spi, t);
if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change) {
orion_spi_set_cs(orion_spi, 0);
cs_active = 0;
}
}
msg_done:
if (cs_active)
orion_spi_set_cs(orion_spi, 0);
m->status = status;
m->complete(m->context);
spin_lock_irq(&orion_spi->lock);
}
spin_unlock_irq(&orion_spi->lock);
}
static int __init orion_spi_reset(struct orion_spi *orion_spi)
{
/* Verify that the CS is deasserted */
orion_spi_set_cs(orion_spi, 0);
return 0;
}
static int orion_spi_setup(struct spi_device *spi)
{
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
/* Fix ac timing if required. */
if (orion_spi->spi_info->enable_clock_fix)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
(1 << 14));
if ((spi->max_speed_hz == 0)
|| (spi->max_speed_hz > orion_spi->max_speed))
spi->max_speed_hz = orion_spi->max_speed;
if (spi->max_speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
spi->max_speed_hz);
return -EINVAL;
}
/*
* baudrate & width will be set orion_spi_setup_transfer
*/
return 0;
}
static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct orion_spi *orion_spi;
struct spi_transfer *t = NULL;
unsigned long flags;
m->actual_length = 0;
m->status = 0;
/* reject invalid messages and transfers */
if (list_empty(&m->transfers) || !m->complete)
return -EINVAL;
orion_spi = spi_master_get_devdata(spi->master);
list_for_each_entry(t, &m->transfers, transfer_list) {
unsigned int bits_per_word = spi->bits_per_word;
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
dev_err(&spi->dev,
"message rejected : "
"invalid transfer data buffers\n");
goto msg_rejected;
}
if ((t != NULL) && t->bits_per_word)
bits_per_word = t->bits_per_word;
if ((bits_per_word != 8) && (bits_per_word != 16)) {
dev_err(&spi->dev,
"message rejected : "
"invalid transfer bits_per_word (%d bits)\n",
bits_per_word);
goto msg_rejected;
}
/*make sure buffer length is even when working in 16 bit mode*/
if ((t != NULL) && (t->bits_per_word == 16) && (t->len & 1)) {
dev_err(&spi->dev,
"message rejected : "
"odd data length (%d) while in 16 bit mode\n",
t->len);
goto msg_rejected;
}
if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev,
"message rejected : "
"device min speed (%d Hz) exceeds "
"required transfer speed (%d Hz)\n",
orion_spi->min_speed, t->speed_hz);
goto msg_rejected;
}
}
spin_lock_irqsave(&orion_spi->lock, flags);
list_add_tail(&m->queue, &orion_spi->msg_queue);
queue_work(orion_spi_wq, &orion_spi->work);
spin_unlock_irqrestore(&orion_spi->lock, flags);
return 0;
msg_rejected:
/* Message rejected and not queued */
m->status = -EINVAL;
if (m->complete)
m->complete(m->context);
return -EINVAL;
}
static int __init orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct orion_spi *spi;
struct resource *r;
struct orion_spi_info *spi_info;
int status = 0;
spi_info = pdev->dev.platform_data;
master = spi_alloc_master(&pdev->dev, sizeof *spi);
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
master->bus_num = pdev->id;
/* we support only mode 0, and no options */
master->mode_bits = 0;
master->setup = orion_spi_setup;
master->transfer = orion_spi_transfer;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
dev_set_drvdata(&pdev->dev, master);
spi = spi_master_get_devdata(master);
spi->master = master;
spi->spi_info = spi_info;
spi->max_speed = DIV_ROUND_UP(spi_info->tclk, 4);
spi->min_speed = DIV_ROUND_UP(spi_info->tclk, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
status = -ENODEV;
goto out;
}
if (!request_mem_region(r->start, (r->end - r->start) + 1,
dev_name(&pdev->dev))) {
status = -EBUSY;
goto out;
}
spi->base = ioremap(r->start, SZ_1K);
INIT_WORK(&spi->work, orion_spi_work);
spin_lock_init(&spi->lock);
INIT_LIST_HEAD(&spi->msg_queue);
if (orion_spi_reset(spi) < 0)
goto out_rel_mem;
status = spi_register_master(master);
if (status < 0)
goto out_rel_mem;
return status;
out_rel_mem:
release_mem_region(r->start, (r->end - r->start) + 1);
out:
spi_master_put(master);
return status;
}
static int __exit orion_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct orion_spi *spi;
struct resource *r;
master = dev_get_drvdata(&pdev->dev);
spi = spi_master_get_devdata(master);
cancel_work_sync(&spi->work);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, (r->end - r->start) + 1);
spi_unregister_master(master);
return 0;
}
MODULE_ALIAS("platform:" DRIVER_NAME);
static struct platform_driver orion_spi_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.remove = __exit_p(orion_spi_remove),
};
static int __init orion_spi_init(void)
{
orion_spi_wq = create_singlethread_workqueue(
orion_spi_driver.driver.name);
if (orion_spi_wq == NULL)
return -ENOMEM;
return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
}
module_init(orion_spi_init);
static void __exit orion_spi_exit(void)
{
flush_workqueue(orion_spi_wq);
platform_driver_unregister(&orion_spi_driver);
destroy_workqueue(orion_spi_wq);
}
module_exit(orion_spi_exit);
MODULE_DESCRIPTION("Orion SPI driver");
MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

893
kernel/drivers/spi/spi.c Normal file
View File

@@ -0,0 +1,893 @@
/*
* spi.c - SPI init/core code
*
* Copyright (C) 2005 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
/* SPI bustype and spi_master class are registered after board init code
* provides the SPI device tables, ensuring that both are present by the
* time controller driver registration causes spi_devices to "enumerate".
*/
static void spidev_release(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
/* spi masters may cleanup for released devices */
if (spi->master->cleanup)
spi->master->cleanup(spi);
spi_master_put(spi->master);
kfree(dev);
}
static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
const struct spi_device *spi = to_spi_device(dev);
return sprintf(buf, "%s\n", spi->modalias);
}
static struct device_attribute spi_dev_attrs[] = {
__ATTR_RO(modalias),
__ATTR_NULL,
};
/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
* and the sysfs version makes coldplug work too.
*/
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
const struct spi_device *sdev)
{
while (id->name[0]) {
if (!strcmp(sdev->modalias, id->name))
return id;
id++;
}
return NULL;
}
const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
{
const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver);
return spi_match_id(sdrv->id_table, sdev);
}
EXPORT_SYMBOL_GPL(spi_get_device_id);
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);
return strcmp(spi->modalias, drv->name) == 0;
}
static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
return 0;
}
#ifdef CONFIG_PM
static int spi_suspend(struct device *dev, pm_message_t message)
{
int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
/* suspend will stop irqs and dma; no more i/o */
if (drv) {
if (drv->suspend)
value = drv->suspend(to_spi_device(dev), message);
else
dev_dbg(dev, "... can't suspend\n");
}
return value;
}
static int spi_resume(struct device *dev)
{
int value = 0;
struct spi_driver *drv = to_spi_driver(dev->driver);
/* resume may restart the i/o queue */
if (drv) {
if (drv->resume)
value = drv->resume(to_spi_device(dev));
else
dev_dbg(dev, "... can't resume\n");
}
return value;
}
#else
#define spi_suspend NULL
#define spi_resume NULL
#endif
struct bus_type spi_bus_type = {
.name = "spi",
.dev_attrs = spi_dev_attrs,
.match = spi_match_device,
.uevent = spi_uevent,
.suspend = spi_suspend,
.resume = spi_resume,
};
EXPORT_SYMBOL_GPL(spi_bus_type);
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
return sdrv->probe(to_spi_device(dev));
}
static int spi_drv_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
return sdrv->remove(to_spi_device(dev));
}
static void spi_drv_shutdown(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
sdrv->shutdown(to_spi_device(dev));
}
/**
* spi_register_driver - register a SPI driver
* @sdrv: the driver to register
* Context: can sleep
*/
int spi_register_driver(struct spi_driver *sdrv)
{
sdrv->driver.bus = &spi_bus_type;
if (sdrv->probe)
sdrv->driver.probe = spi_drv_probe;
if (sdrv->remove)
sdrv->driver.remove = spi_drv_remove;
if (sdrv->shutdown)
sdrv->driver.shutdown = spi_drv_shutdown;
return driver_register(&sdrv->driver);
}
EXPORT_SYMBOL_GPL(spi_register_driver);
/*-------------------------------------------------------------------------*/
/* SPI devices should normally not be created by SPI device drivers; that
* would make them board-specific. Similarly with SPI master drivers.
* Device registration normally goes into like arch/.../mach.../board-YYY.c
* with other readonly (flashable) information about mainboard devices.
*/
struct boardinfo {
struct list_head list;
unsigned n_board_info;
struct spi_board_info board_info[0];
};
static LIST_HEAD(board_list);
static DEFINE_MUTEX(board_lock);
/**
* spi_alloc_device - Allocate a new SPI device
* @master: Controller to which device is connected
* Context: can sleep
*
* Allows a driver to allocate and initialize a spi_device without
* registering it immediately. This allows a driver to directly
* fill the spi_device with device parameters before calling
* spi_add_device() on it.
*
* Caller is responsible to call spi_add_device() on the returned
* spi_device structure to add it to the SPI master. If the caller
* needs to discard the spi_device without adding it, then it should
* call spi_dev_put() on it.
*
* Returns a pointer to the new device, or NULL.
*/
struct spi_device *spi_alloc_device(struct spi_master *master)
{
struct spi_device *spi;
struct device *dev = master->dev.parent;
if (!spi_master_get(master))
return NULL;
spi = kzalloc(sizeof *spi, GFP_KERNEL);
if (!spi) {
dev_err(dev, "cannot alloc spi_device\n");
spi_master_put(master);
return NULL;
}
spi->master = master;
spi->dev.parent = dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
device_initialize(&spi->dev);
return spi;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
*
* Companion function to spi_alloc_device. Devices allocated with
* spi_alloc_device can be added onto the spi bus with this function.
*
* Returns 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
struct device *dev = spi->master->dev.parent;
int status;
/* Chipselects are numbered 0..max; validate. */
if (spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
spi->master->num_chipselect);
return -EINVAL;
}
/* Set the bus ID string */
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select);
/* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
* its configuration. Lock against concurrent add() calls.
*/
mutex_lock(&spi_add_lock);
if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
!= NULL) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
status = -EBUSY;
goto done;
}
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
status = spi_setup(spi);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", dev_name(&spi->dev), status);
goto done;
}
/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < 0)
dev_err(dev, "can't %s %s, status %d\n",
"add", dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
done:
mutex_unlock(&spi_add_lock);
return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
/**
* spi_new_device - instantiate one new SPI device
* @master: Controller to which device is connected
* @chip: Describes the SPI device
* Context: can sleep
*
* On typical mainboards, this is purely internal; and it's not needed
* after board init creates the hard-wired devices. Some development
* platforms may not be able to use spi_register_board_info though, and
* this is exported so that for example a USB or parport based adapter
* driver could add devices (which it would learn about out-of-band).
*
* Returns the new device, or NULL.
*/
struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
*
* Also, unless we change the return value convention to use
* error-or-pointer (not NULL-or-pointer), troubleshootability
* suggests syslogged diagnostics are best here (ugh).
*/
proxy = spi_alloc_device(master);
if (!proxy)
return NULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
status = spi_add_device(proxy);
if (status < 0) {
spi_dev_put(proxy);
return NULL;
}
return proxy;
}
EXPORT_SYMBOL_GPL(spi_new_device);
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
* @n: how many descriptors are provided
* Context: can sleep
*
* Board-specific early init code calls this (probably during arch_initcall)
* with segments of the SPI device table. Any device nodes are created later,
* after the relevant parent SPI controller (bus_num) is defined. We keep
* this table of devices forever, so that reloading a controller driver will
* not make Linux forget about these hard-wired devices.
*
* Other code can also call this, e.g. a particular add-on board might provide
* SPI devices through its expansion connector, so code initializing that board
* would naturally declare its SPI devices.
*
* The board info passed can safely be __initdata ... but be careful of
* any embedded pointers (platform_data, etc), they're copied as-is.
*/
int __init
spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
struct boardinfo *bi;
bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
if (!bi)
return -ENOMEM;
bi->n_board_info = n;
memcpy(bi->board_info, info, n * sizeof *info);
mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
mutex_unlock(&board_lock);
return 0;
}
/* FIXME someone should add support for a __setup("spi", ...) that
* creates board info from kernel command lines
*/
static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info *chip = bi->board_info;
unsigned n;
for (n = bi->n_board_info; n > 0; n--, chip++) {
if (chip->bus_num != master->bus_num)
continue;
/* NOTE: this relies on spi_new_device to
* issue diagnostics when given bogus inputs
*/
(void) spi_new_device(master, chip);
}
}
mutex_unlock(&board_lock);
}
/*-------------------------------------------------------------------------*/
static void spi_master_release(struct device *dev)
{
struct spi_master *master;
master = container_of(dev, struct spi_master, dev);
kfree(master);
}
static struct class spi_master_class = {
.name = "spi_master",
.owner = THIS_MODULE,
.dev_release = spi_master_release,
};
/**
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
* @size: how much zeroed driver-private data to allocate; the pointer to this
* memory is in the driver_data field of the returned device,
* accessible with spi_master_get_devdata().
* Context: can sleep
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers. It's how they allocate
* an spi_master structure, prior to calling spi_register_master().
*
* This must be called from context that can sleep. It returns the SPI
* master structure on success, else NULL.
*
* The caller is responsible for assigning the bus number and initializing
* the master's methods before calling spi_register_master(); and (after errors
* adding the device) calling spi_master_put() to prevent a memory leak.
*/
struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
struct spi_master *master;
if (!dev)
return NULL;
master = kzalloc(size + sizeof *master, GFP_KERNEL);
if (!master)
return NULL;
device_initialize(&master->dev);
master->dev.class = &spi_master_class;
master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[1]);
return master;
}
EXPORT_SYMBOL_GPL(spi_alloc_master);
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
* Context: can sleep
*
* SPI master controllers connect to their drivers using some non-SPI bus,
* such as the platform bus. The final stage of probe() in that code
* includes calling spi_register_master() to hook up to this SPI bus glue.
*
* SPI controllers use board specific (often SOC specific) bus numbers,
* and board-specific addressing for SPI devices combines those numbers
* with chip select numbers. Since SPI does not directly support dynamic
* device identification, boards need configuration tables telling which
* chip is at which address.
*
* This must be called from context that can sleep. It returns zero on
* success, else a negative error code (dropping the master's refcount).
* After a successful return, the caller is responsible for calling
* spi_unregister_master().
*/
int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = master->dev.parent;
int status = -ENODEV;
int dynamic = 0;
if (!dev)
return -ENODEV;
/* even if it's just one always-selected device, there must
* be at least one chipselect
*/
if (master->num_chipselect == 0)
return -EINVAL;
/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) {
/* FIXME switch to an IDR based scheme, something like
* I2C now uses, so we can't run out of "dynamic" IDs
*/
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = 1;
}
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
done:
return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);
static int __unregister(struct device *dev, void *master_dev)
{
/* note: before about 2.6.14-rc1 this would corrupt memory: */
if (dev != master_dev)
spi_unregister_device(to_spi_device(dev));
return 0;
}
/**
* spi_unregister_master - unregister SPI master controller
* @master: the master being unregistered
* Context: can sleep
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers.
*
* This must be called from context that can sleep.
*/
void spi_unregister_master(struct spi_master *master)
{
int dummy;
dummy = device_for_each_child(master->dev.parent, &master->dev,
__unregister);
device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
static int __spi_master_match(struct device *dev, void *data)
{
struct spi_master *m;
u16 *bus_num = data;
m = container_of(dev, struct spi_master, dev);
return m->bus_num == *bus_num;
}
/**
* spi_busnum_to_master - look up master associated with bus_num
* @bus_num: the master's bus number
* Context: can sleep
*
* This call may be used with devices that are registered after
* arch init time. It returns a refcounted pointer to the relevant
* spi_master (which the caller must release), or NULL if there is
* no such master registered.
*/
struct spi_master *spi_busnum_to_master(u16 bus_num)
{
struct device *dev;
struct spi_master *master = NULL;
dev = class_find_device(&spi_master_class, NULL, &bus_num,
__spi_master_match);
if (dev)
master = container_of(dev, struct spi_master, dev);
/* reference got in class_find_device */
return master;
}
EXPORT_SYMBOL_GPL(spi_busnum_to_master);
/*-------------------------------------------------------------------------*/
/* Core methods for SPI master protocol drivers. Some of the
* other core methods are currently defined as inline functions.
*/
/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
*
* SPI protocol drivers may need to update the transfer mode if the
* device doesn't work with its default. They may likewise need
* to update clock rates or word sizes from initial values. This function
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
* or from it. When this function returns, the spi device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
* example, not all hardware supports wire transfers using nine bit words,
* LSB-first wire encoding, or active-high chipselects.
*/
int spi_setup(struct spi_device *spi)
{
unsigned bad_bits;
int status;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
bad_bits = spi->mode & ~spi->master->mode_bits;
if (bad_bits) {
dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}
if (!spi->bits_per_word)
spi->bits_per_word = 8;
status = spi->master->setup(spi);
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
"%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
(spi->mode & SPI_3WIRE) ? "3wire, " : "",
(spi->mode & SPI_LOOP) ? "loopback, " : "",
spi->bits_per_word, spi->max_speed_hz,
status);
return status;
}
EXPORT_SYMBOL_GPL(spi_setup);
/**
* spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
* Context: any (irqs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
*
* The completion callback is invoked in a context which can't sleep.
* Before that invocation, the value of message->status is undefined.
* When the callback is issued, message->status holds either zero (to
* indicate complete success) or a negative error code. After that
* callback returns, the driver which issued the transfer request may
* deallocate the associated memory; it's no longer in use by any SPI
* core or controller driver code.
*
* Note that although all messages to a spi_device are handled in
* FIFO order, messages may go to different devices in other orders.
* Some device might be higher priority, or have various "hard" access
* time requirements, for example.
*
* On detection of any fault during the transfer, processing of
* the entire message is aborted, and the device is deselected.
* Until returning from the associated message completion callback,
* no other spi_message queued to that device will be processed.
* (This rule applies equally to all the synchronous transfer calls,
* which are wrappers around this core asynchronous primitive.)
*/
int spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by
* software limitations.
*/
if ((master->flags & SPI_MASTER_HALF_DUPLEX)
|| (spi->mode & SPI_3WIRE)) {
struct spi_transfer *xfer;
unsigned flags = master->flags;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
if (xfer->rx_buf && xfer->tx_buf)
return -EINVAL;
if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
return -EINVAL;
if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
return -EINVAL;
}
}
message->spi = spi;
message->status = -EINPROGRESS;
return master->transfer(spi, message);
}
EXPORT_SYMBOL_GPL(spi_async);
/*-------------------------------------------------------------------------*/
/* Utility methods for SPI master protocol drivers, layered on
* top of the core. Some other utility methods are defined as
* inline functions.
*/
static void spi_complete(void *arg)
{
complete(arg);
}
/**
* spi_sync - blocking/synchronous SPI data transfers
* @spi: device with which data will be exchanged
* @message: describes the data transfers
* Context: can sleep
*
* This call may only be used from a context that may sleep. The sleep
* is non-interruptible, and has no timeout. Low-overhead controller
* drivers may DMA directly into and out of the message buffers.
*
* Note that the SPI device's chip select is active during the message,
* and then is normally disabled between messages. Drivers for some
* frequently-used devices may want to minimize costs of selecting a chip,
* by leaving it selected in anticipation that the next message will go
* to the same chip. (That may increase power usage.)
*
* Also, the caller is guaranteeing that the memory associated with the
* message will not be freed before this call returns.
*
* It returns zero on success, else a negative error code.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = spi_complete;
message->context = &done;
status = spi_async(spi, message);
if (status == 0) {
wait_for_completion(&done);
status = message->status;
}
message->context = NULL;
return status;
}
EXPORT_SYMBOL_GPL(spi_sync);
/* portable code must never pass more than 32 bytes */
#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
static u8 *buf;
/**
* spi_write_then_read - SPI synchronous write followed by read
* @spi: device with which data will be exchanged
* @txbuf: data to be written (need not be dma-safe)
* @n_tx: size of txbuf, in bytes
* @rxbuf: buffer into which data will be read (need not be dma-safe)
* @n_rx: size of rxbuf, in bytes
* Context: can sleep
*
* This performs a half duplex MicroWire style transaction with the
* device, sending txbuf and then reading rxbuf. The return value
* is zero for success, else a negative errno status code.
* This call may only be used from a context that may sleep.
*
* Parameters to this routine are always copied using a small buffer;
* portable code should never use this for more than 32 bytes.
* Performance-sensitive or bulk transfer code should instead use
* spi_{async,sync}() calls with dma-safe buffers.
*/
int spi_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx)
{
static DEFINE_MUTEX(lock);
int status;
struct spi_message message;
struct spi_transfer x[2];
u8 *local_buf;
/* Use preallocated DMA-safe buffer. We can't avoid copying here,
* (as a pure convenience thing), but we can keep heap costs
* out of the hot path ...
*/
if ((n_tx + n_rx) > SPI_BUFSIZ)
return -EINVAL;
spi_message_init(&message);
memset(x, 0, sizeof x);
if (n_tx) {
x[0].len = n_tx;
spi_message_add_tail(&x[0], &message);
}
if (n_rx) {
x[1].len = n_rx;
spi_message_add_tail(&x[1], &message);
}
/* ... unless someone else is using the pre-allocated buffer */
if (!mutex_trylock(&lock)) {
local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!local_buf)
return -ENOMEM;
} else
local_buf = buf;
memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
/* do the i/o */
status = spi_sync(spi, &message);
if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
if (x[0].tx_buf == buf)
mutex_unlock(&lock);
else
kfree(local_buf);
return status;
}
EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
static int __init spi_init(void)
{
int status;
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
return 0;
err2:
bus_unregister(&spi_bus_type);
err1:
kfree(buf);
buf = NULL;
err0:
return status;
}
/* board_info is normally registered in arch_initcall(),
* but even essential drivers wait till later
*
* REVISIT only boardinfo really needs static linking. the rest (device and
* driver registration) _could_ be dynamically linked (modular) ... costs
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall(spi_init);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,512 @@
/*
* spi_bitbang.c - polling/bitbanging SPI master controller driver utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
/*----------------------------------------------------------------------*/
/*
* FIRST PART (OPTIONAL): word-at-a-time spi_transfer support.
* Use this for GPIO or shift-register level hardware APIs.
*
* spi_bitbang_cs is in spi_device->controller_state, which is unavailable
* to glue code. These bitbang setup() and cleanup() routines are always
* used, though maybe they're called from controller-aware code.
*
* chipselect() and friends may use use spi_device->controller_data and
* controller registers as appropriate.
*
*
* NOTE: SPI controller pins can often be used as GPIO pins instead,
* which means you could use a bitbang driver either to get hardware
* working quickly, or testing for differences that aren't speed related.
*/
struct spi_bitbang_cs {
unsigned nsecs; /* (clock cycle time)/2 */
u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs,
u32 word, u8 bits);
unsigned (*txrx_bufs)(struct spi_device *,
u32 (*txrx_word)(
struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits),
unsigned, struct spi_transfer *);
};
static unsigned bitbang_txrx_8(
struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits),
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
while (likely(count > 0)) {
u8 word = 0;
if (tx)
word = *tx++;
word = txrx_word(spi, ns, word, bits);
if (rx)
*rx++ = word;
count -= 1;
}
return t->len - count;
}
static unsigned bitbang_txrx_16(
struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits),
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned count = t->len;
const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf;
while (likely(count > 1)) {
u16 word = 0;
if (tx)
word = *tx++;
word = txrx_word(spi, ns, word, bits);
if (rx)
*rx++ = word;
count -= 2;
}
return t->len - count;
}
static unsigned bitbang_txrx_32(
struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits),
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned count = t->len;
const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf;
while (likely(count > 3)) {
u32 word = 0;
if (tx)
word = *tx++;
word = txrx_word(spi, ns, word, bits);
if (rx)
*rx++ = word;
count -= 4;
}
return t->len - count;
}
int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct spi_bitbang_cs *cs = spi->controller_state;
u8 bits_per_word;
u32 hz;
if (t) {
bits_per_word = t->bits_per_word;
hz = t->speed_hz;
} else {
bits_per_word = 0;
hz = 0;
}
/* spi_transfer level calls that work per-word */
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
if (bits_per_word <= 8)
cs->txrx_bufs = bitbang_txrx_8;
else if (bits_per_word <= 16)
cs->txrx_bufs = bitbang_txrx_16;
else if (bits_per_word <= 32)
cs->txrx_bufs = bitbang_txrx_32;
else
return -EINVAL;
/* nsecs = (clock period)/2 */
if (!hz)
hz = spi->max_speed_hz;
if (hz) {
cs->nsecs = (1000000000/2) / hz;
if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer);
/**
* spi_bitbang_setup - default setup for per-word I/O loops
*/
int spi_bitbang_setup(struct spi_device *spi)
{
struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang;
int retval;
unsigned long flags;
bitbang = spi_master_get_devdata(spi->master);
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
/* per-word shift register access, in hardware or bitbanging */
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
if (!cs->txrx_word)
return -EINVAL;
retval = bitbang->setup_transfer(spi, NULL);
if (retval < 0)
return retval;
dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion
* between normal (active low) and inverted chipselects.
*/
/* deselect chip (low or high) */
spin_lock_irqsave(&bitbang->lock, flags);
if (!bitbang->busy) {
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(cs->nsecs);
}
spin_unlock_irqrestore(&bitbang->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_setup);
/**
* spi_bitbang_cleanup - default cleanup for per-word I/O loops
*/
void spi_bitbang_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct spi_bitbang_cs *cs = spi->controller_state;
unsigned nsecs = cs->nsecs;
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
}
/*----------------------------------------------------------------------*/
/*
* SECOND PART ... simple transfer queue runner.
*
* This costs a task context per controller, running the queue by
* performing each transfer in sequence. Smarter hardware can queue
* several DMA transfers at once, and process several controller queues
* in parallel; this driver doesn't match such hardware very well.
*
* Drivers can provide word-at-a-time i/o primitives, or provide
* transfer-at-a-time ones to leverage dma or fifo hardware.
*/
static void bitbang_work(struct work_struct *work)
{
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work);
unsigned long flags;
int do_setup = -1;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
while (!list_empty(&bitbang->queue)) {
struct spi_message *m;
struct spi_device *spi;
unsigned nsecs;
struct spi_transfer *t = NULL;
unsigned tmp;
unsigned cs_change;
int status;
m = container_of(bitbang->queue.next, struct spi_message,
queue);
list_del_init(&m->queue);
spin_unlock_irqrestore(&bitbang->lock, flags);
/* FIXME this is made-up ... the correct value is known to
* word-at-a-time bitbang code, and presumably chipselect()
* should enforce these requirements too?
*/
nsecs = 100;
spi = m->spi;
tmp = 0;
cs_change = 1;
status = 0;
list_for_each_entry (t, &m->transfers, transfer_list) {
/* override speed or wordsize? */
if (t->speed_hz || t->bits_per_word)
do_setup = 1;
/* init (-1) or override (1) transfer params */
if (do_setup != 0) {
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
status = setup_transfer(spi, t);
if (status < 0)
break;
}
/* set up default clock polarity, and activate chip;
* this implicitly updates clock and spi modes as
* previously recorded for this device via setup().
* (and also deselects any other chip that might be
* selected ...)
*/
if (cs_change) {
bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
ndelay(nsecs);
}
cs_change = t->cs_change;
if (!t->tx_buf && !t->rx_buf && t->len) {
status = -EINVAL;
break;
}
/* transfer data. the lower level code handles any
* new dma mappings it needs. our caller always gave
* us dma-safe buffers.
*/
if (t->len) {
/* REVISIT dma API still needs a designated
* DMA_ADDR_INVALID; ~0 might be better.
*/
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0;
status = bitbang->txrx_bufs(spi, t);
}
if (status > 0)
m->actual_length += status;
if (status != t->len) {
/* always report some kind of error */
if (status >= 0)
status = -EREMOTEIO;
break;
}
status = 0;
/* protocol tweaks before next transfer */
if (t->delay_usecs)
udelay(t->delay_usecs);
if (!cs_change)
continue;
if (t->transfer_list.next == &m->transfers)
break;
/* sometimes a short mid-message deselect of the chip
* may be needed to terminate a mode or command
*/
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
m->status = status;
m->complete(m->context);
/* restore speed and wordsize if it was overridden */
if (do_setup == 1)
setup_transfer(spi, NULL);
do_setup = 0;
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
* be for this chip too.
*/
if (!(status == 0 && cs_change)) {
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
spin_lock_irqsave(&bitbang->lock, flags);
}
bitbang->busy = 0;
spin_unlock_irqrestore(&bitbang->lock, flags);
}
/**
* spi_bitbang_transfer - default submit to transfer queue
*/
int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
{
struct spi_bitbang *bitbang;
unsigned long flags;
int status = 0;
m->actual_length = 0;
m->status = -EINPROGRESS;
bitbang = spi_master_get_devdata(spi->master);
spin_lock_irqsave(&bitbang->lock, flags);
if (!spi->max_speed_hz)
status = -ENETDOWN;
else {
list_add_tail(&m->queue, &bitbang->queue);
queue_work(bitbang->workqueue, &bitbang->work);
}
spin_unlock_irqrestore(&bitbang->lock, flags);
return status;
}
EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
/*----------------------------------------------------------------------*/
/**
* spi_bitbang_start - start up a polled/bitbanging SPI master driver
* @bitbang: driver handle
*
* Caller should have zero-initialized all parts of the structure, and then
* provided callbacks for chip selection and I/O loops. If the master has
* a transfer method, its final step should call spi_bitbang_transfer; or,
* that's the default if the transfer routine is not initialized. It should
* also set up the bus number and number of chipselects.
*
* For i/o loops, provide callbacks either per-word (for bitbanging, or for
* hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines).
*
* Drivers using per-word I/O loops should use (or call) spi_bitbang_setup,
* spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
* master methods. Those methods are the defaults if the bitbang->txrx_bufs
* routine isn't initialized.
*
* This routine registers the spi_master, which will process requests in a
* dedicated task, keeping IRQs unblocked most of the time. To stop
* processing those requests, call spi_bitbang_stop().
*/
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
int status;
if (!bitbang->master || !bitbang->chipselect)
return -EINVAL;
INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue);
if (!bitbang->master->mode_bits)
bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
if (!bitbang->master->transfer)
bitbang->master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup;
}
} else if (!bitbang->master->setup)
return -EINVAL;
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
bitbang->workqueue = create_singlethread_workqueue(
dev_name(bitbang->master->dev.parent));
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
}
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
status = spi_register_master(bitbang->master);
if (status < 0)
goto err2;
return status;
err2:
destroy_workqueue(bitbang->workqueue);
err1:
return status;
}
EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
int spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
WARN_ON(!list_empty(&bitbang->queue));
destroy_workqueue(bitbang->workqueue);
return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,357 @@
/*
* spi_butterfly.c - parport-to-butterfly adapter
*
* Copyright (C) 2005 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/flash.h>
#include <linux/mtd/partitions.h>
/*
* This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
* with a battery powered AVR microcontroller and lots of goodies. You
* can use GCC to develop firmware for this.
*
* See Documentation/spi/butterfly for information about how to build
* and use this custom parallel port cable.
*/
/* DATA output bits (pins 2..9 == D0..D7) */
#define butterfly_nreset (1 << 1) /* pin 3 */
#define spi_sck_bit (1 << 0) /* pin 2 */
#define spi_mosi_bit (1 << 7) /* pin 9 */
#define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */
/* STATUS input bits */
#define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */
/* CONTROL output bits */
#define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */
static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
{
return spi->controller_data;
}
struct butterfly {
/* REVISIT ... for now, this must be first */
struct spi_bitbang bitbang;
struct parport *port;
struct pardevice *pd;
u8 lastbyte;
struct spi_device *dataflash;
struct spi_device *butterfly;
struct spi_board_info info[2];
};
/*----------------------------------------------------------------------*/
static inline void
setsck(struct spi_device *spi, int is_on)
{
struct butterfly *pp = spidev_to_pp(spi);
u8 bit, byte = pp->lastbyte;
bit = spi_sck_bit;
if (is_on)
byte |= bit;
else
byte &= ~bit;
parport_write_data(pp->port, byte);
pp->lastbyte = byte;
}
static inline void
setmosi(struct spi_device *spi, int is_on)
{
struct butterfly *pp = spidev_to_pp(spi);
u8 bit, byte = pp->lastbyte;
bit = spi_mosi_bit;
if (is_on)
byte |= bit;
else
byte &= ~bit;
parport_write_data(pp->port, byte);
pp->lastbyte = byte;
}
static inline int getmiso(struct spi_device *spi)
{
struct butterfly *pp = spidev_to_pp(spi);
int value;
u8 bit;
bit = spi_miso_bit;
/* only STATUS_BUSY is NOT negated */
value = !(parport_read_status(pp->port) & bit);
return (bit == PARPORT_STATUS_BUSY) ? value : !value;
}
static void butterfly_chipselect(struct spi_device *spi, int value)
{
struct butterfly *pp = spidev_to_pp(spi);
/* set default clock polarity */
if (value != BITBANG_CS_INACTIVE)
setsck(spi, spi->mode & SPI_CPOL);
/* here, value == "activate or not";
* most PARPORT_CONTROL_* bits are negated, so we must
* morph it to value == "bit value to write in control register"
*/
if (spi_cs_bit == PARPORT_CONTROL_INIT)
value = !value;
parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
}
/* we only needed to implement one mode here, and choose SPI_MODE_0 */
#define spidelay(X) do{}while(0)
//#define spidelay ndelay
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
static u32
butterfly_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
/*----------------------------------------------------------------------*/
/* override default partitioning with cmdlinepart */
static struct mtd_partition partitions[] = { {
/* JFFS2 wants partitions of 4*N blocks for this device,
* so sectors 0 and 1 can't be partitions by themselves.
*/
/* sector 0 = 8 pages * 264 bytes/page (1 block)
* sector 1 = 248 pages * 264 bytes/page
*/
.name = "bookkeeping", // 66 KB
.offset = 0,
.size = (8 + 248) * 264,
// .mask_flags = MTD_WRITEABLE,
}, {
/* sector 2 = 256 pages * 264 bytes/page
* sectors 3-5 = 512 pages * 264 bytes/page
*/
.name = "filesystem", // 462 KB
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
} };
static struct flash_platform_data flash = {
.name = "butterflash",
.parts = partitions,
.nr_parts = ARRAY_SIZE(partitions),
};
/* REVISIT remove this ugly global and its "only one" limitation */
static struct butterfly *butterfly;
static void butterfly_attach(struct parport *p)
{
struct pardevice *pd;
int status;
struct butterfly *pp;
struct spi_master *master;
struct device *dev = p->physport->dev;
if (butterfly || !dev)
return;
/* REVISIT: this just _assumes_ a butterfly is there ... no probe,
* and no way to be selective about what it binds to.
*/
master = spi_alloc_master(dev, sizeof *pp);
if (!master) {
status = -ENOMEM;
goto done;
}
pp = spi_master_get_devdata(master);
/*
* SPI and bitbang hookup
*
* use default setup(), cleanup(), and transfer() methods; and
* only bother implementing mode 0. Start it later.
*/
master->bus_num = 42;
master->num_chipselect = 2;
pp->bitbang.master = spi_master_get(master);
pp->bitbang.chipselect = butterfly_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
/*
* parport hookup
*/
pp->port = p;
pd = parport_register_device(p, "spi_butterfly",
NULL, NULL, NULL,
0 /* FLAGS */, pp);
if (!pd) {
status = -ENOMEM;
goto clean0;
}
pp->pd = pd;
status = parport_claim(pd);
if (status < 0)
goto clean1;
/*
* Butterfly reset, powerup, run firmware
*/
pr_debug("%s: powerup/reset Butterfly\n", p->name);
/* nCS for dataflash (this bit is inverted on output) */
parport_frob_control(pp->port, spi_cs_bit, 0);
/* stabilize power with chip in reset (nRESET), and
* spi_sck_bit clear (CPOL=0)
*/
pp->lastbyte |= vcc_bits;
parport_write_data(pp->port, pp->lastbyte);
msleep(5);
/* take it out of reset; assume long reset delay */
pp->lastbyte |= butterfly_nreset;
parport_write_data(pp->port, pp->lastbyte);
msleep(100);
/*
* Start SPI ... for now, hide that we're two physical busses.
*/
status = spi_bitbang_start(&pp->bitbang);
if (status < 0)
goto clean2;
/* Bus 1 lets us talk to at45db041b (firmware disables AVR SPI), AVR
* (firmware resets at45, acts as spi slave) or neither (we ignore
* both, AVR uses AT45). Here we expect firmware for the first option.
*/
pp->info[0].max_speed_hz = 15 * 1000 * 1000;
strcpy(pp->info[0].modalias, "mtd_dataflash");
pp->info[0].platform_data = &flash;
pp->info[0].chip_select = 1;
pp->info[0].controller_data = pp;
pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
if (pp->dataflash)
pr_debug("%s: dataflash at %s\n", p->name,
dev_name(&pp->dataflash->dev));
// dev_info(_what?_, ...)
pr_info("%s: AVR Butterfly\n", p->name);
butterfly = pp;
return;
clean2:
/* turn off VCC */
parport_write_data(pp->port, 0);
parport_release(pp->pd);
clean1:
parport_unregister_device(pd);
clean0:
(void) spi_master_put(pp->bitbang.master);
done:
pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
}
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
int status;
/* FIXME this global is ugly ... but, how to quickly get from
* the parport to the "struct butterfly" associated with it?
* "old school" driver-internal device lists?
*/
if (!butterfly || butterfly->port != p)
return;
pp = butterfly;
butterfly = NULL;
/* stop() unregisters child devices too */
status = spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
parport_write_data(pp->port, 0);
msleep(10);
parport_release(pp->pd);
parport_unregister_device(pp->pd);
(void) spi_master_put(pp->bitbang.master);
}
static struct parport_driver butterfly_driver = {
.name = "spi_butterfly",
.attach = butterfly_attach,
.detach = butterfly_detach,
};
static int __init butterfly_init(void)
{
return parport_register_driver(&butterfly_driver);
}
device_initcall(butterfly_init);
static void __exit butterfly_exit(void)
{
parport_unregister_driver(&butterfly_driver);
}
module_exit(butterfly_exit);
MODULE_DESCRIPTION("Parport Adapter driver for AVR Butterfly");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,365 @@
/*
* spi_gpio.c - SPI master driver using generic bitbanged GPIO
*
* Copyright (C) 2006,2008 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/spi_gpio.h>
/*
* This bitbanging SPI master driver should help make systems usable
* when a native hardware SPI engine is not available, perhaps because
* its driver isn't yet working or because the I/O pins it requires
* are used for other purposes.
*
* platform_device->driver_data ... points to spi_gpio
*
* spi->controller_state ... reserved for bitbang framework code
* spi->controller_data ... holds chipselect GPIO
*
* spi->master->dev.driver_data ... points to spi_gpio->bitbang
*/
struct spi_gpio {
struct spi_bitbang bitbang;
struct spi_gpio_platform_data pdata;
struct platform_device *pdev;
};
/*----------------------------------------------------------------------*/
/*
* Because the overhead of going through four GPIO procedure calls
* per transferred bit can make performance a problem, this code
* is set up so that you can use it in either of two ways:
*
* - The slow generic way: set up platform_data to hold the GPIO
* numbers used for MISO/MOSI/SCK, and issue procedure calls for
* each of them. This driver can handle several such busses.
*
* - The quicker inlined way: only helps with platform GPIO code
* that inlines operations for constant GPIOs. This can give
* you tight (fast!) inner loops, but each such bus needs a
* new driver. You'll define a new C file, with Makefile and
* Kconfig support; the C code can be a total of six lines:
*
* #define DRIVER_NAME "myboard_spi2"
* #define SPI_MISO_GPIO 119
* #define SPI_MOSI_GPIO 120
* #define SPI_SCK_GPIO 121
* #define SPI_N_CHIPSEL 4
* #include "spi_gpio.c"
*/
#ifndef DRIVER_NAME
#define DRIVER_NAME "spi_gpio"
#define GENERIC_BITBANG /* vs tight inlines */
/* all functions referencing these symbols must define pdata */
#define SPI_MISO_GPIO ((pdata)->miso)
#define SPI_MOSI_GPIO ((pdata)->mosi)
#define SPI_SCK_GPIO ((pdata)->sck)
#define SPI_N_CHIPSEL ((pdata)->num_chipselect)
#endif
/*----------------------------------------------------------------------*/
static inline const struct spi_gpio_platform_data * __pure
spi_to_pdata(const struct spi_device *spi)
{
const struct spi_bitbang *bang;
const struct spi_gpio *spi_gpio;
bang = spi_master_get_devdata(spi->master);
spi_gpio = container_of(bang, struct spi_gpio, bitbang);
return &spi_gpio->pdata;
}
/* this is #defined to avoid unused-variable warnings when inlining */
#define pdata spi_to_pdata(spi)
static inline void setsck(const struct spi_device *spi, int is_on)
{
gpio_set_value(SPI_SCK_GPIO, is_on);
}
static inline void setmosi(const struct spi_device *spi, int is_on)
{
gpio_set_value(SPI_MOSI_GPIO, is_on);
}
static inline int getmiso(const struct spi_device *spi)
{
return !!gpio_get_value(SPI_MISO_GPIO);
}
#undef pdata
/*
* NOTE: this clocks "as fast as we can". It "should" be a function of the
* requested device clock. Software overhead means we usually have trouble
* reaching even one Mbit/sec (except when we can inline bitops), so for now
* we'll just assume we never need additional per-bit slowdowns.
*/
#define spidelay(nsecs) do {} while (0)
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
/*
* These functions can leverage inline expansion of GPIO calls to shrink
* costs for a txrx bit, often by factors of around ten (by instruction
* count). That is particularly visible for larger word sizes, but helps
* even with default 8-bit words.
*
* REVISIT overheads calling these functions for each word also have
* significant performance costs. Having txrx_bufs() calls that inline
* the txrx_word() logic would help performance, e.g. on larger blocks
* used with flash storage or MMC/SD. There should also be ways to make
* GCC be less stupid about reloading registers inside the I/O loops,
* even without inlined GPIO calls; __attribute__((hot)) on GCC 4.3?
*/
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
}
static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
}
/*----------------------------------------------------------------------*/
static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
{
unsigned long cs = (unsigned long) spi->controller_data;
/* set initial clock polarity */
if (is_active)
setsck(spi, spi->mode & SPI_CPOL);
if (cs != SPI_GPIO_NO_CHIPSELECT) {
/* SPI is normally active-low */
gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
}
}
static int spi_gpio_setup(struct spi_device *spi)
{
unsigned long cs = (unsigned long) spi->controller_data;
int status = 0;
if (spi->bits_per_word > 32)
return -EINVAL;
if (!spi->controller_state) {
if (cs != SPI_GPIO_NO_CHIPSELECT) {
status = gpio_request(cs, dev_name(&spi->dev));
if (status)
return status;
status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
}
}
if (!status)
status = spi_bitbang_setup(spi);
if (status) {
if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
}
return status;
}
static void spi_gpio_cleanup(struct spi_device *spi)
{
unsigned long cs = (unsigned long) spi->controller_data;
if (cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
spi_bitbang_cleanup(spi);
}
static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
{
int value;
value = gpio_request(pin, label);
if (value == 0) {
if (is_in)
value = gpio_direction_input(pin);
else
value = gpio_direction_output(pin, 0);
}
return value;
}
static int __init
spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label)
{
int value;
/* NOTE: SPI_*_GPIO symbols may reference "pdata" */
value = spi_gpio_alloc(SPI_MOSI_GPIO, label, false);
if (value)
goto done;
value = spi_gpio_alloc(SPI_MISO_GPIO, label, true);
if (value)
goto free_mosi;
value = spi_gpio_alloc(SPI_SCK_GPIO, label, false);
if (value)
goto free_miso;
goto done;
free_miso:
gpio_free(SPI_MISO_GPIO);
free_mosi:
gpio_free(SPI_MOSI_GPIO);
done:
return value;
}
static int __init spi_gpio_probe(struct platform_device *pdev)
{
int status;
struct spi_master *master;
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
pdata = pdev->dev.platform_data;
#ifdef GENERIC_BITBANG
if (!pdata || !pdata->num_chipselect)
return -ENODEV;
#endif
status = spi_gpio_request(pdata, dev_name(&pdev->dev));
if (status < 0)
return status;
master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);
if (!master) {
status = -ENOMEM;
goto gpio_free;
}
spi_gpio = spi_master_get_devdata(master);
platform_set_drvdata(pdev, spi_gpio);
spi_gpio->pdev = pdev;
if (pdata)
spi_gpio->pdata = *pdata;
master->bus_num = pdev->id;
master->num_chipselect = SPI_N_CHIPSEL;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
spi_gpio->bitbang.master = spi_master_get(master);
spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
spi_gpio->bitbang.flags = SPI_CS_HIGH;
status = spi_bitbang_start(&spi_gpio->bitbang);
if (status < 0) {
spi_master_put(spi_gpio->bitbang.master);
gpio_free:
gpio_free(SPI_MISO_GPIO);
gpio_free(SPI_MOSI_GPIO);
gpio_free(SPI_SCK_GPIO);
spi_master_put(master);
}
return status;
}
static int __exit spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
int status;
spi_gpio = platform_get_drvdata(pdev);
pdata = pdev->dev.platform_data;
/* stop() unregisters child devices too */
status = spi_bitbang_stop(&spi_gpio->bitbang);
spi_master_put(spi_gpio->bitbang.master);
platform_set_drvdata(pdev, NULL);
gpio_free(SPI_MISO_GPIO);
gpio_free(SPI_MOSI_GPIO);
gpio_free(SPI_SCK_GPIO);
return status;
}
MODULE_ALIAS("platform:" DRIVER_NAME);
static struct platform_driver spi_gpio_driver = {
.driver.name = DRIVER_NAME,
.driver.owner = THIS_MODULE,
.remove = __exit_p(spi_gpio_remove),
};
static int __init spi_gpio_init(void)
{
return platform_driver_probe(&spi_gpio_driver, spi_gpio_probe);
}
module_init(spi_gpio_init);
static void __exit spi_gpio_exit(void)
{
platform_driver_unregister(&spi_gpio_driver);
}
module_exit(spi_gpio_exit);
MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO ");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,680 @@
/*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2008 Juergen Beisert
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*/
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>
#include <mach/spi.h>
#define DRIVER_NAME "spi_imx"
#define MXC_CSPIRXDATA 0x00
#define MXC_CSPITXDATA 0x04
#define MXC_CSPICTRL 0x08
#define MXC_CSPIINT 0x0c
#define MXC_RESET 0x1c
/* generic defines to abstract from the different register layouts */
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
struct spi_imx_config {
unsigned int speed_hz;
unsigned int bpw;
unsigned int mode;
int cs;
};
struct spi_imx_data {
struct spi_bitbang bitbang;
struct completion xfer_done;
void *base;
int irq;
struct clk *clk;
unsigned long spi_clk;
int *chipselect;
unsigned int count;
void (*tx)(struct spi_imx_data *);
void (*rx)(struct spi_imx_data *);
void *rx_buf;
const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
/* SoC specific functions */
void (*intctrl)(struct spi_imx_data *, int);
int (*config)(struct spi_imx_data *, struct spi_imx_config *);
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
};
#define MXC_SPI_BUF_RX(type) \
static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
{ \
unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); \
\
if (spi_imx->rx_buf) { \
*(type *)spi_imx->rx_buf = val; \
spi_imx->rx_buf += sizeof(type); \
} \
}
#define MXC_SPI_BUF_TX(type) \
static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \
{ \
type val = 0; \
\
if (spi_imx->tx_buf) { \
val = *(type *)spi_imx->tx_buf; \
spi_imx->tx_buf += sizeof(type); \
} \
\
spi_imx->count -= sizeof(type); \
\
writel(val, spi_imx->base + MXC_CSPITXDATA); \
}
MXC_SPI_BUF_RX(u8)
MXC_SPI_BUF_TX(u8)
MXC_SPI_BUF_RX(u16)
MXC_SPI_BUF_TX(u16)
MXC_SPI_BUF_RX(u32)
MXC_SPI_BUF_TX(u32)
/* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
* (which is currently not the case in this driver)
*/
static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
256, 384, 512, 768, 1024};
/* MX21, MX27 */
static unsigned int spi_imx_clkdiv_1(unsigned int fin,
unsigned int fspi)
{
int i, max;
if (cpu_is_mx21())
max = 18;
else
max = 16;
for (i = 2; i < max; i++)
if (fspi * mxc_clkdivs[i] >= fin)
return i;
return max;
}
/* MX1, MX31, MX35 */
static unsigned int spi_imx_clkdiv_2(unsigned int fin,
unsigned int fspi)
{
int i, div = 4;
for (i = 0; i < 7; i++) {
if (fspi * div >= fin)
return i;
div <<= 1;
}
return 7;
}
#define MX31_INTREG_TEEN (1 << 0)
#define MX31_INTREG_RREN (1 << 3)
#define MX31_CSPICTRL_ENABLE (1 << 0)
#define MX31_CSPICTRL_MASTER (1 << 1)
#define MX31_CSPICTRL_XCH (1 << 2)
#define MX31_CSPICTRL_POL (1 << 4)
#define MX31_CSPICTRL_PHA (1 << 5)
#define MX31_CSPICTRL_SSCTL (1 << 6)
#define MX31_CSPICTRL_SSPOL (1 << 7)
#define MX31_CSPICTRL_BC_SHIFT 8
#define MX35_CSPICTRL_BL_SHIFT 20
#define MX31_CSPICTRL_CS_SHIFT 24
#define MX35_CSPICTRL_CS_SHIFT 12
#define MX31_CSPICTRL_DR_SHIFT 16
#define MX31_CSPISTATUS 0x14
#define MX31_STATUS_RR (1 << 3)
/* These functions also work for the i.MX35, but be aware that
* the i.MX35 has a slightly different register layout for bits
* we do not use here.
*/
static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
if (enable & MXC_INT_TE)
val |= MX31_INTREG_TEEN;
if (enable & MXC_INT_RR)
val |= MX31_INTREG_RREN;
writel(val, spi_imx->base + MXC_CSPIINT);
}
static void mx31_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
reg = readl(spi_imx->base + MXC_CSPICTRL);
reg |= MX31_CSPICTRL_XCH;
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
static int mx31_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX31_CSPICTRL_DR_SHIFT;
if (cpu_is_mx31())
reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
else if (cpu_is_mx35()) {
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
reg |= MX31_CSPICTRL_SSCTL;
}
if (config->mode & SPI_CPHA)
reg |= MX31_CSPICTRL_PHA;
if (config->mode & SPI_CPOL)
reg |= MX31_CSPICTRL_POL;
if (config->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
if (config->cs < 0) {
if (cpu_is_mx31())
reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT;
else if (cpu_is_mx35())
reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT;
}
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
static int mx31_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
}
#define MX27_INTREG_RR (1 << 4)
#define MX27_INTREG_TEEN (1 << 9)
#define MX27_INTREG_RREN (1 << 13)
#define MX27_CSPICTRL_POL (1 << 5)
#define MX27_CSPICTRL_PHA (1 << 6)
#define MX27_CSPICTRL_SSPOL (1 << 8)
#define MX27_CSPICTRL_XCH (1 << 9)
#define MX27_CSPICTRL_ENABLE (1 << 10)
#define MX27_CSPICTRL_MASTER (1 << 11)
#define MX27_CSPICTRL_DR_SHIFT 14
#define MX27_CSPICTRL_CS_SHIFT 19
static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
if (enable & MXC_INT_TE)
val |= MX27_INTREG_TEEN;
if (enable & MXC_INT_RR)
val |= MX27_INTREG_RREN;
writel(val, spi_imx->base + MXC_CSPIINT);
}
static void mx27_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
reg = readl(spi_imx->base + MXC_CSPICTRL);
reg |= MX27_CSPICTRL_XCH;
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
static int mx27_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER;
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) <<
MX27_CSPICTRL_DR_SHIFT;
reg |= config->bpw - 1;
if (config->mode & SPI_CPHA)
reg |= MX27_CSPICTRL_PHA;
if (config->mode & SPI_CPOL)
reg |= MX27_CSPICTRL_POL;
if (config->mode & SPI_CS_HIGH)
reg |= MX27_CSPICTRL_SSPOL;
if (config->cs < 0)
reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
static int mx27_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR;
}
#define MX1_INTREG_RR (1 << 3)
#define MX1_INTREG_TEEN (1 << 8)
#define MX1_INTREG_RREN (1 << 11)
#define MX1_CSPICTRL_POL (1 << 4)
#define MX1_CSPICTRL_PHA (1 << 5)
#define MX1_CSPICTRL_XCH (1 << 8)
#define MX1_CSPICTRL_ENABLE (1 << 9)
#define MX1_CSPICTRL_MASTER (1 << 10)
#define MX1_CSPICTRL_DR_SHIFT 13
static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
if (enable & MXC_INT_TE)
val |= MX1_INTREG_TEEN;
if (enable & MXC_INT_RR)
val |= MX1_INTREG_RREN;
writel(val, spi_imx->base + MXC_CSPIINT);
}
static void mx1_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
reg = readl(spi_imx->base + MXC_CSPICTRL);
reg |= MX1_CSPICTRL_XCH;
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
static int mx1_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX1_CSPICTRL_DR_SHIFT;
reg |= config->bpw - 1;
if (config->mode & SPI_CPHA)
reg |= MX1_CSPICTRL_PHA;
if (config->mode & SPI_CPOL)
reg |= MX1_CSPICTRL_POL;
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
static int mx1_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
}
static void spi_imx_chipselect(struct spi_device *spi, int is_active)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int gpio = spi_imx->chipselect[spi->chip_select];
int active = is_active != BITBANG_CS_INACTIVE;
int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
if (gpio < 0)
return;
gpio_set_value(gpio, dev_is_lowactive ^ active);
}
static void spi_imx_push(struct spi_imx_data *spi_imx)
{
while (spi_imx->txfifo < 8) {
if (!spi_imx->count)
break;
spi_imx->tx(spi_imx);
spi_imx->txfifo++;
}
spi_imx->trigger(spi_imx);
}
static irqreturn_t spi_imx_isr(int irq, void *dev_id)
{
struct spi_imx_data *spi_imx = dev_id;
while (spi_imx->rx_available(spi_imx)) {
spi_imx->rx(spi_imx);
spi_imx->txfifo--;
}
if (spi_imx->count) {
spi_imx_push(spi_imx);
return IRQ_HANDLED;
}
if (spi_imx->txfifo) {
/* No data left to push, but still waiting for rx data,
* enable receive data available interrupt.
*/
spi_imx->intctrl(spi_imx, MXC_INT_RR);
return IRQ_HANDLED;
}
spi_imx->intctrl(spi_imx, 0);
complete(&spi_imx->xfer_done);
return IRQ_HANDLED;
}
static int spi_imx_setupxfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
struct spi_imx_config config;
config.bpw = t ? t->bits_per_word : spi->bits_per_word;
config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
config.mode = spi->mode;
config.cs = spi_imx->chipselect[spi->chip_select];
if (!config.speed_hz)
config.speed_hz = spi->max_speed_hz;
if (!config.bpw)
config.bpw = spi->bits_per_word;
if (!config.speed_hz)
config.speed_hz = spi->max_speed_hz;
/* Initialize the functions for transfer */
if (config.bpw <= 8) {
spi_imx->rx = spi_imx_buf_rx_u8;
spi_imx->tx = spi_imx_buf_tx_u8;
} else if (config.bpw <= 16) {
spi_imx->rx = spi_imx_buf_rx_u16;
spi_imx->tx = spi_imx_buf_tx_u16;
} else if (config.bpw <= 32) {
spi_imx->rx = spi_imx_buf_rx_u32;
spi_imx->tx = spi_imx_buf_tx_u32;
} else
BUG();
spi_imx->config(spi_imx, &config);
return 0;
}
static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
init_completion(&spi_imx->xfer_done);
spi_imx_push(spi_imx);
spi_imx->intctrl(spi_imx, MXC_INT_TE);
wait_for_completion(&spi_imx->xfer_done);
return transfer->len;
}
static int spi_imx_setup(struct spi_device *spi)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int gpio = spi_imx->chipselect[spi->chip_select];
pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz);
if (gpio >= 0)
gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
spi_imx_chipselect(spi, BITBANG_CS_INACTIVE);
return 0;
}
static void spi_imx_cleanup(struct spi_device *spi)
{
}
static int __init spi_imx_probe(struct platform_device *pdev)
{
struct spi_imx_master *mxc_platform_info;
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret;
mxc_platform_info = (struct spi_imx_master *)pdev->dev.platform_data;
if (!mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master);
master->bus_num = pdev->id;
master->num_chipselect = mxc_platform_info->num_chipselect;
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = spi_master_get(master);
spi_imx->chipselect = mxc_platform_info->chipselect;
for (i = 0; i < master->num_chipselect; i++) {
if (spi_imx->chipselect[i] < 0)
continue;
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
if (ret) {
i--;
while (i > 0)
if (spi_imx->chipselect[i] >= 0)
gpio_free(spi_imx->chipselect[i--]);
dev_err(&pdev->dev, "can't get cs gpios");
goto out_master_put;
}
}
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
spi_imx->bitbang.master->setup = spi_imx_setup;
spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
init_completion(&spi_imx->xfer_done);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "can't get platform resource\n");
ret = -ENOMEM;
goto out_gpio_free;
}
if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "request_mem_region failed\n");
ret = -EBUSY;
goto out_gpio_free;
}
spi_imx->base = ioremap(res->start, resource_size(res));
if (!spi_imx->base) {
ret = -EINVAL;
goto out_release_mem;
}
spi_imx->irq = platform_get_irq(pdev, 0);
if (!spi_imx->irq) {
ret = -EINVAL;
goto out_iounmap;
}
ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
goto out_iounmap;
}
if (cpu_is_mx31() || cpu_is_mx35()) {
spi_imx->intctrl = mx31_intctrl;
spi_imx->config = mx31_config;
spi_imx->trigger = mx31_trigger;
spi_imx->rx_available = mx31_rx_available;
} else if (cpu_is_mx27() || cpu_is_mx21()) {
spi_imx->intctrl = mx27_intctrl;
spi_imx->config = mx27_config;
spi_imx->trigger = mx27_trigger;
spi_imx->rx_available = mx27_rx_available;
} else if (cpu_is_mx1()) {
spi_imx->intctrl = mx1_intctrl;
spi_imx->config = mx1_config;
spi_imx->trigger = mx1_trigger;
spi_imx->rx_available = mx1_rx_available;
} else
BUG();
spi_imx->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(spi_imx->clk)) {
dev_err(&pdev->dev, "unable to get clock\n");
ret = PTR_ERR(spi_imx->clk);
goto out_free_irq;
}
clk_enable(spi_imx->clk);
spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
if (!cpu_is_mx31() || !cpu_is_mx35())
writel(1, spi_imx->base + MXC_RESET);
spi_imx->intctrl(spi_imx, 0);
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
dev_info(&pdev->dev, "probed\n");
return ret;
out_clk_put:
clk_disable(spi_imx->clk);
clk_put(spi_imx->clk);
out_free_irq:
free_irq(spi_imx->irq, spi_imx);
out_iounmap:
iounmap(spi_imx->base);
out_release_mem:
release_mem_region(res->start, resource_size(res));
out_gpio_free:
for (i = 0; i < master->num_chipselect; i++)
if (spi_imx->chipselect[i] >= 0)
gpio_free(spi_imx->chipselect[i]);
out_master_put:
spi_master_put(master);
kfree(master);
platform_set_drvdata(pdev, NULL);
return ret;
}
static int __exit spi_imx_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
int i;
spi_bitbang_stop(&spi_imx->bitbang);
writel(0, spi_imx->base + MXC_CSPICTRL);
clk_disable(spi_imx->clk);
clk_put(spi_imx->clk);
free_irq(spi_imx->irq, spi_imx);
iounmap(spi_imx->base);
for (i = 0; i < master->num_chipselect; i++)
if (spi_imx->chipselect[i] >= 0)
gpio_free(spi_imx->chipselect[i]);
spi_master_put(master);
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.probe = spi_imx_probe,
.remove = __exit_p(spi_imx_remove),
};
static int __init spi_imx_init(void)
{
return platform_driver_register(&spi_imx_driver);
}
static void __exit spi_imx_exit(void)
{
platform_driver_unregister(&spi_imx_driver);
}
module_init(spi_imx_init);
module_exit(spi_imx_exit);
MODULE_DESCRIPTION("SPI Master Controller driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,352 @@
/*
* spi_lm70llp.c - driver for LM70EVAL-LLP board for the LM70 sensor
*
* Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/parport.h>
#include <linux/sysfs.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
/*
* The LM70 communicates with a host processor using a 3-wire variant of
* the SPI/Microwire bus interface. This driver specifically supports an
* NS LM70 LLP Evaluation Board, interfacing to a PC using its parallel
* port to bitbang an SPI-parport bridge. Accordingly, this is an SPI
* master controller driver. The hwmon/lm70 driver is a "SPI protocol
* driver", layered on top of this one and usable without the lm70llp.
*
* Datasheet and Schematic:
* The LM70 is a temperature sensor chip from National Semiconductor; its
* datasheet is available at http://www.national.com/pf/LM/LM70.html
* The schematic for this particular board (the LM70EVAL-LLP) is
* available (on page 4) here:
* http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
*
* Also see Documentation/spi/spi-lm70llp. The SPI<->parport code here is
* (heavily) based on spi-butterfly by David Brownell.
*
* The LM70 LLP connects to the PC parallel port in the following manner:
*
* Parallel LM70 LLP
* Port Direction JP2 Header
* ----------- --------- ------------
* D0 2 - -
* D1 3 --> V+ 5
* D2 4 --> V+ 5
* D3 5 --> V+ 5
* D4 6 --> V+ 5
* D5 7 --> nCS 8
* D6 8 --> SCLK 3
* D7 9 --> SI/O 5
* GND 25 - GND 7
* Select 13 <-- SI/O 1
*
* Note that parport pin 13 actually gets inverted by the transistor
* arrangement which lets either the parport or the LM70 drive the
* SI/SO signal (see the schematic for details).
*/
#define DRVNAME "spi-lm70llp"
#define lm70_INIT 0xBE
#define SIO 0x10
#define nCS 0x20
#define SCLK 0x40
/*-------------------------------------------------------------------------*/
struct spi_lm70llp {
struct spi_bitbang bitbang;
struct parport *port;
struct pardevice *pd;
struct spi_device *spidev_lm70;
struct spi_board_info info;
//struct device *dev;
};
/* REVISIT : ugly global ; provides "exclusive open" facility */
static struct spi_lm70llp *lm70llp;
/*-------------------------------------------------------------------*/
static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
{
return spi->controller_data;
}
/*---------------------- LM70 LLP eval board-specific inlines follow */
/* NOTE: we don't actually need to reread the output values, since they'll
* still be what we wrote before. Plus, going through parport builds in
* a ~1ms/operation delay; these SPI transfers could easily be faster.
*/
static inline void deassertCS(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
data &= ~0x80; /* pull D7/SI-out low while de-asserted */
parport_write_data(pp->port, data | nCS);
}
static inline void assertCS(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
data |= 0x80; /* pull D7/SI-out high so lm70 drives SO-in */
parport_write_data(pp->port, data & ~nCS);
}
static inline void clkHigh(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
parport_write_data(pp->port, data | SCLK);
}
static inline void clkLow(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
parport_write_data(pp->port, data & ~SCLK);
}
/*------------------------- SPI-LM70-specific inlines ----------------------*/
static inline void spidelay(unsigned d)
{
udelay(d);
}
static inline void setsck(struct spi_device *s, int is_on)
{
struct spi_lm70llp *pp = spidev_to_pp(s);
if (is_on)
clkHigh(pp);
else
clkLow(pp);
}
static inline void setmosi(struct spi_device *s, int is_on)
{
/* FIXME update D7 ... this way we can put the chip
* into shutdown mode and read the manufacturer ID,
* but we can't put it back into operational mode.
*/
}
/*
* getmiso:
* Why do we return 0 when the SIO line is high and vice-versa?
* The fact is, the lm70 eval board from NS (which this driver drives),
* is wired in just such a way : when the lm70's SIO goes high, a transistor
* switches it to low reflecting this on the parport (pin 13), and vice-versa.
*/
static inline int getmiso(struct spi_device *s)
{
struct spi_lm70llp *pp = spidev_to_pp(s);
return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1 );
}
/*--------------------------------------------------------------------*/
#define EXPAND_BITBANG_TXRX 1
#include <linux/spi/spi_bitbang.h>
static void lm70_chipselect(struct spi_device *spi, int value)
{
struct spi_lm70llp *pp = spidev_to_pp(spi);
if (value)
assertCS(pp);
else
deassertCS(pp);
}
/*
* Our actual bitbanger routine.
*/
static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static void spi_lm70llp_attach(struct parport *p)
{
struct pardevice *pd;
struct spi_lm70llp *pp;
struct spi_master *master;
int status;
if (lm70llp) {
printk(KERN_WARNING
"%s: spi_lm70llp instance already loaded. Aborting.\n",
DRVNAME);
return;
}
/* TODO: this just _assumes_ a lm70 is there ... no probe;
* the lm70 driver could verify it, reading the manf ID.
*/
master = spi_alloc_master(p->physport->dev, sizeof *pp);
if (!master) {
status = -ENOMEM;
goto out_fail;
}
pp = spi_master_get_devdata(master);
master->bus_num = -1; /* dynamic alloc of a bus number */
master->num_chipselect = 1;
/*
* SPI and bitbang hookup.
*/
pp->bitbang.master = spi_master_get(master);
pp->bitbang.chipselect = lm70_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
pp->bitbang.flags = SPI_3WIRE;
/*
* Parport hookup
*/
pp->port = p;
pd = parport_register_device(p, DRVNAME,
NULL, NULL, NULL,
PARPORT_FLAG_EXCL, pp);
if (!pd) {
status = -ENOMEM;
goto out_free_master;
}
pp->pd = pd;
status = parport_claim(pd);
if (status < 0)
goto out_parport_unreg;
/*
* Start SPI ...
*/
status = spi_bitbang_start(&pp->bitbang);
if (status < 0) {
printk(KERN_WARNING
"%s: spi_bitbang_start failed with status %d\n",
DRVNAME, status);
goto out_off_and_release;
}
/*
* The modalias name MUST match the device_driver name
* for the bus glue code to match and subsequently bind them.
* We are binding to the generic drivers/hwmon/lm70.c device
* driver.
*/
strcpy(pp->info.modalias, "lm70");
pp->info.max_speed_hz = 6 * 1000 * 1000;
pp->info.chip_select = 0;
pp->info.mode = SPI_3WIRE | SPI_MODE_0;
/* power up the chip, and let the LM70 control SI/SO */
parport_write_data(pp->port, lm70_INIT);
/* Enable access to our primary data structure via
* the board info's (void *)controller_data.
*/
pp->info.controller_data = pp;
pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
if (pp->spidev_lm70)
dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
dev_name(&pp->spidev_lm70->dev));
else {
printk(KERN_WARNING "%s: spi_new_device failed\n", DRVNAME);
status = -ENODEV;
goto out_bitbang_stop;
}
pp->spidev_lm70->bits_per_word = 8;
lm70llp = pp;
return;
out_bitbang_stop:
spi_bitbang_stop(&pp->bitbang);
out_off_and_release:
/* power down */
parport_write_data(pp->port, 0);
mdelay(10);
parport_release(pp->pd);
out_parport_unreg:
parport_unregister_device(pd);
out_free_master:
(void) spi_master_put(master);
out_fail:
pr_info("%s: spi_lm70llp probe fail, status %d\n", DRVNAME, status);
}
static void spi_lm70llp_detach(struct parport *p)
{
struct spi_lm70llp *pp;
if (!lm70llp || lm70llp->port != p)
return;
pp = lm70llp;
spi_bitbang_stop(&pp->bitbang);
/* power down */
parport_write_data(pp->port, 0);
parport_release(pp->pd);
parport_unregister_device(pp->pd);
(void) spi_master_put(pp->bitbang.master);
lm70llp = NULL;
}
static struct parport_driver spi_lm70llp_drv = {
.name = DRVNAME,
.attach = spi_lm70llp_attach,
.detach = spi_lm70llp_detach,
};
static int __init init_spi_lm70llp(void)
{
return parport_register_driver(&spi_lm70llp_drv);
}
module_init(init_spi_lm70llp);
static void __exit cleanup_spi_lm70llp(void)
{
parport_unregister_driver(&spi_lm70llp_drv);
}
module_exit(cleanup_spi_lm70llp);
MODULE_AUTHOR("Kaiwan N Billimoria <kaiwan@designergraphix.com>");
MODULE_DESCRIPTION(
"Parport adapter for the National Semiconductor LM70 LLP eval board");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,945 @@
/*
* MPC8xxx SPI controller driver.
*
* Maintainer: Kumar Gala
*
* Copyright (C) 2006 Polycom, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_spi.h>
#include <sysdev/fsl_soc.h>
#include <asm/irq.h>
/* SPI Controller registers */
struct mpc8xxx_spi_reg {
u8 res1[0x20];
__be32 mode;
__be32 event;
__be32 mask;
__be32 command;
__be32 transmit;
__be32 receive;
};
/* SPI Controller mode register definitions */
#define SPMODE_LOOP (1 << 30)
#define SPMODE_CI_INACTIVEHIGH (1 << 29)
#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
#define SPMODE_DIV16 (1 << 27)
#define SPMODE_REV (1 << 26)
#define SPMODE_MS (1 << 25)
#define SPMODE_ENABLE (1 << 24)
#define SPMODE_LEN(x) ((x) << 20)
#define SPMODE_PM(x) ((x) << 16)
#define SPMODE_OP (1 << 14)
#define SPMODE_CG(x) ((x) << 7)
/*
* Default for SPI Mode:
* SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
*/
#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
/* SPIE register values */
#define SPIE_NE 0x00000200 /* Not empty */
#define SPIE_NF 0x00000100 /* Not full */
/* SPIM register values */
#define SPIM_NE 0x00000200 /* Not empty */
#define SPIM_NF 0x00000100 /* Not full */
/* SPI Controller driver's private data. */
struct mpc8xxx_spi {
struct mpc8xxx_spi_reg __iomem *base;
/* rx & tx bufs from the spi_transfer */
const void *tx;
void *rx;
/* functions to deal with different sized buffers */
void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
u32(*get_tx) (struct mpc8xxx_spi *);
unsigned int count;
unsigned int irq;
unsigned nsecs; /* (clock cycle time)/2 */
u32 spibrg; /* SPIBRG input clock */
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
bool qe_mode;
struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
spinlock_t lock;
struct completion done;
};
struct spi_mpc8xxx_cs {
/* functions to deal with different sized buffers */
void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
u32 (*get_tx) (struct mpc8xxx_spi *);
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
u32 hw_mode; /* Holds HW mode register settings */
};
static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
{
out_be32(reg, val);
}
static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
{
return in_be32(reg);
}
#define MPC83XX_SPI_RX_BUF(type) \
static \
void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
{ \
type *rx = mpc8xxx_spi->rx; \
*rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \
mpc8xxx_spi->rx = rx; \
}
#define MPC83XX_SPI_TX_BUF(type) \
static \
u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
{ \
u32 data; \
const type *tx = mpc8xxx_spi->tx; \
if (!tx) \
return 0; \
data = *tx++ << mpc8xxx_spi->tx_shift; \
mpc8xxx_spi->tx = tx; \
return data; \
}
MPC83XX_SPI_RX_BUF(u8)
MPC83XX_SPI_RX_BUF(u16)
MPC83XX_SPI_RX_BUF(u32)
MPC83XX_SPI_TX_BUF(u8)
MPC83XX_SPI_TX_BUF(u16)
MPC83XX_SPI_TX_BUF(u32)
static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
bool pol = spi->mode & SPI_CS_HIGH;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
if (value == BITBANG_CS_INACTIVE) {
if (pdata->cs_control)
pdata->cs_control(spi, !pol);
}
if (value == BITBANG_CS_ACTIVE) {
u32 regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
mpc8xxx_spi->rx_shift = cs->rx_shift;
mpc8xxx_spi->tx_shift = cs->tx_shift;
mpc8xxx_spi->get_rx = cs->get_rx;
mpc8xxx_spi->get_tx = cs->get_tx;
if (cs->hw_mode != regval) {
unsigned long flags;
__be32 __iomem *mode = &mpc8xxx_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time that
* SPI is disabled
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
mpc8xxx_spi_write_reg(mode, regval);
local_irq_restore(flags);
}
if (pdata->cs_control)
pdata->cs_control(spi, pol);
}
}
static
int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi;
u32 regval;
u8 bits_per_word, pm;
u32 hz;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
mpc8xxx_spi = spi_master_get_devdata(spi->master);
if (t) {
bits_per_word = t->bits_per_word;
hz = t->speed_hz;
} else {
bits_per_word = 0;
hz = 0;
}
/* spi_transfer level calls that work per-word */
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
cs->rx_shift = 0;
cs->tx_shift = 0;
if (bits_per_word <= 8) {
cs->get_rx = mpc8xxx_spi_rx_buf_u8;
cs->get_tx = mpc8xxx_spi_tx_buf_u8;
if (mpc8xxx_spi->qe_mode) {
cs->rx_shift = 16;
cs->tx_shift = 24;
}
} else if (bits_per_word <= 16) {
cs->get_rx = mpc8xxx_spi_rx_buf_u16;
cs->get_tx = mpc8xxx_spi_tx_buf_u16;
if (mpc8xxx_spi->qe_mode) {
cs->rx_shift = 16;
cs->tx_shift = 16;
}
} else if (bits_per_word <= 32) {
cs->get_rx = mpc8xxx_spi_rx_buf_u32;
cs->get_tx = mpc8xxx_spi_tx_buf_u32;
} else
return -EINVAL;
if (mpc8xxx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
cs->tx_shift = 0;
if (bits_per_word <= 8)
cs->rx_shift = 8;
else
cs->rx_shift = 0;
}
mpc8xxx_spi->rx_shift = cs->rx_shift;
mpc8xxx_spi->tx_shift = cs->tx_shift;
mpc8xxx_spi->get_rx = cs->get_rx;
mpc8xxx_spi->get_tx = cs->get_tx;
if (bits_per_word == 32)
bits_per_word = 0;
else
bits_per_word = bits_per_word - 1;
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
| SPMODE_PM(0xF));
cs->hw_mode |= SPMODE_LEN(bits_per_word);
if ((mpc8xxx_spi->spibrg / hz) > 64) {
cs->hw_mode |= SPMODE_DIV16;
pm = mpc8xxx_spi->spibrg / (hz * 64);
WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
"Will use %d Hz instead.\n", dev_name(&spi->dev),
hz, mpc8xxx_spi->spibrg / 1024);
if (pm > 16)
pm = 16;
} else
pm = mpc8xxx_spi->spibrg / (hz * 4);
if (pm)
pm--;
cs->hw_mode |= SPMODE_PM(pm);
regval = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
if (cs->hw_mode != regval) {
unsigned long flags;
__be32 __iomem *mode = &mpc8xxx_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time
* that SPI is disabled
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
mpc8xxx_spi_write_reg(mode, regval & ~SPMODE_ENABLE);
mpc8xxx_spi_write_reg(mode, regval);
local_irq_restore(flags);
}
return 0;
}
static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi;
u32 word, len, bits_per_word;
mpc8xxx_spi = spi_master_get_devdata(spi->master);
mpc8xxx_spi->tx = t->tx_buf;
mpc8xxx_spi->rx = t->rx_buf;
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
len = t->len;
if (bits_per_word > 8) {
/* invalid length? */
if (len & 1)
return -EINVAL;
len /= 2;
}
if (bits_per_word > 16) {
/* invalid length? */
if (len & 1)
return -EINVAL;
len /= 2;
}
mpc8xxx_spi->count = len;
INIT_COMPLETION(mpc8xxx_spi->done);
/* enable rx ints */
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, SPIM_NE);
/* transmit word */
word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
wait_for_completion(&mpc8xxx_spi->done);
/* disable rx ints */
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
return mpc8xxx_spi->count;
}
static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
{
struct spi_device *spi = m->spi;
struct spi_transfer *t;
unsigned int cs_change;
const int nsecs = 50;
int status;
cs_change = 1;
status = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
/* Don't allow changes if CS is active */
status = -EINVAL;
if (cs_change)
status = mpc8xxx_spi_setup_transfer(spi, t);
if (status < 0)
break;
}
if (cs_change) {
mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
ndelay(nsecs);
}
cs_change = t->cs_change;
if (t->len)
status = mpc8xxx_spi_bufs(spi, t);
if (status) {
status = -EMSGSIZE;
break;
}
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (cs_change) {
ndelay(nsecs);
mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
}
m->status = status;
m->complete(m->context);
if (status || !cs_change) {
ndelay(nsecs);
mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
}
mpc8xxx_spi_setup_transfer(spi, NULL);
}
static void mpc8xxx_spi_work(struct work_struct *work)
{
struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
work);
spin_lock_irq(&mpc8xxx_spi->lock);
while (!list_empty(&mpc8xxx_spi->queue)) {
struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&mpc8xxx_spi->lock);
mpc8xxx_spi_do_one_msg(m);
spin_lock_irq(&mpc8xxx_spi->lock);
}
spin_unlock_irq(&mpc8xxx_spi->lock);
}
static int mpc8xxx_spi_setup(struct spi_device *spi)
{
struct mpc8xxx_spi *mpc8xxx_spi;
int retval;
u32 hw_mode;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
if (!spi->max_speed_hz)
return -EINVAL;
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
mpc8xxx_spi = spi_master_get_devdata(spi->master);
hw_mode = cs->hw_mode; /* Save orginal settings */
cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
| SPMODE_REV | SPMODE_LOOP);
if (spi->mode & SPI_CPHA)
cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
if (spi->mode & SPI_CPOL)
cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
if (!(spi->mode & SPI_LSB_FIRST))
cs->hw_mode |= SPMODE_REV;
if (spi->mode & SPI_LOOP)
cs->hw_mode |= SPMODE_LOOP;
retval = mpc8xxx_spi_setup_transfer(spi, NULL);
if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */
return retval;
}
return 0;
}
static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
{
struct mpc8xxx_spi *mpc8xxx_spi = context_data;
u32 event;
irqreturn_t ret = IRQ_NONE;
/* Get interrupt events(tx/rx) */
event = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event);
/* We need handle RX first */
if (event & SPIE_NE) {
u32 rx_data = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->receive);
if (mpc8xxx_spi->rx)
mpc8xxx_spi->get_rx(rx_data, mpc8xxx_spi);
ret = IRQ_HANDLED;
}
if ((event & SPIE_NF) == 0)
/* spin until TX is done */
while (((event =
mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->event)) &
SPIE_NF) == 0)
cpu_relax();
mpc8xxx_spi->count -= 1;
if (mpc8xxx_spi->count) {
u32 word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->transmit, word);
} else {
complete(&mpc8xxx_spi->done);
}
/* Clear the events */
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, event);
return ret;
}
static int mpc8xxx_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
list_add_tail(&m->queue, &mpc8xxx_spi->queue);
queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
return 0;
}
static void mpc8xxx_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static struct spi_master * __devinit
mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
u32 regval;
int ret = 0;
master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
if (master == NULL) {
ret = -ENOMEM;
goto err;
}
dev_set_drvdata(dev, master);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
| SPI_LSB_FIRST | SPI_LOOP;
master->setup = mpc8xxx_spi_setup;
master->transfer = mpc8xxx_spi_transfer;
master->cleanup = mpc8xxx_spi_cleanup;
mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->qe_mode = pdata->qe_mode;
mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
mpc8xxx_spi->spibrg = pdata->sysclk;
mpc8xxx_spi->rx_shift = 0;
mpc8xxx_spi->tx_shift = 0;
if (mpc8xxx_spi->qe_mode) {
mpc8xxx_spi->rx_shift = 16;
mpc8xxx_spi->tx_shift = 24;
}
init_completion(&mpc8xxx_spi->done);
mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
if (mpc8xxx_spi->base == NULL) {
ret = -ENOMEM;
goto put_master;
}
mpc8xxx_spi->irq = irq;
/* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
0, "mpc8xxx_spi", mpc8xxx_spi);
if (ret != 0)
goto unmap_io;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
/* SPI controller initializations */
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
if (pdata->qe_mode)
regval |= SPMODE_OP;
mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
spin_lock_init(&mpc8xxx_spi->lock);
init_completion(&mpc8xxx_spi->done);
INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
INIT_LIST_HEAD(&mpc8xxx_spi->queue);
mpc8xxx_spi->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (mpc8xxx_spi->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
ret = spi_register_master(master);
if (ret < 0)
goto unreg_master;
printk(KERN_INFO
"%s: MPC8xxx SPI Controller driver at 0x%p (irq = %d)\n",
dev_name(dev), mpc8xxx_spi->base, mpc8xxx_spi->irq);
return master;
unreg_master:
destroy_workqueue(mpc8xxx_spi->workqueue);
free_irq:
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
unmap_io:
iounmap(mpc8xxx_spi->base);
put_master:
spi_master_put(master);
err:
return ERR_PTR(ret);
}
static int __devexit mpc8xxx_spi_remove(struct device *dev)
{
struct mpc8xxx_spi *mpc8xxx_spi;
struct spi_master *master;
master = dev_get_drvdata(dev);
mpc8xxx_spi = spi_master_get_devdata(master);
flush_workqueue(mpc8xxx_spi->workqueue);
destroy_workqueue(mpc8xxx_spi->workqueue);
spi_unregister_master(master);
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
iounmap(mpc8xxx_spi->base);
return 0;
}
struct mpc8xxx_spi_probe_info {
struct fsl_spi_platform_data pdata;
int *gpios;
bool *alow_flags;
};
static struct mpc8xxx_spi_probe_info *
to_of_pinfo(struct fsl_spi_platform_data *pdata)
{
return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
}
static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
{
struct device *dev = spi->dev.parent;
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
u16 cs = spi->chip_select;
int gpio = pinfo->gpios[cs];
bool alow = pinfo->alow_flags[cs];
gpio_set_value(gpio, on ^ alow);
}
static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
{
struct device_node *np = dev_archdata_get_node(&dev->archdata);
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
unsigned int ngpios;
int i = 0;
int ret;
ngpios = of_gpio_count(np);
if (!ngpios) {
/*
* SPI w/o chip-select line. One SPI device is still permitted
* though.
*/
pdata->max_chipselect = 1;
return 0;
}
pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
if (!pinfo->gpios)
return -ENOMEM;
memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
GFP_KERNEL);
if (!pinfo->alow_flags) {
ret = -ENOMEM;
goto err_alloc_flags;
}
for (; i < ngpios; i++) {
int gpio;
enum of_gpio_flags flags;
gpio = of_get_gpio_flags(np, i, &flags);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
goto err_loop;
}
ret = gpio_request(gpio, dev_name(dev));
if (ret) {
dev_err(dev, "can't request gpio #%d: %d\n", i, ret);
goto err_loop;
}
pinfo->gpios[i] = gpio;
pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW;
ret = gpio_direction_output(pinfo->gpios[i],
pinfo->alow_flags[i]);
if (ret) {
dev_err(dev, "can't set output direction for gpio "
"#%d: %d\n", i, ret);
goto err_loop;
}
}
pdata->max_chipselect = ngpios;
pdata->cs_control = mpc8xxx_spi_cs_control;
return 0;
err_loop:
while (i >= 0) {
if (gpio_is_valid(pinfo->gpios[i]))
gpio_free(pinfo->gpios[i]);
i--;
}
kfree(pinfo->alow_flags);
pinfo->alow_flags = NULL;
err_alloc_flags:
kfree(pinfo->gpios);
pinfo->gpios = NULL;
return ret;
}
static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
int i;
if (!pinfo->gpios)
return 0;
for (i = 0; i < pdata->max_chipselect; i++) {
if (gpio_is_valid(pinfo->gpios[i]))
gpio_free(pinfo->gpios[i]);
}
kfree(pinfo->gpios);
kfree(pinfo->alow_flags);
return 0;
}
static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
const struct of_device_id *ofid)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->node;
struct mpc8xxx_spi_probe_info *pinfo;
struct fsl_spi_platform_data *pdata;
struct spi_master *master;
struct resource mem;
struct resource irq;
const void *prop;
int ret = -ENOMEM;
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
pdata = &pinfo->pdata;
dev->platform_data = pdata;
/* Allocate bus num dynamically. */
pdata->bus_num = -1;
/* SPI controller is either clocked from QE or SoC clock. */
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
pdata->sysclk = fsl_get_sys_freq();
if (pdata->sysclk == -1) {
ret = -ENODEV;
goto err_clk;
}
}
prop = of_get_property(np, "mode", NULL);
if (prop && !strcmp(prop, "cpu-qe"))
pdata->qe_mode = 1;
ret = of_mpc8xxx_spi_get_chipselects(dev);
if (ret)
goto err;
ret = of_address_to_resource(np, 0, &mem);
if (ret)
goto err;
ret = of_irq_to_resource(np, 0, &irq);
if (!ret) {
ret = -EINVAL;
goto err;
}
master = mpc8xxx_spi_probe(dev, &mem, irq.start);
if (IS_ERR(master)) {
ret = PTR_ERR(master);
goto err;
}
of_register_spi_devices(master, np);
return 0;
err:
of_mpc8xxx_spi_free_chipselects(dev);
err_clk:
kfree(pinfo);
return ret;
}
static int __devexit of_mpc8xxx_spi_remove(struct of_device *ofdev)
{
int ret;
ret = mpc8xxx_spi_remove(&ofdev->dev);
if (ret)
return ret;
of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
return 0;
}
static const struct of_device_id of_mpc8xxx_spi_match[] = {
{ .compatible = "fsl,spi" },
{},
};
MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
static struct of_platform_driver of_mpc8xxx_spi_driver = {
.name = "mpc8xxx_spi",
.match_table = of_mpc8xxx_spi_match,
.probe = of_mpc8xxx_spi_probe,
.remove = __devexit_p(of_mpc8xxx_spi_remove),
};
#ifdef CONFIG_MPC832x_RDB
/*
* XXX XXX XXX
* This is "legacy" platform driver, was used by the MPC8323E-RDB boards
* only. The driver should go away soon, since newer MPC8323E-RDB's device
* tree can work with OpenFirmware driver. But for now we support old trees
* as well.
*/
static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
unsigned int irq;
struct spi_master *master;
if (!pdev->dev.platform_data)
return -EINVAL;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
if (!irq)
return -EINVAL;
master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
if (IS_ERR(master))
return PTR_ERR(master);
return 0;
}
static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
return mpc8xxx_spi_remove(&pdev->dev);
}
MODULE_ALIAS("platform:mpc8xxx_spi");
static struct platform_driver mpc8xxx_spi_driver = {
.probe = plat_mpc8xxx_spi_probe,
.remove = __exit_p(plat_mpc8xxx_spi_remove),
.driver = {
.name = "mpc8xxx_spi",
.owner = THIS_MODULE,
},
};
static bool legacy_driver_failed;
static void __init legacy_driver_register(void)
{
legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
}
static void __exit legacy_driver_unregister(void)
{
if (legacy_driver_failed)
return;
platform_driver_unregister(&mpc8xxx_spi_driver);
}
#else
static void __init legacy_driver_register(void) {}
static void __exit legacy_driver_unregister(void) {}
#endif /* CONFIG_MPC832x_RDB */
static int __init mpc8xxx_spi_init(void)
{
legacy_driver_register();
return of_register_platform_driver(&of_mpc8xxx_spi_driver);
}
static void __exit mpc8xxx_spi_exit(void)
{
of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
legacy_driver_unregister();
}
module_init(mpc8xxx_spi_init);
module_exit(mpc8xxx_spi_exit);
MODULE_AUTHOR("Kumar Gala");
MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,612 @@
/*
* SPI_PPC4XX SPI controller driver.
*
* Copyright (C) 2007 Gary Jennejohn <garyj@denx.de>
* Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
* Copyright 2009 Harris Corporation, Steven A. Falco <sfalco@harris.com>
*
* Based in part on drivers/spi/spi_s3c24xx.c
*
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
/*
* The PPC4xx SPI controller has no FIFO so each sent/received byte will
* generate an interrupt to the CPU. This can cause high CPU utilization.
* This driver allows platforms to reduce the interrupt load on the CPU
* during SPI transfers by setting max_speed_hz via the device tree.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/of_platform.h>
#include <linux/of_spi.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/io.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
/* bits in mode register - bit 0 is MSb */
/*
* SPI_PPC4XX_MODE_SCP = 0 means "data latched on trailing edge of clock"
* SPI_PPC4XX_MODE_SCP = 1 means "data latched on leading edge of clock"
* Note: This is the inverse of CPHA.
*/
#define SPI_PPC4XX_MODE_SCP (0x80 >> 3)
/* SPI_PPC4XX_MODE_SPE = 1 means "port enabled" */
#define SPI_PPC4XX_MODE_SPE (0x80 >> 4)
/*
* SPI_PPC4XX_MODE_RD = 0 means "MSB first" - this is the normal mode
* SPI_PPC4XX_MODE_RD = 1 means "LSB first" - this is bit-reversed mode
* Note: This is identical to SPI_LSB_FIRST.
*/
#define SPI_PPC4XX_MODE_RD (0x80 >> 5)
/*
* SPI_PPC4XX_MODE_CI = 0 means "clock idles low"
* SPI_PPC4XX_MODE_CI = 1 means "clock idles high"
* Note: This is identical to CPOL.
*/
#define SPI_PPC4XX_MODE_CI (0x80 >> 6)
/*
* SPI_PPC4XX_MODE_IL = 0 means "loopback disable"
* SPI_PPC4XX_MODE_IL = 1 means "loopback enable"
*/
#define SPI_PPC4XX_MODE_IL (0x80 >> 7)
/* bits in control register */
/* starts a transfer when set */
#define SPI_PPC4XX_CR_STR (0x80 >> 7)
/* bits in status register */
/* port is busy with a transfer */
#define SPI_PPC4XX_SR_BSY (0x80 >> 6)
/* RxD ready */
#define SPI_PPC4XX_SR_RBR (0x80 >> 7)
/* clock settings (SCP and CI) for various SPI modes */
#define SPI_CLK_MODE0 (SPI_PPC4XX_MODE_SCP | 0)
#define SPI_CLK_MODE1 (0 | 0)
#define SPI_CLK_MODE2 (SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
#define SPI_CLK_MODE3 (0 | SPI_PPC4XX_MODE_CI)
#define DRIVER_NAME "spi_ppc4xx_of"
struct spi_ppc4xx_regs {
u8 mode;
u8 rxd;
u8 txd;
u8 cr;
u8 sr;
u8 dummy;
/*
* Clock divisor modulus register
* This uses the follwing formula:
* SCPClkOut = OPBCLK/(4(CDM + 1))
* or
* CDM = (OPBCLK/4*SCPClkOut) - 1
* bit 0 is the MSb!
*/
u8 cdm;
};
/* SPI Controller driver's private data. */
struct ppc4xx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
u64 mapbase;
u64 mapsize;
int irqnum;
/* need this to set the SPI clock */
unsigned int opb_freq;
/* for transfers */
int len;
int count;
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
int *gpios;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
struct spi_master *master;
struct device *dev;
};
/* need this so we can set the clock in the chipselect routine */
struct spi_ppc4xx_cs {
u8 mode;
};
static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct ppc4xx_spi *hw;
u8 data;
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
hw = spi_master_get_devdata(spi->master);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->len = t->len;
hw->count = 0;
/* send the first byte */
data = hw->tx ? hw->tx[0] : 0;
out_8(&hw->regs->txd, data);
out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
wait_for_completion(&hw->done);
return hw->count;
}
static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
struct spi_ppc4xx_cs *cs = spi->controller_state;
int scr;
u8 cdm = 0;
u32 speed;
u8 bits_per_word;
/* Start with the generic configuration for this device. */
bits_per_word = spi->bits_per_word;
speed = spi->max_speed_hz;
/*
* Modify the configuration if the transfer overrides it. Do not allow
* the transfer to overwrite the generic configuration with zeros.
*/
if (t) {
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
if (t->speed_hz)
speed = min(t->speed_hz, spi->max_speed_hz);
}
if (bits_per_word != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
bits_per_word);
return -EINVAL;
}
if (!speed || (speed > spi->max_speed_hz)) {
dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
return -EINVAL;
}
/* Write new configration */
out_8(&hw->regs->mode, cs->mode);
/* Set the clock */
/* opb_freq was already divided by 4 */
scr = (hw->opb_freq / speed) - 1;
if (scr > 0)
cdm = min(scr, 0xff);
dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", cdm, speed);
if (in_8(&hw->regs->cdm) != cdm)
out_8(&hw->regs->cdm, cdm);
spin_lock(&hw->bitbang.lock);
if (!hw->bitbang.busy) {
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
/* Need to ndelay here? */
}
spin_unlock(&hw->bitbang.lock);
return 0;
}
static int spi_ppc4xx_setup(struct spi_device *spi)
{
struct spi_ppc4xx_cs *cs = spi->controller_state;
if (spi->bits_per_word != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
spi->bits_per_word);
return -EINVAL;
}
if (!spi->max_speed_hz) {
dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
return -EINVAL;
}
if (cs == NULL) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
/*
* We set all bits of the SPI0_MODE register, so,
* no need to read-modify-write
*/
cs->mode = SPI_PPC4XX_MODE_SPE;
switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
case SPI_MODE_0:
cs->mode |= SPI_CLK_MODE0;
break;
case SPI_MODE_1:
cs->mode |= SPI_CLK_MODE1;
break;
case SPI_MODE_2:
cs->mode |= SPI_CLK_MODE2;
break;
case SPI_MODE_3:
cs->mode |= SPI_CLK_MODE3;
break;
}
if (spi->mode & SPI_LSB_FIRST)
cs->mode |= SPI_PPC4XX_MODE_RD;
return 0;
}
static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
{
struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
unsigned int cs = spi->chip_select;
unsigned int cspol;
/*
* If there are no chip selects at all, or if this is the special
* case of a non-existent (dummy) chip select, do nothing.
*/
if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
return;
cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
if (value == BITBANG_CS_INACTIVE)
cspol = !cspol;
gpio_set_value(hw->gpios[cs], cspol);
}
static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
{
struct ppc4xx_spi *hw;
u8 status;
u8 data;
unsigned int count;
hw = (struct ppc4xx_spi *)dev_id;
status = in_8(&hw->regs->sr);
if (!status)
return IRQ_NONE;
/*
* BSY de-asserts one cycle after the transfer is complete. The
* interrupt is asserted after the transfer is complete. The exact
* relationship is not documented, hence this code.
*/
if (unlikely(status & SPI_PPC4XX_SR_BSY)) {
u8 lstatus;
int cnt = 0;
dev_dbg(hw->dev, "got interrupt but spi still busy?\n");
do {
ndelay(10);
lstatus = in_8(&hw->regs->sr);
} while (++cnt < 100 && lstatus & SPI_PPC4XX_SR_BSY);
if (cnt >= 100) {
dev_err(hw->dev, "busywait: too many loops!\n");
complete(&hw->done);
return IRQ_HANDLED;
} else {
/* status is always 1 (RBR) here */
status = in_8(&hw->regs->sr);
dev_dbg(hw->dev, "loops %d status %x\n", cnt, status);
}
}
count = hw->count;
hw->count++;
/* RBR triggered this interrupt. Therefore, data must be ready. */
data = in_8(&hw->regs->rxd);
if (hw->rx)
hw->rx[count] = data;
count++;
if (count < hw->len) {
data = hw->tx ? hw->tx[count] : 0;
out_8(&hw->regs->txd, data);
out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
} else {
complete(&hw->done);
}
return IRQ_HANDLED;
}
static void spi_ppc4xx_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
{
/*
* On all 4xx PPC's the SPI bus is shared/multiplexed with
* the 2nd I2C bus. We need to enable the the SPI bus before
* using it.
*/
/* need to clear bit 14 to enable SPC */
dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
}
static void free_gpios(struct ppc4xx_spi *hw)
{
if (hw->master->num_chipselect) {
int i;
for (i = 0; i < hw->master->num_chipselect; i++)
if (gpio_is_valid(hw->gpios[i]))
gpio_free(hw->gpios[i]);
kfree(hw->gpios);
hw->gpios = NULL;
}
}
/*
* of_device layer stuff...
*/
static int __init spi_ppc4xx_of_probe(struct of_device *op,
const struct of_device_id *match)
{
struct ppc4xx_spi *hw;
struct spi_master *master;
struct spi_bitbang *bbp;
struct resource resource;
struct device_node *np = op->node;
struct device *dev = &op->dev;
struct device_node *opbnp;
int ret;
int num_gpios;
const unsigned int *clk;
master = spi_alloc_master(dev, sizeof *hw);
if (master == NULL)
return -ENOMEM;
dev_set_drvdata(dev, master);
hw = spi_master_get_devdata(master);
hw->master = spi_master_get(master);
hw->dev = dev;
init_completion(&hw->done);
/*
* A count of zero implies a single SPI device without any chip-select.
* Note that of_gpio_count counts all gpios assigned to this spi master.
* This includes both "null" gpio's and real ones.
*/
num_gpios = of_gpio_count(np);
if (num_gpios) {
int i;
hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
if (!hw->gpios) {
ret = -ENOMEM;
goto free_master;
}
for (i = 0; i < num_gpios; i++) {
int gpio;
enum of_gpio_flags flags;
gpio = of_get_gpio_flags(np, i, &flags);
hw->gpios[i] = gpio;
if (gpio_is_valid(gpio)) {
/* Real CS - set the initial state. */
ret = gpio_request(gpio, np->name);
if (ret < 0) {
dev_err(dev, "can't request gpio "
"#%d: %d\n", i, ret);
goto free_gpios;
}
gpio_direction_output(gpio,
!!(flags & OF_GPIO_ACTIVE_LOW));
} else if (gpio == -EEXIST) {
; /* No CS, but that's OK. */
} else {
dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
ret = -EINVAL;
goto free_gpios;
}
}
}
/* Setup the state for the bitbang driver */
bbp = &hw->bitbang;
bbp->master = hw->master;
bbp->setup_transfer = spi_ppc4xx_setupxfer;
bbp->chipselect = spi_ppc4xx_chipsel;
bbp->txrx_bufs = spi_ppc4xx_txrx;
bbp->use_dma = 0;
bbp->master->setup = spi_ppc4xx_setup;
bbp->master->cleanup = spi_ppc4xx_cleanup;
/* Allocate bus num dynamically. */
bbp->master->bus_num = -1;
/* the spi->mode bits understood by this driver: */
bbp->master->mode_bits =
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
/* this many pins in all GPIO controllers */
bbp->master->num_chipselect = num_gpios;
/* Get the clock for the OPB */
opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
if (opbnp == NULL) {
dev_err(dev, "OPB: cannot find node\n");
ret = -ENODEV;
goto free_gpios;
}
/* Get the clock (Hz) for the OPB */
clk = of_get_property(opbnp, "clock-frequency", NULL);
if (clk == NULL) {
dev_err(dev, "OPB: no clock-frequency property set\n");
of_node_put(opbnp);
ret = -ENODEV;
goto free_gpios;
}
hw->opb_freq = *clk;
hw->opb_freq >>= 2;
of_node_put(opbnp);
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_err(dev, "error while parsing device node resource\n");
goto free_gpios;
}
hw->mapbase = resource.start;
hw->mapsize = resource.end - resource.start + 1;
/* Sanity check */
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
dev_err(dev, "too small to map registers\n");
ret = -EINVAL;
goto free_gpios;
}
/* Request IRQ */
hw->irqnum = irq_of_parse_and_map(np, 0);
ret = request_irq(hw->irqnum, spi_ppc4xx_int,
IRQF_DISABLED, "spi_ppc4xx_of", (void *)hw);
if (ret) {
dev_err(dev, "unable to allocate interrupt\n");
goto free_gpios;
}
if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
dev_err(dev, "resource unavailable\n");
ret = -EBUSY;
goto request_mem_error;
}
hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
if (!hw->regs) {
dev_err(dev, "unable to memory map registers\n");
ret = -ENXIO;
goto map_io_error;
}
spi_ppc4xx_enable(hw);
/* Finally register our spi controller */
dev->dma_mask = 0;
ret = spi_bitbang_start(bbp);
if (ret) {
dev_err(dev, "failed to register SPI master\n");
goto unmap_regs;
}
dev_info(dev, "driver initialized\n");
of_register_spi_devices(master, np);
return 0;
unmap_regs:
iounmap(hw->regs);
map_io_error:
release_mem_region(hw->mapbase, hw->mapsize);
request_mem_error:
free_irq(hw->irqnum, hw);
free_gpios:
free_gpios(hw);
free_master:
dev_set_drvdata(dev, NULL);
spi_master_put(master);
dev_err(dev, "initialization failed\n");
return ret;
}
static int __exit spi_ppc4xx_of_remove(struct of_device *op)
{
struct spi_master *master = dev_get_drvdata(&op->dev);
struct ppc4xx_spi *hw = spi_master_get_devdata(master);
spi_bitbang_stop(&hw->bitbang);
dev_set_drvdata(&op->dev, NULL);
release_mem_region(hw->mapbase, hw->mapsize);
free_irq(hw->irqnum, hw);
iounmap(hw->regs);
free_gpios(hw);
return 0;
}
static struct of_device_id spi_ppc4xx_of_match[] = {
{ .compatible = "ibm,ppc4xx-spi", },
{},
};
MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
static struct of_platform_driver spi_ppc4xx_of_driver = {
.match_table = spi_ppc4xx_of_match,
.probe = spi_ppc4xx_of_probe,
.remove = __exit_p(spi_ppc4xx_of_remove),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static int __init spi_ppc4xx_init(void)
{
return of_register_platform_driver(&spi_ppc4xx_of_driver);
}
module_init(spi_ppc4xx_init);
static void __exit spi_ppc4xx_exit(void)
{
of_unregister_platform_driver(&spi_ppc4xx_of_driver);
}
module_exit(spi_ppc4xx_exit);
MODULE_AUTHOR("Gary Jennejohn & Stefan Roese");
MODULE_DESCRIPTION("Simple PPC4xx SPI Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,527 @@
/* linux/drivers/spi/spi_s3c24xx.c
*
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <plat/regs-spi.h>
#include <mach/spi.h>
/**
* s3c24xx_spi_devstate - per device data
* @hz: Last frequency calculated for @sppre field.
* @mode: Last mode setting for the @spcon field.
* @spcon: Value to write to the SPCON register.
* @sppre: Value to write to the SPPRE register.
*/
struct s3c24xx_spi_devstate {
unsigned int hz;
unsigned int mode;
u8 spcon;
u8 sppre;
};
struct s3c24xx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
void __iomem *regs;
int irq;
int len;
int count;
void (*set_cs)(struct s3c2410_spi_info *spi,
int cs, int pol);
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
struct clk *clk;
struct resource *ioarea;
struct spi_master *master;
struct spi_device *curdev;
struct device *dev;
struct s3c2410_spi_info *pdata;
};
#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
{
return spi_master_get_devdata(sdev->master);
}
static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
{
gpio_set_value(spi->pin_cs, pol);
}
static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
{
struct s3c24xx_spi_devstate *cs = spi->controller_state;
struct s3c24xx_spi *hw = to_hw(spi);
unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
/* change the chipselect state and the state of the spi engine clock */
switch (value) {
case BITBANG_CS_INACTIVE:
hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
writeb(cs->spcon, hw->regs + S3C2410_SPCON);
break;
case BITBANG_CS_ACTIVE:
writeb(cs->spcon | S3C2410_SPCON_ENSCK,
hw->regs + S3C2410_SPCON);
hw->set_cs(hw->pdata, spi->chip_select, cspol);
break;
}
}
static int s3c24xx_spi_update_state(struct spi_device *spi,
struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
if (!bpw)
bpw = 8;
if (!hz)
hz = spi->max_speed_hz;
if (bpw != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
return -EINVAL;
}
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT;
if (spi->mode & SPI_CPHA)
spcon |= S3C2410_SPCON_CPHA_FMTB;
if (spi->mode & SPI_CPOL)
spcon |= S3C2410_SPCON_CPOL_HIGH;
cs->mode = spi->mode;
cs->spcon = spcon;
}
if (cs->hz != hz) {
clk = clk_get_rate(hw->clk);
div = DIV_ROUND_UP(clk, hz * 2) - 1;
if (div > 255)
div = 255;
dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n",
div, hz, clk / (2 * (div + 1)));
cs->hz = hz;
cs->sppre = div;
}
return 0;
}
static int s3c24xx_spi_setupxfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct s3c24xx_spi_devstate *cs = spi->controller_state;
struct s3c24xx_spi *hw = to_hw(spi);
int ret;
ret = s3c24xx_spi_update_state(spi, t);
if (!ret)
writeb(cs->sppre, hw->regs + S3C2410_SPPRE);
return ret;
}
static int s3c24xx_spi_setup(struct spi_device *spi)
{
struct s3c24xx_spi_devstate *cs = spi->controller_state;
struct s3c24xx_spi *hw = to_hw(spi);
int ret;
/* allocate settings on the first call */
if (!cs) {
cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL);
if (!cs) {
dev_err(&spi->dev, "no memory for controller state\n");
return -ENOMEM;
}
cs->spcon = SPCON_DEFAULT;
cs->hz = -1;
spi->controller_state = cs;
}
/* initialise the state from the device */
ret = s3c24xx_spi_update_state(spi, NULL);
if (ret)
return ret;
spin_lock(&hw->bitbang.lock);
if (!hw->bitbang.busy) {
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
/* need to ndelay for 0.5 clocktick ? */
}
spin_unlock(&hw->bitbang.lock);
return 0;
}
static void s3c24xx_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
return hw->tx ? hw->tx[count] : 0;
}
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->len = t->len;
hw->count = 0;
init_completion(&hw->done);
/* send the first byte */
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
wait_for_completion(&hw->done);
return hw->count;
}
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
{
struct s3c24xx_spi *hw = dev;
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
unsigned int count = hw->count;
if (spsta & S3C2410_SPSTA_DCOL) {
dev_dbg(hw->dev, "data-collision\n");
complete(&hw->done);
goto irq_done;
}
if (!(spsta & S3C2410_SPSTA_READY)) {
dev_dbg(hw->dev, "spi not ready for tx?\n");
complete(&hw->done);
goto irq_done;
}
hw->count++;
if (hw->rx)
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
count++;
if (count < hw->len)
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
else
complete(&hw->done);
irq_done:
return IRQ_HANDLED;
}
static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
{
/* for the moment, permanently enable the clock */
clk_enable(hw->clk);
/* program defaults into the registers */
writeb(0xff, hw->regs + S3C2410_SPPRE);
writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
if (hw->pdata) {
if (hw->set_cs == s3c24xx_spi_gpiocs)
gpio_direction_output(hw->pdata->pin_cs, 1);
if (hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 1);
}
}
static int __init s3c24xx_spi_probe(struct platform_device *pdev)
{
struct s3c2410_spi_info *pdata;
struct s3c24xx_spi *hw;
struct spi_master *master;
struct resource *res;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master == NULL) {
dev_err(&pdev->dev, "No memory for spi_master\n");
err = -ENOMEM;
goto err_nomem;
}
hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));
hw->master = spi_master_get(master);
hw->pdata = pdata = pdev->dev.platform_data;
hw->dev = &pdev->dev;
if (pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
err = -ENOENT;
goto err_no_pdata;
}
platform_set_drvdata(pdev, hw);
init_completion(&hw->done);
/* setup the master state. */
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
/* setup the state for the bitbang driver */
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
hw->bitbang.chipselect = s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
hw->master->setup = s3c24xx_spi_setup;
hw->master->cleanup = s3c24xx_spi_cleanup;
dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
err = -ENOENT;
goto err_no_iores;
}
hw->ioarea = request_mem_region(res->start, resource_size(res),
pdev->name);
if (hw->ioarea == NULL) {
dev_err(&pdev->dev, "Cannot reserve region\n");
err = -ENXIO;
goto err_no_iores;
}
hw->regs = ioremap(res->start, resource_size(res));
if (hw->regs == NULL) {
dev_err(&pdev->dev, "Cannot map IO\n");
err = -ENXIO;
goto err_no_iomap;
}
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq < 0) {
dev_err(&pdev->dev, "No IRQ specified\n");
err = -ENOENT;
goto err_no_irq;
}
err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
if (err) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
goto err_no_irq;
}
hw->clk = clk_get(&pdev->dev, "spi");
if (IS_ERR(hw->clk)) {
dev_err(&pdev->dev, "No clock for device\n");
err = PTR_ERR(hw->clk);
goto err_no_clk;
}
/* setup any gpio we can */
if (!pdata->set_cs) {
if (pdata->pin_cs < 0) {
dev_err(&pdev->dev, "No chipselect pin\n");
goto err_register;
}
err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
if (err) {
dev_err(&pdev->dev, "Failed to get gpio for cs\n");
goto err_register;
}
hw->set_cs = s3c24xx_spi_gpiocs;
gpio_direction_output(pdata->pin_cs, 1);
} else
hw->set_cs = pdata->set_cs;
s3c24xx_spi_initialsetup(hw);
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
if (err) {
dev_err(&pdev->dev, "Failed to register SPI master\n");
goto err_register;
}
return 0;
err_register:
if (hw->set_cs == s3c24xx_spi_gpiocs)
gpio_free(pdata->pin_cs);
clk_disable(hw->clk);
clk_put(hw->clk);
err_no_clk:
free_irq(hw->irq, hw);
err_no_irq:
iounmap(hw->regs);
err_no_iomap:
release_resource(hw->ioarea);
kfree(hw->ioarea);
err_no_iores:
err_no_pdata:
spi_master_put(hw->master);
err_nomem:
return err;
}
static int __exit s3c24xx_spi_remove(struct platform_device *dev)
{
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
spi_unregister_master(hw->master);
clk_disable(hw->clk);
clk_put(hw->clk);
free_irq(hw->irq, hw);
iounmap(hw->regs);
if (hw->set_cs == s3c24xx_spi_gpiocs)
gpio_free(hw->pdata->pin_cs);
release_resource(hw->ioarea);
kfree(hw->ioarea);
spi_master_put(hw->master);
return 0;
}
#ifdef CONFIG_PM
static int s3c24xx_spi_suspend(struct device *dev)
{
struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
clk_disable(hw->clk);
return 0;
}
static int s3c24xx_spi_resume(struct device *dev)
{
struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
s3c24xx_spi_initialsetup(hw);
return 0;
}
static struct dev_pm_ops s3c24xx_spi_pmops = {
.suspend = s3c24xx_spi_suspend,
.resume = s3c24xx_spi_resume,
};
#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops
#else
#define S3C24XX_SPI_PMOPS NULL
#endif /* CONFIG_PM */
MODULE_ALIAS("platform:s3c2410-spi");
static struct platform_driver s3c24xx_spi_driver = {
.remove = __exit_p(s3c24xx_spi_remove),
.driver = {
.name = "s3c2410-spi",
.owner = THIS_MODULE,
.pm = S3C24XX_SPI_PMOPS,
},
};
static int __init s3c24xx_spi_init(void)
{
return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
}
static void __exit s3c24xx_spi_exit(void)
{
platform_driver_unregister(&s3c24xx_spi_driver);
}
module_init(s3c24xx_spi_init);
module_exit(s3c24xx_spi_exit);
MODULE_DESCRIPTION("S3C24XX SPI Driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,202 @@
/* linux/drivers/spi/spi_s3c24xx_gpio.c
*
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
*
* S3C24XX GPIO based SPI driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <mach/regs-gpio.h>
#include <mach/spi-gpio.h>
#include <mach/hardware.h>
struct s3c2410_spigpio {
struct spi_bitbang bitbang;
struct s3c2410_spigpio_info *info;
struct platform_device *dev;
};
static inline struct s3c2410_spigpio *spidev_to_sg(struct spi_device *spi)
{
return spi_master_get_devdata(spi->master);
}
static inline void setsck(struct spi_device *dev, int on)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
s3c2410_gpio_setpin(sg->info->pin_clk, on ? 1 : 0);
}
static inline void setmosi(struct spi_device *dev, int on)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
s3c2410_gpio_setpin(sg->info->pin_mosi, on ? 1 : 0);
}
static inline u32 getmiso(struct spi_device *dev)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
return s3c2410_gpio_getpin(sg->info->pin_miso) ? 1 : 0;
}
#define spidelay(x) ndelay(x)
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
}
static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
if (sg->info && sg->info->chip_select)
(sg->info->chip_select)(sg->info, value);
}
static int s3c2410_spigpio_probe(struct platform_device *dev)
{
struct s3c2410_spigpio_info *info;
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
if (master == NULL) {
dev_err(&dev->dev, "failed to allocate spi master\n");
ret = -ENOMEM;
goto err;
}
sp = spi_master_get_devdata(master);
platform_set_drvdata(dev, sp);
/* copy in the plkatform data */
info = sp->info = dev->dev.platform_data;
/* setup spi bitbang adaptor */
sp->bitbang.master = spi_master_get(master);
sp->bitbang.master->bus_num = info->bus_num;
sp->bitbang.master->num_chipselect = info->num_chipselect;
sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
sp->bitbang.txrx_word[SPI_MODE_2] = s3c2410_spigpio_txrx_mode2;
sp->bitbang.txrx_word[SPI_MODE_3] = s3c2410_spigpio_txrx_mode3;
/* set state of spi pins, always assume that the clock is
* available, but do check the MOSI and MISO. */
s3c2410_gpio_setpin(info->pin_clk, 0);
s3c2410_gpio_cfgpin(info->pin_clk, S3C2410_GPIO_OUTPUT);
if (info->pin_mosi < S3C2410_GPH10) {
s3c2410_gpio_setpin(info->pin_mosi, 0);
s3c2410_gpio_cfgpin(info->pin_mosi, S3C2410_GPIO_OUTPUT);
}
if (info->pin_miso != S3C2410_GPA0 && info->pin_miso < S3C2410_GPH10)
s3c2410_gpio_cfgpin(info->pin_miso, S3C2410_GPIO_INPUT);
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
goto err_no_bitbang;
return 0;
err_no_bitbang:
spi_master_put(sp->bitbang.master);
err:
return ret;
}
static int s3c2410_spigpio_remove(struct platform_device *dev)
{
struct s3c2410_spigpio *sp = platform_get_drvdata(dev);
spi_bitbang_stop(&sp->bitbang);
spi_master_put(sp->bitbang.master);
return 0;
}
/* all gpio should be held over suspend/resume, so we should
* not need to deal with this
*/
#define s3c2410_spigpio_suspend NULL
#define s3c2410_spigpio_resume NULL
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:spi_s3c24xx_gpio");
static struct platform_driver s3c2410_spigpio_drv = {
.probe = s3c2410_spigpio_probe,
.remove = s3c2410_spigpio_remove,
.suspend = s3c2410_spigpio_suspend,
.resume = s3c2410_spigpio_resume,
.driver = {
.name = "spi_s3c24xx_gpio",
.owner = THIS_MODULE,
},
};
static int __init s3c2410_spigpio_init(void)
{
return platform_driver_register(&s3c2410_spigpio_drv);
}
static void __exit s3c2410_spigpio_exit(void)
{
platform_driver_unregister(&s3c2410_spigpio_drv);
}
module_init(s3c2410_spigpio_init);
module_exit(s3c2410_spigpio_exit);
MODULE_DESCRIPTION("S3C24XX SPI Driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,206 @@
/*
* SH SCI SPI interface
*
* Copyright (c) 2008 Magnus Damm
*
* Based on S3C24XX GPIO based SPI driver, which is:
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/spi.h>
#include <asm/io.h>
struct sh_sci_spi {
struct spi_bitbang bitbang;
void __iomem *membase;
unsigned char val;
struct sh_spi_info *info;
struct platform_device *dev;
};
#define SCSPTR(sp) (sp->membase + 0x1c)
#define PIN_SCK (1 << 2)
#define PIN_TXD (1 << 0)
#define PIN_RXD PIN_TXD
#define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD)
static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
{
/*
* We are the only user of SCSPTR so no locking is required.
* Reading bit 2 and 0 in SCSPTR gives pin state as input.
* Writing the same bits sets the output value.
* This makes regular read-modify-write difficult so we
* use sp->val to keep track of the latest register value.
*/
if (on)
sp->val |= bits;
else
sp->val &= ~bits;
iowrite8(sp->val, SCSPTR(sp));
}
static inline void setsck(struct spi_device *dev, int on)
{
setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
}
static inline void setmosi(struct spi_device *dev, int on)
{
setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
}
static inline u32 getmiso(struct spi_device *dev)
{
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
}
#define spidelay(x) ndelay(x)
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
}
static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
}
static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
if (sp->info && sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value);
}
static int sh_sci_spi_probe(struct platform_device *dev)
{
struct resource *r;
struct spi_master *master;
struct sh_sci_spi *sp;
int ret;
master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
if (master == NULL) {
dev_err(&dev->dev, "failed to allocate spi master\n");
ret = -ENOMEM;
goto err0;
}
sp = spi_master_get_devdata(master);
platform_set_drvdata(dev, sp);
sp->info = dev->dev.platform_data;
/* setup spi bitbang adaptor */
sp->bitbang.master = spi_master_get(master);
sp->bitbang.master->bus_num = sp->info->bus_num;
sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
sp->bitbang.chipselect = sh_sci_spi_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1;
sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2;
sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3;
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (r == NULL) {
ret = -ENOENT;
goto err1;
}
sp->membase = ioremap(r->start, r->end - r->start + 1);
if (!sp->membase) {
ret = -ENXIO;
goto err1;
}
sp->val = ioread8(SCSPTR(sp));
setbits(sp, PIN_INIT, 1);
ret = spi_bitbang_start(&sp->bitbang);
if (!ret)
return 0;
setbits(sp, PIN_INIT, 0);
iounmap(sp->membase);
err1:
spi_master_put(sp->bitbang.master);
err0:
return ret;
}
static int sh_sci_spi_remove(struct platform_device *dev)
{
struct sh_sci_spi *sp = platform_get_drvdata(dev);
iounmap(sp->membase);
setbits(sp, PIN_INIT, 0);
spi_bitbang_stop(&sp->bitbang);
spi_master_put(sp->bitbang.master);
return 0;
}
static struct platform_driver sh_sci_spi_drv = {
.probe = sh_sci_spi_probe,
.remove = sh_sci_spi_remove,
.driver = {
.name = "spi_sh_sci",
.owner = THIS_MODULE,
},
};
static int __init sh_sci_spi_init(void)
{
return platform_driver_register(&sh_sci_spi_drv);
}
module_init(sh_sci_spi_init);
static void __exit sh_sci_spi_exit(void)
{
platform_driver_unregister(&sh_sci_spi_drv);
}
module_exit(sh_sci_spi_exit);
MODULE_DESCRIPTION("SH SCI SPI Driver");
MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:spi_sh_sci");

View File

@@ -0,0 +1,563 @@
/*
* ------------------------------------------------------------------------
* spi_stm.c SPI/SSC driver for STMicroelectronics platforms
* ------------------------------------------------------------------------
*
* Copyright (c) 2008 STMicroelectronics Limited
* Author: Angus Clark <Angus.Clark@st.com>
*
* May be copied or modified under the terms of the GNU General Public
* License Version 2.0 only. See linux/COPYING for more information.
*
* ------------------------------------------------------------------------
* Changelog:
* 2008-01-24 (angus.clark@st.com)
* - Initial version
* 2008-08-28 (angus.clark@st.com)
* - Updates to fit with changes to 'ssc_pio_t'
* - SSC accesses now all 32-bit, for compatibility with 7141 Comms block
* - Updated to handle 7141 PIO ALT configuration
* - Support for user-defined, per-bus, chip_select function. Specified
* in board setup
* - Bug fix for rx_bytes_pending updates
*
* ------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/uaccess.h>
#include <linux/param.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/stm/platform.h>
#include <linux/stm/ssc.h>
#define NAME "spi-stm"
struct spi_stm {
/* SSC SPI Controller */
struct spi_bitbang bitbang;
void __iomem *base;
struct clk *clk;
struct platform_device *pdev;
/* Resources */
struct resource r_mem;
struct resource r_irq;
struct stm_pad_state *pad_state;
/* SSC SPI current transaction */
const u8 *tx_ptr;
u8 *rx_ptr;
u16 bits_per_word;
u16 bytes_per_word;
unsigned int baud;
unsigned int words_remaining;
struct completion done;
};
static void spi_stm_gpio_chipselect(struct spi_device *spi, int value)
{
unsigned int out;
if (spi->chip_select == (typeof(spi->chip_select))(STM_GPIO_INVALID))
return;
if (!spi->controller_data) {
if (gpio_request(spi->chip_select, "spi_stm cs")) {
dev_err(&spi->dev, "failed to allocate CS pin\n");
return;
}
spi->controller_data = (void *)1;
gpio_direction_output(spi->chip_select,
spi->mode & SPI_CS_HIGH);
}
if (value == BITBANG_CS_ACTIVE)
out = spi->mode & SPI_CS_HIGH ? 1 : 0;
else
out = spi->mode & SPI_CS_HIGH ? 0 : 1;
gpio_set_value(spi->chip_select, out);
dev_dbg(&spi->dev, "%s PIO%d[%d] -> %d \n",
value == BITBANG_CS_ACTIVE ? "select" : "deselect",
stm_gpio_port(spi->chip_select),
stm_gpio_pin(spi->chip_select), out);
return;
}
static int spi_stm_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct spi_stm *spi_stm;
u32 hz;
u8 bits_per_word;
u32 reg;
u32 sscbrg;
spi_stm = spi_master_get_devdata(spi->master);
bits_per_word = (t) ? t->bits_per_word : 0;
hz = (t) ? t->speed_hz : 0;
/* If not specified, use defaults */
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
if (!hz)
hz = spi->max_speed_hz;
/* Actually, can probably support 2-16 without any other change!!! */
if (bits_per_word != 8 && bits_per_word != 16) {
dev_err(&spi->dev, "unsupported bits_per_word=%d\n",
bits_per_word);
return -EINVAL;
}
spi_stm->bits_per_word = bits_per_word;
/* Set SSC_BRF */
sscbrg = clk_get_rate(spi_stm->clk) / (2*hz);
if (sscbrg < 0x07 || sscbrg > (0x1 << 16)) {
dev_err(&spi->dev, "baudrate outside valid range"
" %d (sscbrg = %d)\n", hz, sscbrg);
return -EINVAL;
}
spi_stm->baud = clk_get_rate(spi_stm->clk) / (2 * sscbrg);
if (sscbrg == (0x1 << 16)) /* 16-bit counter wraps */
sscbrg = 0x0;
ssc_store32(spi_stm, SSC_BRG, sscbrg);
dev_dbg(&spi->dev, "setting baudrate: target = %u hz, "
"actual = %u hz, sscbrg = %u\n",
hz, spi_stm->baud, sscbrg);
/* Set SSC_CTL and enable SSC */
reg = ssc_load32(spi_stm, SSC_CTL);
reg |= SSC_CTL_MS;
if (spi->mode & SPI_CPOL)
reg |= SSC_CTL_PO;
else
reg &= ~SSC_CTL_PO;
if (spi->mode & SPI_CPHA)
reg |= SSC_CTL_PH;
else
reg &= ~SSC_CTL_PH;
if ((spi->mode & SPI_LSB_FIRST) == 0)
reg |= SSC_CTL_HB;
else
reg &= ~SSC_CTL_HB;
if (spi->mode & SPI_LOOP)
reg |= SSC_CTL_LPB;
else
reg &= ~SSC_CTL_LPB;
reg &= 0xfffffff0;
reg |= (bits_per_word - 1);
reg |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO;
reg |= SSC_CTL_EN;
dev_dbg(&spi->dev, "ssc_ctl = 0x%04x\n", reg);
ssc_store32(spi_stm, SSC_CTL, reg);
/* Clear the status register */
ssc_load32(spi_stm, SSC_RBUF);
return 0;
}
static void spi_stm_cleanup(struct spi_device *spi)
{
if (spi->controller_data) {
gpio_free(spi->chip_select);
spi->controller_data = (void *)0;
}
}
/* the spi->mode bits understood by this driver: */
#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH)
static int spi_stm_setup(struct spi_device *spi)
{
struct spi_stm *spi_stm;
spi_stm = spi_master_get_devdata(spi->master);
if (spi->mode & ~MODEBITS) {
dev_err(&spi->dev, "unsupported mode bits %x\n",
spi->mode & ~MODEBITS);
return -EINVAL;
}
if (!spi->max_speed_hz) {
dev_err(&spi->dev, "max_speed_hz unspecified\n");
return -EINVAL;
}
if (!spi->bits_per_word)
spi->bits_per_word = 8;
return spi_stm_setup_transfer(spi, NULL);
}
/* Load the TX FIFO */
static void ssc_write_tx_fifo(struct spi_stm *spi_stm)
{
uint32_t count;
uint32_t word = 0;
int i;
if (spi_stm->words_remaining > 8)
count = 8;
else
count = spi_stm->words_remaining;
for (i = 0; i < count; i++) {
if (spi_stm->tx_ptr) {
if (spi_stm->bytes_per_word == 1) {
word = *spi_stm->tx_ptr++;
} else {
word = *spi_stm->tx_ptr++;
word = *spi_stm->tx_ptr++ | (word << 8);
}
}
ssc_store32(spi_stm, SSC_TBUF, word);
}
}
/* Read the RX FIFO */
static void ssc_read_rx_fifo(struct spi_stm *spi_stm)
{
uint32_t count;
uint32_t word = 0;
int i;
if (spi_stm->words_remaining > 8)
count = 8;
else
count = spi_stm->words_remaining;
for (i = 0; i < count; i++) {
word = ssc_load32(spi_stm, SSC_RBUF);
if (spi_stm->rx_ptr) {
if (spi_stm->bytes_per_word == 1) {
*spi_stm->rx_ptr++ = (uint8_t)word;
} else {
*spi_stm->rx_ptr++ = (word >> 8);
*spi_stm->rx_ptr++ = word & 0xff;
}
}
}
spi_stm->words_remaining -= count;
}
/* Interrupt fired when TX shift register becomes empty */
static irqreturn_t spi_stm_irq(int irq, void *dev_id)
{
struct spi_stm *spi_stm = (struct spi_stm *)dev_id;
/* Read RX FIFO */
ssc_read_rx_fifo(spi_stm);
/* Fill TX FIFO */
if (spi_stm->words_remaining) {
ssc_write_tx_fifo(spi_stm);
} else {
/* TX/RX complete */
ssc_store32(spi_stm, SSC_IEN, 0x0);
complete(&spi_stm->done);
}
return IRQ_HANDLED;
}
static int spi_stm_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct spi_stm *spi_stm;
uint32_t ctl = 0;
spi_stm = spi_master_get_devdata(spi->master);
/* Setup transfer */
spi_stm->tx_ptr = t->tx_buf;
spi_stm->rx_ptr = t->rx_buf;
if (spi_stm->bits_per_word > 8) {
/* Anything greater than 8 bits-per-word requires 2
* bytes-per-word in the RX/TX buffers */
spi_stm->bytes_per_word = 2;
spi_stm->words_remaining = t->len/2;
} else if (spi_stm->bits_per_word == 8 &&
((t->len & 0x1) == 0)) {
/* If transfer is even-length, and 8 bits-per-word, then
* implement as half-length 16 bits-per-word transfer */
spi_stm->bytes_per_word = 2;
spi_stm->words_remaining = t->len/2;
/* Set SSC_CTL to 16 bits-per-word */
ctl = ssc_load32(spi_stm, SSC_CTL);
ssc_store32(spi_stm, SSC_CTL, (ctl | 0xf));
ssc_load32(spi_stm, SSC_RBUF);
} else {
spi_stm->bytes_per_word = 1;
spi_stm->words_remaining = t->len;
}
INIT_COMPLETION(spi_stm->done);
/* Start transfer by writing to the TX FIFO */
ssc_write_tx_fifo(spi_stm);
ssc_store32(spi_stm, SSC_IEN, SSC_IEN_TEEN);
/* Wait for transfer to complete */
wait_for_completion(&spi_stm->done);
/* Restore SSC_CTL if necessary */
if (ctl)
ssc_store32(spi_stm, SSC_CTL, ctl);
return t->len;
}
static int __init spi_stm_probe(struct platform_device *pdev)
{
struct stm_plat_ssc_data *plat_data = pdev->dev.platform_data;
struct spi_master *master;
struct resource *res;
struct spi_stm *spi_stm;
u32 reg;
int status = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_stm));
if (!master) {
dev_err(&pdev->dev, "failed to allocate spi master\n");
status = -ENOMEM;
goto err0;
}
platform_set_drvdata(pdev, master);
spi_stm = spi_master_get_devdata(master);
spi_stm->bitbang.master = spi_master_get(master);
spi_stm->bitbang.setup_transfer = spi_stm_setup_transfer;
spi_stm->bitbang.txrx_bufs = spi_stm_txrx_bufs;
spi_stm->bitbang.master->setup = spi_stm_setup;
spi_stm->bitbang.master->cleanup = spi_stm_cleanup;
if (plat_data->spi_chipselect)
spi_stm->bitbang.chipselect = plat_data->spi_chipselect;
else
spi_stm->bitbang.chipselect = spi_stm_gpio_chipselect;
/* the spi->mode bits understood by this driver: */
master->mode_bits = MODEBITS;
/* chip_select field of spi_device is declared as u8 and therefore
* limits number of GPIOs that can be used as a CS line. Sorry. */
master->num_chipselect =
sizeof(((struct spi_device *)0)->chip_select) * 256;
master->bus_num = pdev->id;
init_completion(&spi_stm->done);
/* Get resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to find IOMEM resource\n");
status = -ENOENT;
goto err1;
}
spi_stm->r_mem = *res;
if (!request_mem_region(res->start,
res->end - res->start + 1, NAME)) {
dev_err(&pdev->dev, "request memory region failed [0x%x]\n",
res->start);
status = -EBUSY;
goto err1;
}
spi_stm->base = ioremap_nocache(res->start, res->end - res->start + 1);
if (!spi_stm->base) {
dev_err(&pdev->dev, "ioremap memory failed [0x%x]\n",
res->start);
status = -ENXIO;
goto err2;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "failed to find IRQ resource\n");
status = -ENOENT;
goto err3;
}
spi_stm->r_irq = *res;
if (request_irq(res->start, spi_stm_irq,
IRQF_DISABLED, dev_name(&pdev->dev), spi_stm)) {
dev_err(&pdev->dev, "irq request failed\n");
status = -EBUSY;
goto err3;
}
spi_stm->pad_state = stm_pad_claim(plat_data->pad_config,
dev_name(&pdev->dev));
if (!spi_stm->pad_state) {
dev_err(&pdev->dev, "pads request failed\n");
status = -EBUSY;
goto err4;
}
/* Disable I2C and Reset SSC */
ssc_store32(spi_stm, SSC_I2C, 0x0);
reg = ssc_load16(spi_stm, SSC_CTL);
reg |= SSC_CTL_SR;
ssc_store32(spi_stm, SSC_CTL, reg);
udelay(1);
reg = ssc_load32(spi_stm, SSC_CTL);
reg &= ~SSC_CTL_SR;
ssc_store32(spi_stm, SSC_CTL, reg);
/* Set SSC into slave mode before reconfiguring PIO pins */
reg = ssc_load32(spi_stm, SSC_CTL);
reg &= ~SSC_CTL_MS;
ssc_store32(spi_stm, SSC_CTL, reg);
spi_stm->clk = clk_get(&pdev->dev, "comms_clk");
if (!spi_stm->clk) {
dev_err(&pdev->dev, "Comms clock not found!\n");
goto err5;
}
clk_enable(spi_stm->clk);
/* Start "bitbang" worker */
status = spi_bitbang_start(&spi_stm->bitbang);
if (status) {
dev_err(&pdev->dev, "bitbang start failed [%d]\n", status);
goto err5;
}
dev_info(&pdev->dev, "registered SPI Bus %d\n", master->bus_num);
return status;
err5:
stm_pad_release(spi_stm->pad_state);
err4:
free_irq(spi_stm->r_irq.start, spi_stm);
err3:
iounmap(spi_stm->base);
err2:
release_mem_region(spi_stm->r_mem.start,
resource_size(&spi_stm->r_mem));
err1:
spi_master_put(spi_stm->bitbang.master);
platform_set_drvdata(pdev, NULL);
err0:
return status;
}
static int spi_stm_remove(struct platform_device *pdev)
{
struct spi_stm *spi_stm;
struct spi_master *master;
master = platform_get_drvdata(pdev);
spi_stm = spi_master_get_devdata(master);
spi_bitbang_stop(&spi_stm->bitbang);
clk_disable(spi_stm->clk);
stm_pad_release(spi_stm->pad_state);
free_irq(spi_stm->r_irq.start, spi_stm);
iounmap(spi_stm->base);
release_mem_region(spi_stm->r_mem.start,
resource_size(&spi_stm->r_mem));
spi_master_put(spi_stm->bitbang.master);
platform_set_drvdata(pdev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int spi_stm_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct spi_stm *spi_stm;
spi_stm = spi_master_get_devdata(master);
ssc_store32(spi_stm, SSC_IEN, 0);
clk_disable(spi_stm->clk);
return 0;
}
static int spi_stm_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct spi_stm *spi_stm;
spi_stm = spi_master_get_devdata(master);
clk_enable(spi_stm->clk);
return 0;
}
static struct dev_pm_ops spi_stm_pm = {
.suspend = spi_stm_suspend,
.resume = spi_stm_resume,
.freeze = spi_stm_suspend,
.restore = spi_stm_resume,
.runtime_suspend = spi_stm_suspend,
.runtime_resume = spi_stm_resume,
};
#else
static struct dev_pm_ops spi_stm_pm;
#endif
static struct platform_driver spi_stm_driver = {
.driver.name = NAME,
.driver.owner = THIS_MODULE,
.driver.pm = &spi_stm_pm,
.probe = spi_stm_probe,
.remove = spi_stm_remove,
};
static int __init spi_stm_init(void)
{
return platform_driver_register(&spi_stm_driver);
}
static void __exit spi_stm_exit(void)
{
platform_driver_unregister(&spi_stm_driver);
}
module_init(spi_stm_init);
module_exit(spi_stm_exit);
MODULE_AUTHOR("STMicroelectronics <www.st.com>");
MODULE_DESCRIPTION("STM SSC SPI driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,679 @@
/*
* Freescale STMP378X SPI master driver
*
* Author: dmitry pervushin <dimka@embeddedalley.com>
*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <mach/platform.h>
#include <mach/stmp3xxx.h>
#include <mach/dma.h>
#include <mach/regs-ssp.h>
#include <mach/regs-apbh.h>
/* 0 means DMA mode(recommended, default), !0 - PIO mode */
static int pio;
static int clock;
/* default timeout for busy waits is 2 seconds */
#define STMP_SPI_TIMEOUT (2 * HZ)
struct stmp_spi {
int id;
void * __iomem regs; /* vaddr of the control registers */
int irq, err_irq;
u32 dma;
struct stmp3xxx_dma_descriptor d;
u32 speed_khz;
u32 saved_timings;
u32 divider;
struct clk *clk;
struct device *master_dev;
struct work_struct work;
struct workqueue_struct *workqueue;
/* lock protects queue access */
spinlock_t lock;
struct list_head queue;
struct completion done;
};
#define busy_wait(cond) \
({ \
unsigned long end_jiffies = jiffies + STMP_SPI_TIMEOUT; \
bool succeeded = false; \
do { \
if (cond) { \
succeeded = true; \
break; \
} \
cpu_relax(); \
} while (time_before(end_jiffies, jiffies)); \
succeeded; \
})
/**
* stmp_spi_init_hw
* Initialize the SSP port
*/
static int stmp_spi_init_hw(struct stmp_spi *ss)
{
int err = 0;
void *pins = ss->master_dev->platform_data;
err = stmp3xxx_request_pin_group(pins, dev_name(ss->master_dev));
if (err)
goto out;
ss->clk = clk_get(NULL, "ssp");
if (IS_ERR(ss->clk)) {
err = PTR_ERR(ss->clk);
goto out_free_pins;
}
clk_enable(ss->clk);
stmp3xxx_reset_block(ss->regs, false);
stmp3xxx_dma_reset_channel(ss->dma);
return 0;
out_free_pins:
stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
out:
return err;
}
static void stmp_spi_release_hw(struct stmp_spi *ss)
{
void *pins = ss->master_dev->platform_data;
if (ss->clk && !IS_ERR(ss->clk)) {
clk_disable(ss->clk);
clk_put(ss->clk);
}
stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
}
static int stmp_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
u8 bits_per_word;
u32 hz;
struct stmp_spi *ss = spi_master_get_devdata(spi->master);
u16 rate;
bits_per_word = spi->bits_per_word;
if (t && t->bits_per_word)
bits_per_word = t->bits_per_word;
/*
* Calculate speed:
* - by default, use maximum speed from ssp clk
* - if device overrides it, use it
* - if transfer specifies other speed, use transfer's one
*/
hz = 1000 * ss->speed_khz / ss->divider;
if (spi->max_speed_hz)
hz = min(hz, spi->max_speed_hz);
if (t && t->speed_hz)
hz = min(hz, t->speed_hz);
if (hz == 0) {
dev_err(&spi->dev, "Cannot continue with zero clock\n");
return -EINVAL;
}
if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
return -EINVAL;
}
dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %uHz/%d = %uHz\n",
hz, ss->speed_khz, ss->divider,
ss->speed_khz * 1000 / ss->divider);
if (ss->speed_khz * 1000 / ss->divider < hz) {
dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
__func__, hz);
return -EINVAL;
}
rate = 1000 * ss->speed_khz/ss->divider/hz;
writel(BF(ss->divider, SSP_TIMING_CLOCK_DIVIDE) |
BF(rate - 1, SSP_TIMING_CLOCK_RATE),
HW_SSP_TIMING + ss->regs);
writel(BF(1 /* mode SPI */, SSP_CTRL1_SSP_MODE) |
BF(4 /* 8 bits */, SSP_CTRL1_WORD_LENGTH) |
((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0) |
(pio ? 0 : BM_SSP_CTRL1_DMA_ENABLE),
ss->regs + HW_SSP_CTRL1);
return 0;
}
static int stmp_spi_setup(struct spi_device *spi)
{
/* spi_setup() does basic checks,
* stmp_spi_setup_transfer() does more later
*/
if (spi->bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, spi->bits_per_word);
return -EINVAL;
}
return 0;
}
static inline u32 stmp_spi_cs(unsigned cs)
{
return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) |
((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0);
}
static int stmp_spi_txrx_dma(struct stmp_spi *ss, int cs,
unsigned char *buf, dma_addr_t dma_buf, int len,
int first, int last, bool write)
{
u32 c0 = 0;
dma_addr_t spi_buf_dma = dma_buf;
int status = 0;
enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
c0 |= (first ? BM_SSP_CTRL0_LOCK_CS : 0);
c0 |= (last ? BM_SSP_CTRL0_IGNORE_CRC : 0);
c0 |= (write ? 0 : BM_SSP_CTRL0_READ);
c0 |= BM_SSP_CTRL0_DATA_XFER;
c0 |= stmp_spi_cs(cs);
c0 |= BF(len, SSP_CTRL0_XFER_COUNT);
if (!dma_buf)
spi_buf_dma = dma_map_single(ss->master_dev, buf, len, dir);
ss->d.command->cmd =
BF(len, APBH_CHn_CMD_XFER_COUNT) |
BF(1, APBH_CHn_CMD_CMDWORDS) |
BM_APBH_CHn_CMD_WAIT4ENDCMD |
BM_APBH_CHn_CMD_IRQONCMPLT |
BF(write ? BV_APBH_CHn_CMD_COMMAND__DMA_READ :
BV_APBH_CHn_CMD_COMMAND__DMA_WRITE,
APBH_CHn_CMD_COMMAND);
ss->d.command->pio_words[0] = c0;
ss->d.command->buf_ptr = spi_buf_dma;
stmp3xxx_dma_reset_channel(ss->dma);
stmp3xxx_dma_clear_interrupt(ss->dma);
stmp3xxx_dma_enable_interrupt(ss->dma);
init_completion(&ss->done);
stmp3xxx_dma_go(ss->dma, &ss->d, 1);
wait_for_completion(&ss->done);
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN))
status = -ETIMEDOUT;
if (!dma_buf)
dma_unmap_single(ss->master_dev, spi_buf_dma, len, dir);
return status;
}
static inline void stmp_spi_enable(struct stmp_spi *ss)
{
stmp3xxx_setl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
stmp3xxx_clearl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
}
static inline void stmp_spi_disable(struct stmp_spi *ss)
{
stmp3xxx_clearl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
stmp3xxx_setl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
}
static int stmp_spi_txrx_pio(struct stmp_spi *ss, int cs,
unsigned char *buf, int len,
bool first, bool last, bool write)
{
if (first)
stmp_spi_enable(ss);
stmp3xxx_setl(stmp_spi_cs(cs), ss->regs + HW_SSP_CTRL0);
while (len--) {
if (last && len <= 0)
stmp_spi_disable(ss);
stmp3xxx_clearl(BM_SSP_CTRL0_XFER_COUNT,
ss->regs + HW_SSP_CTRL0);
stmp3xxx_setl(1, ss->regs + HW_SSP_CTRL0);
if (write)
stmp3xxx_clearl(BM_SSP_CTRL0_READ,
ss->regs + HW_SSP_CTRL0);
else
stmp3xxx_setl(BM_SSP_CTRL0_READ,
ss->regs + HW_SSP_CTRL0);
/* Run! */
stmp3xxx_setl(BM_SSP_CTRL0_RUN, ss->regs + HW_SSP_CTRL0);
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
BM_SSP_CTRL0_RUN))
break;
if (write)
writel(*buf, ss->regs + HW_SSP_DATA);
/* Set TRANSFER */
stmp3xxx_setl(BM_SSP_CTRL0_DATA_XFER, ss->regs + HW_SSP_CTRL0);
if (!write) {
if (busy_wait((readl(ss->regs + HW_SSP_STATUS) &
BM_SSP_STATUS_FIFO_EMPTY)))
break;
*buf = readl(ss->regs + HW_SSP_DATA) & 0xFF;
}
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
BM_SSP_CTRL0_RUN))
break;
/* advance to the next byte */
buf++;
}
return len < 0 ? 0 : -ETIMEDOUT;
}
static int stmp_spi_handle_message(struct stmp_spi *ss, struct spi_message *m)
{
bool first, last;
struct spi_transfer *t, *tmp_t;
int status = 0;
int cs;
cs = m->spi->chip_select;
list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
first = (&t->transfer_list == m->transfers.next);
last = (&t->transfer_list == m->transfers.prev);
if (first || t->speed_hz || t->bits_per_word)
stmp_spi_setup_transfer(m->spi, t);
/* reject "not last" transfers which request to change cs */
if (t->cs_change && !last) {
dev_err(&m->spi->dev,
"Message with t->cs_change has been skipped\n");
continue;
}
if (t->tx_buf) {
status = pio ?
stmp_spi_txrx_pio(ss, cs, (void *)t->tx_buf,
t->len, first, last, true) :
stmp_spi_txrx_dma(ss, cs, (void *)t->tx_buf,
t->tx_dma, t->len, first, last, true);
#ifdef DEBUG
if (t->len < 0x10)
print_hex_dump_bytes("Tx ",
DUMP_PREFIX_OFFSET,
t->tx_buf, t->len);
else
pr_debug("Tx: %d bytes\n", t->len);
#endif
}
if (t->rx_buf) {
status = pio ?
stmp_spi_txrx_pio(ss, cs, t->rx_buf,
t->len, first, last, false) :
stmp_spi_txrx_dma(ss, cs, t->rx_buf,
t->rx_dma, t->len, first, last, false);
#ifdef DEBUG
if (t->len < 0x10)
print_hex_dump_bytes("Rx ",
DUMP_PREFIX_OFFSET,
t->rx_buf, t->len);
else
pr_debug("Rx: %d bytes\n", t->len);
#endif
}
if (t->delay_usecs)
udelay(t->delay_usecs);
if (status)
break;
}
return status;
}
/**
* stmp_spi_handle - handle messages from the queue
*/
static void stmp_spi_handle(struct work_struct *w)
{
struct stmp_spi *ss = container_of(w, struct stmp_spi, work);
unsigned long flags;
struct spi_message *m;
spin_lock_irqsave(&ss->lock, flags);
while (!list_empty(&ss->queue)) {
m = list_entry(ss->queue.next, struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irqrestore(&ss->lock, flags);
m->status = stmp_spi_handle_message(ss, m);
m->complete(m->context);
spin_lock_irqsave(&ss->lock, flags);
}
spin_unlock_irqrestore(&ss->lock, flags);
return;
}
/**
* stmp_spi_transfer - perform message transfer.
* Called indirectly from spi_async, queues all the messages to
* spi_handle_message.
* @spi: spi device
* @m: message to be queued
*/
static int stmp_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct stmp_spi *ss = spi_master_get_devdata(spi->master);
unsigned long flags;
m->status = -EINPROGRESS;
spin_lock_irqsave(&ss->lock, flags);
list_add_tail(&m->queue, &ss->queue);
queue_work(ss->workqueue, &ss->work);
spin_unlock_irqrestore(&ss->lock, flags);
return 0;
}
static irqreturn_t stmp_spi_irq(int irq, void *dev_id)
{
struct stmp_spi *ss = dev_id;
stmp3xxx_dma_clear_interrupt(ss->dma);
complete(&ss->done);
return IRQ_HANDLED;
}
static irqreturn_t stmp_spi_irq_err(int irq, void *dev_id)
{
struct stmp_spi *ss = dev_id;
u32 c1, st;
c1 = readl(ss->regs + HW_SSP_CTRL1);
st = readl(ss->regs + HW_SSP_STATUS);
dev_err(ss->master_dev, "%s: status = 0x%08X, c1 = 0x%08X\n",
__func__, st, c1);
stmp3xxx_clearl(c1 & 0xCCCC0000, ss->regs + HW_SSP_CTRL1);
return IRQ_HANDLED;
}
static int __devinit stmp_spi_probe(struct platform_device *dev)
{
int err = 0;
struct spi_master *master;
struct stmp_spi *ss;
struct resource *r;
master = spi_alloc_master(&dev->dev, sizeof(struct stmp_spi));
if (master == NULL) {
err = -ENOMEM;
goto out0;
}
master->flags = SPI_MASTER_HALF_DUPLEX;
ss = spi_master_get_devdata(master);
platform_set_drvdata(dev, master);
/* Get resources(memory, IRQ) associated with the device */
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (r == NULL) {
err = -ENODEV;
goto out_put_master;
}
ss->regs = ioremap(r->start, resource_size(r));
if (!ss->regs) {
err = -EINVAL;
goto out_put_master;
}
ss->master_dev = &dev->dev;
ss->id = dev->id;
INIT_WORK(&ss->work, stmp_spi_handle);
INIT_LIST_HEAD(&ss->queue);
spin_lock_init(&ss->lock);
ss->workqueue = create_singlethread_workqueue(dev_name(&dev->dev));
if (!ss->workqueue) {
err = -ENXIO;
goto out_put_master;
}
master->transfer = stmp_spi_transfer;
master->setup = stmp_spi_setup;
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
ss->irq = platform_get_irq(dev, 0);
if (ss->irq < 0) {
err = ss->irq;
goto out_put_master;
}
ss->err_irq = platform_get_irq(dev, 1);
if (ss->err_irq < 0) {
err = ss->err_irq;
goto out_put_master;
}
r = platform_get_resource(dev, IORESOURCE_DMA, 0);
if (r == NULL) {
err = -ENODEV;
goto out_put_master;
}
ss->dma = r->start;
err = stmp3xxx_dma_request(ss->dma, &dev->dev, dev_name(&dev->dev));
if (err)
goto out_put_master;
err = stmp3xxx_dma_allocate_command(ss->dma, &ss->d);
if (err)
goto out_free_dma;
master->bus_num = dev->id;
master->num_chipselect = 1;
/* SPI controller initializations */
err = stmp_spi_init_hw(ss);
if (err) {
dev_dbg(&dev->dev, "cannot initialize hardware\n");
goto out_free_dma_desc;
}
if (clock) {
dev_info(&dev->dev, "clock rate forced to %d\n", clock);
clk_set_rate(ss->clk, clock);
}
ss->speed_khz = clk_get_rate(ss->clk);
ss->divider = 2;
dev_info(&dev->dev, "max possible speed %d = %ld/%d kHz\n",
ss->speed_khz, clk_get_rate(ss->clk), ss->divider);
/* Register for SPI interrupt */
err = request_irq(ss->irq, stmp_spi_irq, 0,
dev_name(&dev->dev), ss);
if (err) {
dev_dbg(&dev->dev, "request_irq failed, %d\n", err);
goto out_release_hw;
}
/* ..and shared interrupt for all SSP controllers */
err = request_irq(ss->err_irq, stmp_spi_irq_err, IRQF_SHARED,
dev_name(&dev->dev), ss);
if (err) {
dev_dbg(&dev->dev, "request_irq(error) failed, %d\n", err);
goto out_free_irq;
}
err = spi_register_master(master);
if (err) {
dev_dbg(&dev->dev, "cannot register spi master, %d\n", err);
goto out_free_irq_2;
}
dev_info(&dev->dev, "at (mapped) 0x%08X, irq=%d, bus %d, %s mode\n",
(u32)ss->regs, ss->irq, master->bus_num,
pio ? "PIO" : "DMA");
return 0;
out_free_irq_2:
free_irq(ss->err_irq, ss);
out_free_irq:
free_irq(ss->irq, ss);
out_free_dma_desc:
stmp3xxx_dma_free_command(ss->dma, &ss->d);
out_free_dma:
stmp3xxx_dma_release(ss->dma);
out_release_hw:
stmp_spi_release_hw(ss);
out_put_master:
if (ss->workqueue)
destroy_workqueue(ss->workqueue);
if (ss->regs)
iounmap(ss->regs);
platform_set_drvdata(dev, NULL);
spi_master_put(master);
out0:
return err;
}
static int __devexit stmp_spi_remove(struct platform_device *dev)
{
struct stmp_spi *ss;
struct spi_master *master;
master = platform_get_drvdata(dev);
if (master == NULL)
goto out0;
ss = spi_master_get_devdata(master);
spi_unregister_master(master);
free_irq(ss->err_irq, ss);
free_irq(ss->irq, ss);
stmp3xxx_dma_free_command(ss->dma, &ss->d);
stmp3xxx_dma_release(ss->dma);
stmp_spi_release_hw(ss);
destroy_workqueue(ss->workqueue);
iounmap(ss->regs);
spi_master_put(master);
platform_set_drvdata(dev, NULL);
out0:
return 0;
}
#ifdef CONFIG_PM
static int stmp_spi_suspend(struct platform_device *pdev, pm_message_t pmsg)
{
struct stmp_spi *ss;
struct spi_master *master;
master = platform_get_drvdata(pdev);
ss = spi_master_get_devdata(master);
ss->saved_timings = readl(HW_SSP_TIMING + ss->regs);
clk_disable(ss->clk);
return 0;
}
static int stmp_spi_resume(struct platform_device *pdev)
{
struct stmp_spi *ss;
struct spi_master *master;
master = platform_get_drvdata(pdev);
ss = spi_master_get_devdata(master);
clk_enable(ss->clk);
stmp3xxx_reset_block(ss->regs, false);
writel(ss->saved_timings, ss->regs + HW_SSP_TIMING);
return 0;
}
#else
#define stmp_spi_suspend NULL
#define stmp_spi_resume NULL
#endif
static struct platform_driver stmp_spi_driver = {
.probe = stmp_spi_probe,
.remove = __devexit_p(stmp_spi_remove),
.driver = {
.name = "stmp3xxx_ssp",
.owner = THIS_MODULE,
},
.suspend = stmp_spi_suspend,
.resume = stmp_spi_resume,
};
static int __init stmp_spi_init(void)
{
return platform_driver_register(&stmp_spi_driver);
}
static void __exit stmp_spi_exit(void)
{
platform_driver_unregister(&stmp_spi_driver);
}
module_init(stmp_spi_init);
module_exit(stmp_spi_exit);
module_param(pio, int, S_IRUGO);
module_param(clock, int, S_IRUGO);
MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com>");
MODULE_DESCRIPTION("STMP3xxx SPI/SSP driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,474 @@
/*
* spi_txx9.c - TXx9 SPI controller driver.
*
* Based on linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
* Copyright (C) 2000-2001 Toshiba Corporation
*
* 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
* terms of the GNU General Public License version 2. This program is
* licensed "as is" without any warranty of any kind, whether express
* or implied.
*
* Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
*
* Convert to generic SPI framework - Atsushi Nemoto (anemo@mba.ocn.ne.jp)
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/gpio.h>
#define SPI_FIFO_SIZE 4
#define SPI_MAX_DIVIDER 0xff /* Max. value for SPCR1.SER */
#define SPI_MIN_DIVIDER 1 /* Min. value for SPCR1.SER */
#define TXx9_SPMCR 0x00
#define TXx9_SPCR0 0x04
#define TXx9_SPCR1 0x08
#define TXx9_SPFS 0x0c
#define TXx9_SPSR 0x14
#define TXx9_SPDR 0x18
/* SPMCR : SPI Master Control */
#define TXx9_SPMCR_OPMODE 0xc0
#define TXx9_SPMCR_CONFIG 0x40
#define TXx9_SPMCR_ACTIVE 0x80
#define TXx9_SPMCR_SPSTP 0x02
#define TXx9_SPMCR_BCLR 0x01
/* SPCR0 : SPI Control 0 */
#define TXx9_SPCR0_TXIFL_MASK 0xc000
#define TXx9_SPCR0_RXIFL_MASK 0x3000
#define TXx9_SPCR0_SIDIE 0x0800
#define TXx9_SPCR0_SOEIE 0x0400
#define TXx9_SPCR0_RBSIE 0x0200
#define TXx9_SPCR0_TBSIE 0x0100
#define TXx9_SPCR0_IFSPSE 0x0010
#define TXx9_SPCR0_SBOS 0x0004
#define TXx9_SPCR0_SPHA 0x0002
#define TXx9_SPCR0_SPOL 0x0001
/* SPSR : SPI Status */
#define TXx9_SPSR_TBSI 0x8000
#define TXx9_SPSR_RBSI 0x4000
#define TXx9_SPSR_TBS_MASK 0x3800
#define TXx9_SPSR_RBS_MASK 0x0700
#define TXx9_SPSR_SPOE 0x0080
#define TXx9_SPSR_IFSD 0x0008
#define TXx9_SPSR_SIDLE 0x0004
#define TXx9_SPSR_STRDY 0x0002
#define TXx9_SPSR_SRRDY 0x0001
struct txx9spi {
struct workqueue_struct *workqueue;
struct work_struct work;
spinlock_t lock; /* protect 'queue' */
struct list_head queue;
wait_queue_head_t waitq;
void __iomem *membase;
int baseclk;
struct clk *clk;
u32 max_speed_hz, min_speed_hz;
int last_chipselect;
int last_chipselect_val;
};
static u32 txx9spi_rd(struct txx9spi *c, int reg)
{
return __raw_readl(c->membase + reg);
}
static void txx9spi_wr(struct txx9spi *c, u32 val, int reg)
{
__raw_writel(val, c->membase + reg);
}
static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
int on, unsigned int cs_delay)
{
int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
if (on) {
/* deselect the chip with cs_change hint in last transfer */
if (c->last_chipselect >= 0)
gpio_set_value(c->last_chipselect,
!c->last_chipselect_val);
c->last_chipselect = spi->chip_select;
c->last_chipselect_val = val;
} else {
c->last_chipselect = -1;
ndelay(cs_delay); /* CS Hold Time */
}
gpio_set_value(spi->chip_select, val);
ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
}
static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
u8 bits_per_word;
if (!spi->max_speed_hz
|| spi->max_speed_hz > c->max_speed_hz
|| spi->max_speed_hz < c->min_speed_hz)
return -EINVAL;
bits_per_word = spi->bits_per_word;
if (bits_per_word != 8 && bits_per_word != 16)
return -EINVAL;
if (gpio_direction_output(spi->chip_select,
!(spi->mode & SPI_CS_HIGH))) {
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
return -EINVAL;
}
/* deselect chip */
spin_lock(&c->lock);
txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
spin_unlock(&c->lock);
return 0;
}
static irqreturn_t txx9spi_interrupt(int irq, void *dev_id)
{
struct txx9spi *c = dev_id;
/* disable rx intr */
txx9spi_wr(c, txx9spi_rd(c, TXx9_SPCR0) & ~TXx9_SPCR0_RBSIE,
TXx9_SPCR0);
wake_up(&c->waitq);
return IRQ_HANDLED;
}
static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
{
struct spi_device *spi = m->spi;
struct spi_transfer *t;
unsigned int cs_delay;
unsigned int cs_change = 1;
int status = 0;
u32 mcr;
u32 prev_speed_hz = 0;
u8 prev_bits_per_word = 0;
/* CS setup/hold/recovery time in nsec */
cs_delay = 100 + (NSEC_PER_SEC / 2) / spi->max_speed_hz;
mcr = txx9spi_rd(c, TXx9_SPMCR);
if (unlikely((mcr & TXx9_SPMCR_OPMODE) == TXx9_SPMCR_ACTIVE)) {
dev_err(&spi->dev, "Bad mode.\n");
status = -EIO;
goto exit;
}
mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
/* enter config mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
txx9spi_wr(c, TXx9_SPCR0_SBOS
| ((spi->mode & SPI_CPOL) ? TXx9_SPCR0_SPOL : 0)
| ((spi->mode & SPI_CPHA) ? TXx9_SPCR0_SPHA : 0)
| 0x08,
TXx9_SPCR0);
list_for_each_entry (t, &m->transfers, transfer_list) {
const void *txbuf = t->tx_buf;
void *rxbuf = t->rx_buf;
u32 data;
unsigned int len = t->len;
unsigned int wsize;
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
bits_per_word = bits_per_word ? : 8;
wsize = bits_per_word >> 3; /* in bytes */
if (prev_speed_hz != speed_hz
|| prev_bits_per_word != bits_per_word) {
int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1;
n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER);
/* enter config mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR,
TXx9_SPMCR);
txx9spi_wr(c, (n << 8) | bits_per_word, TXx9_SPCR1);
/* enter active mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_ACTIVE, TXx9_SPMCR);
prev_speed_hz = speed_hz;
prev_bits_per_word = bits_per_word;
}
if (cs_change)
txx9spi_cs_func(spi, c, 1, cs_delay);
cs_change = t->cs_change;
while (len) {
unsigned int count = SPI_FIFO_SIZE;
int i;
u32 cr0;
if (len < count * wsize)
count = len / wsize;
/* now tx must be idle... */
while (!(txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_SIDLE))
cpu_relax();
cr0 = txx9spi_rd(c, TXx9_SPCR0);
cr0 &= ~TXx9_SPCR0_RXIFL_MASK;
cr0 |= (count - 1) << 12;
/* enable rx intr */
cr0 |= TXx9_SPCR0_RBSIE;
txx9spi_wr(c, cr0, TXx9_SPCR0);
/* send */
for (i = 0; i < count; i++) {
if (txbuf) {
data = (wsize == 1)
? *(const u8 *)txbuf
: *(const u16 *)txbuf;
txx9spi_wr(c, data, TXx9_SPDR);
txbuf += wsize;
} else
txx9spi_wr(c, 0, TXx9_SPDR);
}
/* wait all rx data */
wait_event(c->waitq,
txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_RBSI);
/* receive */
for (i = 0; i < count; i++) {
data = txx9spi_rd(c, TXx9_SPDR);
if (rxbuf) {
if (wsize == 1)
*(u8 *)rxbuf = data;
else
*(u16 *)rxbuf = data;
rxbuf += wsize;
}
}
len -= count * wsize;
}
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (!cs_change)
continue;
if (t->transfer_list.next == &m->transfers)
break;
/* sometimes a short mid-message deselect of the chip
* may be needed to terminate a mode or command
*/
txx9spi_cs_func(spi, c, 0, cs_delay);
}
exit:
m->status = status;
m->complete(m->context);
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
* be for this chip too.
*/
if (!(status == 0 && cs_change))
txx9spi_cs_func(spi, c, 0, cs_delay);
/* enter config mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
}
static void txx9spi_work(struct work_struct *work)
{
struct txx9spi *c = container_of(work, struct txx9spi, work);
unsigned long flags;
spin_lock_irqsave(&c->lock, flags);
while (!list_empty(&c->queue)) {
struct spi_message *m;
m = container_of(c->queue.next, struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irqrestore(&c->lock, flags);
txx9spi_work_one(c, m);
spin_lock_irqsave(&c->lock, flags);
}
spin_unlock_irqrestore(&c->lock, flags);
}
static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct spi_master *master = spi->master;
struct txx9spi *c = spi_master_get_devdata(master);
struct spi_transfer *t;
unsigned long flags;
m->actual_length = 0;
/* check each transfer's parameters */
list_for_each_entry (t, &m->transfers, transfer_list) {
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
bits_per_word = bits_per_word ? : 8;
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
if (bits_per_word != 8 && bits_per_word != 16)
return -EINVAL;
if (t->len & ((bits_per_word >> 3) - 1))
return -EINVAL;
if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
return -EINVAL;
}
spin_lock_irqsave(&c->lock, flags);
list_add_tail(&m->queue, &c->queue);
queue_work(c->workqueue, &c->work);
spin_unlock_irqrestore(&c->lock, flags);
return 0;
}
static int __init txx9spi_probe(struct platform_device *dev)
{
struct spi_master *master;
struct txx9spi *c;
struct resource *res;
int ret = -ENODEV;
u32 mcr;
int irq;
master = spi_alloc_master(&dev->dev, sizeof(*c));
if (!master)
return ret;
c = spi_master_get_devdata(master);
platform_set_drvdata(dev, master);
INIT_WORK(&c->work, txx9spi_work);
spin_lock_init(&c->lock);
INIT_LIST_HEAD(&c->queue);
init_waitqueue_head(&c->waitq);
c->clk = clk_get(&dev->dev, "spi-baseclk");
if (IS_ERR(c->clk)) {
ret = PTR_ERR(c->clk);
c->clk = NULL;
goto exit;
}
ret = clk_enable(c->clk);
if (ret) {
clk_put(c->clk);
c->clk = NULL;
goto exit;
}
c->baseclk = clk_get_rate(c->clk);
c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
goto exit_busy;
if (!devm_request_mem_region(&dev->dev,
res->start, res->end - res->start + 1,
"spi_txx9"))
goto exit_busy;
c->membase = devm_ioremap(&dev->dev,
res->start, res->end - res->start + 1);
if (!c->membase)
goto exit_busy;
/* enter config mode */
mcr = txx9spi_rd(c, TXx9_SPMCR);
mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
irq = platform_get_irq(dev, 0);
if (irq < 0)
goto exit_busy;
ret = devm_request_irq(&dev->dev, irq, txx9spi_interrupt, 0,
"spi_txx9", c);
if (ret)
goto exit;
c->workqueue = create_singlethread_workqueue(
dev_name(master->dev.parent));
if (!c->workqueue)
goto exit_busy;
c->last_chipselect = -1;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
(unsigned long long)res->start, irq,
(c->baseclk + 500000) / 1000000);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->bus_num = dev->id;
master->setup = txx9spi_setup;
master->transfer = txx9spi_transfer;
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
ret = spi_register_master(master);
if (ret)
goto exit;
return 0;
exit_busy:
ret = -EBUSY;
exit:
if (c->workqueue)
destroy_workqueue(c->workqueue);
if (c->clk) {
clk_disable(c->clk);
clk_put(c->clk);
}
platform_set_drvdata(dev, NULL);
spi_master_put(master);
return ret;
}
static int __exit txx9spi_remove(struct platform_device *dev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
struct txx9spi *c = spi_master_get_devdata(master);
spi_unregister_master(master);
platform_set_drvdata(dev, NULL);
destroy_workqueue(c->workqueue);
clk_disable(c->clk);
clk_put(c->clk);
spi_master_put(master);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:spi_txx9");
static struct platform_driver txx9spi_driver = {
.remove = __exit_p(txx9spi_remove),
.driver = {
.name = "spi_txx9",
.owner = THIS_MODULE,
},
};
static int __init txx9spi_init(void)
{
return platform_driver_probe(&txx9spi_driver, txx9spi_probe);
}
subsys_initcall(txx9spi_init);
static void __exit txx9spi_exit(void)
{
platform_driver_unregister(&txx9spi_driver);
}
module_exit(txx9spi_exit);
MODULE_DESCRIPTION("TXx9 SPI Driver");
MODULE_LICENSE("GPL");

691
kernel/drivers/spi/spidev.c Normal file
View File

@@ -0,0 +1,691 @@
/*
* spidev.c -- simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>
* Copyright (C) 2007 David Brownell (simplification, cleanup)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <asm/uaccess.h>
/*
* This supports acccess to SPI devices using normal userspace I/O calls.
* Note that while traditional UNIX/POSIX I/O semantics are half duplex,
* and often mask message boundaries, full SPI support requires full duplex
* transfers. There are several kinds of of internal message boundaries to
* handle chipselect management and other protocol options.
*
* SPI has a character major number assigned. We allocate minor numbers
* dynamically using a bitmask. You must use hotplug tools, such as udev
* (or mdev with busybox) to create and destroy the /dev/spidevB.C device
* nodes, since there is no fixed association of minor numbers with any
* particular SPI bus or device.
*/
#define SPIDEV_MAJOR 153 /* assigned */
#define N_SPI_MINORS 32 /* ... up to 256 */
static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
/* Bit masks for spi_device.mode management. Note that incorrect
* settings for some settings can cause *lots* of trouble for other
* devices on a shared bus:
*
* - CS_HIGH ... this device will be active when it shouldn't be
* - 3WIRE ... when active, it won't behave as it should
* - NO_CS ... there will be no explicit message boundaries; this
* is completely incompatible with the shared bus model
* - READY ... transfers may proceed when they shouldn't.
*
* REVISIT should changing those flags be privileged?
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY)
struct spidev_data {
dev_t devt;
spinlock_t spi_lock;
struct spi_device *spi;
struct list_head device_entry;
/* buffer is NULL unless this device is open (users > 0) */
struct mutex buf_lock;
unsigned users;
u8 *buffer;
};
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
static unsigned bufsiz = 4096;
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
/*-------------------------------------------------------------------------*/
/*
* We can't use the standard synchronous wrappers for file I/O; we
* need to protect against async removal of the underlying spi_device.
*/
static void spidev_complete(void *arg)
{
complete(arg);
}
static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = spidev_complete;
message->context = &done;
spin_lock_irq(&spidev->spi_lock);
if (spidev->spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spidev->spi, message);
spin_unlock_irq(&spidev->spi_lock);
if (status == 0) {
wait_for_completion(&done);
status = message->status;
if (status == 0)
status = message->actual_length;
}
return status;
}
static inline ssize_t
spidev_sync_write(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
.tx_buf = spidev->buffer,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spidev_sync(spidev, &m);
}
static inline ssize_t
spidev_sync_read(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
.rx_buf = spidev->buffer,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spidev_sync(spidev, &m);
}
/*-------------------------------------------------------------------------*/
/* Read-only message with current device setup */
static ssize_t
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
ssize_t status = 0;
/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;
spidev = filp->private_data;
mutex_lock(&spidev->buf_lock);
status = spidev_sync_read(spidev, count);
if (status > 0) {
unsigned long missing;
missing = copy_to_user(buf, spidev->buffer, status);
if (missing == status)
status = -EFAULT;
else
status = status - missing;
}
mutex_unlock(&spidev->buf_lock);
return status;
}
/* Write-only message with current device setup */
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
ssize_t status = 0;
unsigned long missing;
/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;
spidev = filp->private_data;
mutex_lock(&spidev->buf_lock);
missing = copy_from_user(spidev->buffer, buf, count);
if (missing == 0) {
status = spidev_sync_write(spidev, count);
} else
status = -EFAULT;
mutex_unlock(&spidev->buf_lock);
return status;
}
static int spidev_message(struct spidev_data *spidev,
struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{
struct spi_message msg;
struct spi_transfer *k_xfers;
struct spi_transfer *k_tmp;
struct spi_ioc_transfer *u_tmp;
unsigned n, total;
u8 *buf;
int status = -EFAULT;
spi_message_init(&msg);
k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
if (k_xfers == NULL)
return -ENOMEM;
/* Construct spi_message, copying any tx data to bounce buffer.
* We walk the array of user-provided transfers, using each one
* to initialize a kernel version of the same transfer.
*/
buf = spidev->buffer;
total = 0;
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
k_tmp->len = u_tmp->len;
total += k_tmp->len;
if (total > bufsiz) {
status = -EMSGSIZE;
goto done;
}
if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
(uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
if (copy_from_user(buf, (const u8 __user *)
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
#ifdef VERBOSE
dev_dbg(&spi->dev,
" xfer len %zd %s%s%s%dbits %u usec %uHz\n",
u_tmp->len,
u_tmp->rx_buf ? "rx " : "",
u_tmp->tx_buf ? "tx " : "",
u_tmp->cs_change ? "cs " : "",
u_tmp->bits_per_word ? : spi->bits_per_word,
u_tmp->delay_usecs,
u_tmp->speed_hz ? : spi->max_speed_hz);
#endif
spi_message_add_tail(k_tmp, &msg);
}
status = spidev_sync(spidev, &msg);
if (status < 0)
goto done;
/* copy any rx data out of bounce buffer */
buf = spidev->buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
if (__copy_to_user((u8 __user *)
(uintptr_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
}
buf += u_tmp->len;
}
status = total;
done:
kfree(k_xfers);
return status;
}
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int err = 0;
int retval = 0;
struct spidev_data *spidev;
struct spi_device *spi;
u32 tmp;
unsigned n_ioc;
struct spi_ioc_transfer *ioc;
/* Check type and command number */
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
return -ENOTTY;
/* Check access direction once here; don't repeat below.
* IOC_DIR is from the user perspective, while access_ok is
* from the kernel perspective; so they look reversed.
*/
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE,
(void __user *)arg, _IOC_SIZE(cmd));
if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ,
(void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
/* guard against device removal before, or while,
* we issue this ioctl.
*/
spidev = filp->private_data;
spin_lock_irq(&spidev->spi_lock);
spi = spi_dev_get(spidev->spi);
spin_unlock_irq(&spidev->spi_lock);
if (spi == NULL)
return -ESHUTDOWN;
/* use the buffer lock here for triple duty:
* - prevent I/O (from us) so calling spi_setup() is safe;
* - prevent concurrent SPI_IOC_WR_* from morphing
* data fields while SPI_IOC_RD_* reads them;
* - SPI_IOC_MESSAGE needs the buffer locked "normally".
*/
mutex_lock(&spidev->buf_lock);
switch (cmd) {
/* read requests */
case SPI_IOC_RD_MODE:
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
break;
/* write requests */
case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
break;
}
tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp)
spi->mode |= SPI_LSB_FIRST;
else
spi->mode &= ~SPI_LSB_FIRST;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "%csb first\n",
tmp ? 'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->bits_per_word;
spi->bits_per_word = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->bits_per_word = save;
else
dev_dbg(&spi->dev, "%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ:
retval = __get_user(tmp, (__u32 __user *)arg);
if (retval == 0) {
u32 save = spi->max_speed_hz;
spi->max_speed_hz = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->max_speed_hz = save;
else
dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
}
break;
default:
/* segmented and/or full-duplex I/O request */
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE) {
retval = -ENOTTY;
break;
}
tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
retval = -EINVAL;
break;
}
n_ioc = tmp / sizeof(struct spi_ioc_transfer);
if (n_ioc == 0)
break;
/* copy into scratch area */
ioc = kmalloc(tmp, GFP_KERNEL);
if (!ioc) {
retval = -ENOMEM;
break;
}
if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
kfree(ioc);
retval = -EFAULT;
break;
}
/* translate to spi_message, execute */
retval = spidev_message(spidev, ioc, n_ioc);
kfree(ioc);
break;
}
mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);
return retval;
}
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = -ENXIO;
lock_kernel();
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {
if (spidev->devt == inode->i_rdev) {
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) {
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM;
}
}
if (status == 0) {
spidev->users++;
filp->private_data = spidev;
nonseekable_open(inode, filp);
}
} else
pr_debug("spidev: nothing for minor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
unlock_kernel();
return status;
}
static int spidev_release(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = 0;
mutex_lock(&device_list_lock);
spidev = filp->private_data;
filp->private_data = NULL;
/* last close? */
spidev->users--;
if (!spidev->users) {
int dofree;
kfree(spidev->buffer);
spidev->buffer = NULL;
/* ... after we unbound from the underlying device? */
spin_lock_irq(&spidev->spi_lock);
dofree = (spidev->spi == NULL);
spin_unlock_irq(&spidev->spi_lock);
if (dofree)
kfree(spidev);
}
mutex_unlock(&device_list_lock);
return status;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage. It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.read = spidev_read,
.unlocked_ioctl = spidev_ioctl,
.open = spidev_open,
.release = spidev_release,
};
/*-------------------------------------------------------------------------*/
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status;
unsigned long minor;
/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
if (!spidev)
return -ENOMEM;
/* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
/* If we can allocate a minor number, hook up this device.
* Reusing minors is fine so long as udev or mdev is working.
*/
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
dev = device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num, spi->chip_select);
status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock);
if (status == 0)
spi_set_drvdata(spi, spidev);
else
kfree(spidev);
return status;
}
static int spidev_remove(struct spi_device *spi)
{
struct spidev_data *spidev = spi_get_drvdata(spi);
/* make sure ops on existing fds can abort cleanly */
spin_lock_irq(&spidev->spi_lock);
spidev->spi = NULL;
spi_set_drvdata(spi, NULL);
spin_unlock_irq(&spidev->spi_lock);
/* prevent new opens */
mutex_lock(&device_list_lock);
list_del(&spidev->device_entry);
device_destroy(spidev_class, spidev->devt);
clear_bit(MINOR(spidev->devt), minors);
if (spidev->users == 0)
kfree(spidev);
mutex_unlock(&device_list_lock);
return 0;
}
static struct spi_driver spidev_spi = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller. The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
int status;
/* Claim our 256 reserved device numbers. Then register a class
* that will key udev/mdev to add/remove /dev nodes. Last, register
* the driver which manages those device numbers.
*/
BUILD_BUG_ON(N_SPI_MINORS > 256);
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;
spidev_class = class_create(THIS_MODULE, "spidev");
if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
return PTR_ERR(spidev_class);
}
status = spi_register_driver(&spidev_spi);
if (status < 0) {
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi);
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
module_exit(spidev_exit);
MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:spidev");

View File

@@ -0,0 +1,332 @@
/*
* tle62x0.c -- support Infineon TLE62x0 driver chips
*
* Copyright (c) 2007 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/spi/tle62x0.h>
#define CMD_READ 0x00
#define CMD_SET 0xff
#define DIAG_NORMAL 0x03
#define DIAG_OVERLOAD 0x02
#define DIAG_OPEN 0x01
#define DIAG_SHORTGND 0x00
struct tle62x0_state {
struct spi_device *us;
struct mutex lock;
unsigned int nr_gpio;
unsigned int gpio_state;
unsigned char tx_buff[4];
unsigned char rx_buff[4];
};
static int to_gpio_num(struct device_attribute *attr);
static inline int tle62x0_write(struct tle62x0_state *st)
{
unsigned char *buff = st->tx_buff;
unsigned int gpio_state = st->gpio_state;
buff[0] = CMD_SET;
if (st->nr_gpio == 16) {
buff[1] = gpio_state >> 8;
buff[2] = gpio_state;
} else {
buff[1] = gpio_state;
}
dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
buff[0], buff[1], buff[2]);
return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
}
static inline int tle62x0_read(struct tle62x0_state *st)
{
unsigned char *txbuff = st->tx_buff;
struct spi_transfer xfer = {
.tx_buf = txbuff,
.rx_buf = st->rx_buff,
.len = (st->nr_gpio * 2) / 8,
};
struct spi_message msg;
txbuff[0] = CMD_READ;
txbuff[1] = 0x00;
txbuff[2] = 0x00;
txbuff[3] = 0x00;
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
return spi_sync(st->us, &msg);
}
static unsigned char *decode_fault(unsigned int fault_code)
{
fault_code &= 3;
switch (fault_code) {
case DIAG_NORMAL:
return "N";
case DIAG_OVERLOAD:
return "V";
case DIAG_OPEN:
return "O";
case DIAG_SHORTGND:
return "G";
}
return "?";
}
static ssize_t tle62x0_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tle62x0_state *st = dev_get_drvdata(dev);
char *bp = buf;
unsigned char *buff = st->rx_buff;
unsigned long fault = 0;
int ptr;
int ret;
mutex_lock(&st->lock);
ret = tle62x0_read(st);
dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
fault <<= 8;
fault |= ((unsigned long)buff[ptr]);
dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]);
}
for (ptr = 0; ptr < st->nr_gpio; ptr++) {
bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2)));
}
*bp++ = '\n';
mutex_unlock(&st->lock);
return bp - buf;
}
static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL);
static ssize_t tle62x0_gpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tle62x0_state *st = dev_get_drvdata(dev);
int gpio_num = to_gpio_num(attr);
int value;
mutex_lock(&st->lock);
value = (st->gpio_state >> gpio_num) & 1;
mutex_unlock(&st->lock);
return snprintf(buf, PAGE_SIZE, "%d", value);
}
static ssize_t tle62x0_gpio_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct tle62x0_state *st = dev_get_drvdata(dev);
int gpio_num = to_gpio_num(attr);
unsigned long val;
char *endp;
val = simple_strtoul(buf, &endp, 0);
if (buf == endp)
return -EINVAL;
dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val);
mutex_lock(&st->lock);
if (val)
st->gpio_state |= 1 << gpio_num;
else
st->gpio_state &= ~(1 << gpio_num);
tle62x0_write(st);
mutex_unlock(&st->lock);
return len;
}
static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO,
tle62x0_gpio_show, tle62x0_gpio_store);
static struct device_attribute *gpio_attrs[] = {
[0] = &dev_attr_gpio1,
[1] = &dev_attr_gpio2,
[2] = &dev_attr_gpio3,
[3] = &dev_attr_gpio4,
[4] = &dev_attr_gpio5,
[5] = &dev_attr_gpio6,
[6] = &dev_attr_gpio7,
[7] = &dev_attr_gpio8,
[8] = &dev_attr_gpio9,
[9] = &dev_attr_gpio10,
[10] = &dev_attr_gpio11,
[11] = &dev_attr_gpio12,
[12] = &dev_attr_gpio13,
[13] = &dev_attr_gpio14,
[14] = &dev_attr_gpio15,
[15] = &dev_attr_gpio16
};
static int to_gpio_num(struct device_attribute *attr)
{
int ptr;
for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) {
if (gpio_attrs[ptr] == attr)
return ptr;
}
return -1;
}
static int __devinit tle62x0_probe(struct spi_device *spi)
{
struct tle62x0_state *st;
struct tle62x0_pdata *pdata;
int ptr;
int ret;
pdata = spi->dev.platform_data;
if (pdata == NULL) {
dev_err(&spi->dev, "no device data specified\n");
return -EINVAL;
}
st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL);
if (st == NULL) {
dev_err(&spi->dev, "no memory for device state\n");
return -ENOMEM;
}
st->us = spi;
st->nr_gpio = pdata->gpio_count;
st->gpio_state = pdata->init_state;
mutex_init(&st->lock);
ret = device_create_file(&spi->dev, &dev_attr_status_show);
if (ret) {
dev_err(&spi->dev, "cannot create status attribute\n");
goto err_status;
}
for (ptr = 0; ptr < pdata->gpio_count; ptr++) {
ret = device_create_file(&spi->dev, gpio_attrs[ptr]);
if (ret) {
dev_err(&spi->dev, "cannot create gpio attribute\n");
goto err_gpios;
}
}
/* tle62x0_write(st); */
spi_set_drvdata(spi, st);
return 0;
err_gpios:
for (; ptr > 0; ptr--)
device_remove_file(&spi->dev, gpio_attrs[ptr]);
device_remove_file(&spi->dev, &dev_attr_status_show);
err_status:
kfree(st);
return ret;
}
static int __devexit tle62x0_remove(struct spi_device *spi)
{
struct tle62x0_state *st = spi_get_drvdata(spi);
int ptr;
for (ptr = 0; ptr < st->nr_gpio; ptr++)
device_remove_file(&spi->dev, gpio_attrs[ptr]);
kfree(st);
return 0;
}
static struct spi_driver tle62x0_driver = {
.driver = {
.name = "tle62x0",
.owner = THIS_MODULE,
},
.probe = tle62x0_probe,
.remove = __devexit_p(tle62x0_remove),
};
static __init int tle62x0_init(void)
{
return spi_register_driver(&tle62x0_driver);
}
static __exit void tle62x0_exit(void)
{
spi_unregister_driver(&tle62x0_driver);
}
module_init(tle62x0_init);
module_exit(tle62x0_exit);
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("TLE62x0 SPI driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:tle62x0");

View File

@@ -0,0 +1,456 @@
/*
* xilinx_spi.c
*
* Xilinx SPI controller driver (master mode only)
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
* terms of the GNU General Public License version 2. This program is licensed
* "as is" without any warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_spi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/io.h>
#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* Product Specification", DS464
*/
#define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */
#define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04
#define XSPI_CR_CPOL 0x08
#define XSPI_CR_CPHA 0x10
#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL)
#define XSPI_CR_TXFIFO_RESET 0x20
#define XSPI_CR_RXFIFO_RESET 0x40
#define XSPI_CR_MANUAL_SSELECT 0x80
#define XSPI_CR_TRANS_INHIBIT 0x100
#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */
#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
#define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */
#define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */
#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
* IPIF registers are 32 bit
*/
#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */
#define XIPIF_V123B_GINTR_ENABLE 0x80000000
#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */
#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */
#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */
#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while
* disabled */
#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */
#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
struct xilinx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
void __iomem *regs; /* virt. address of the control registers */
u32 irq;
u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
};
static void xspi_init_hw(void __iomem *regs_base)
{
/* Reset the SPI device */
out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
XIPIF_V123B_RESET_MASK);
/* Disable all the interrupts just in case */
out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
/* Enable the global IPIF interrupt */
out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
XIPIF_V123B_GINTR_ENABLE);
/* Deselect the slave on the SPI bus */
out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
/* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */
out_be16(regs_base + XSPI_CR_OFFSET,
XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
| XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
}
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
if (is_on == BITBANG_CS_INACTIVE) {
/* Deselect the slave on the SPI bus */
out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
} else if (is_on == BITBANG_CS_ACTIVE) {
/* Set the SPI clock phase and polarity */
u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
& ~XSPI_CR_MODE_MASK;
if (spi->mode & SPI_CPHA)
cr |= XSPI_CR_CPHA;
if (spi->mode & SPI_CPOL)
cr |= XSPI_CR_CPOL;
out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
* parameter)
*/
/* Activate the chip select */
out_be32(xspi->regs + XSPI_SSR_OFFSET,
~(0x0001 << spi->chip_select));
}
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
* custom txrx_bufs(). We have nothing to setup here as the SPI IP block
* supports just 8 bits per word, and SPI clock can't be changed in software.
* Check for 8 bits per word. Chip select delay calculations could be
* added here as soon as bitbang_work() can be made aware of the delay value.
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
u8 bits_per_word;
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
return -EINVAL;
}
return 0;
}
static int xilinx_spi_setup(struct spi_device *spi)
{
struct spi_bitbang *bitbang;
struct xilinx_spi *xspi;
int retval;
xspi = spi_master_get_devdata(spi->master);
bitbang = &xspi->bitbang;
retval = xilinx_spi_setup_transfer(spi, NULL);
if (retval < 0)
return retval;
return 0;
}
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
{
u8 sr;
/* Fill the Tx FIFO with as many bytes as possible */
sr = in_8(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
if (xspi->tx_ptr) {
out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
} else {
out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
}
xspi->remaining_bytes--;
sr = in_8(xspi->regs + XSPI_SR_OFFSET);
}
}
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u32 ipif_ier;
u16 cr;
/* We get here with transmitter inhibited */
xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf;
xspi->remaining_bytes = t->len;
INIT_COMPLETION(xspi->done);
xilinx_spi_fill_tx_fifo(xspi);
/* Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
ipif_ier | XSPI_INTR_TX_EMPTY);
/* Start the transfer by not inhibiting the transmitter any longer */
cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
wait_for_completion(&xspi->done);
/* Disable the transmit empty interrupt */
out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
return t->len - xspi->remaining_bytes;
}
/* This driver supports single master mode only. Hence Tx FIFO Empty
* is the only interrupt we care about.
* Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
* Fault are not to happen.
*/
static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
{
struct xilinx_spi *xspi = dev_id;
u32 ipif_isr;
/* Get the IPIF interrupts, and clear them immediately */
ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
u16 cr;
u8 sr;
/* A transmit has just completed. Process received data and
* check for more data to transmit. Always inhibit the
* transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done.
*/
cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
out_be16(xspi->regs + XSPI_CR_OFFSET,
cr | XSPI_CR_TRANS_INHIBIT);
/* Read out all the data from the Rx FIFO */
sr = in_8(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
u8 data;
data = in_8(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr++ = data;
}
sr = in_8(xspi->regs + XSPI_SR_OFFSET);
}
/* See if there is more data to send */
if (xspi->remaining_bytes > 0) {
xilinx_spi_fill_tx_fifo(xspi);
/* Start the transfer by not inhibiting the
* transmitter any longer
*/
out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
} else {
/* No more data to send.
* Indicate the transfer is completed.
*/
complete(&xspi->done);
}
}
return IRQ_HANDLED;
}
static int __init xilinx_spi_of_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct spi_master *master;
struct xilinx_spi *xspi;
struct resource r_irq_struct;
struct resource r_mem_struct;
struct resource *r_irq = &r_irq_struct;
struct resource *r_mem = &r_mem_struct;
int rc = 0;
const u32 *prop;
int len;
/* Get resources(memory, IRQ) associated with the device */
master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
if (master == NULL) {
return -ENOMEM;
}
dev_set_drvdata(&ofdev->dev, master);
rc = of_address_to_resource(ofdev->node, 0, r_mem);
if (rc) {
dev_warn(&ofdev->dev, "invalid address\n");
goto put_master;
}
rc = of_irq_to_resource(ofdev->node, 0, r_irq);
if (rc == NO_IRQ) {
dev_warn(&ofdev->dev, "no IRQ found\n");
goto put_master;
}
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
xspi = spi_master_get_devdata(master);
xspi->bitbang.master = spi_master_get(master);
xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
xspi->irq = r_irq->start;
if (!request_mem_region(r_mem->start,
r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
rc = -ENXIO;
dev_warn(&ofdev->dev, "memory request failure\n");
goto put_master;
}
xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
if (xspi->regs == NULL) {
rc = -ENOMEM;
dev_warn(&ofdev->dev, "ioremap failure\n");
goto release_mem;
}
xspi->irq = r_irq->start;
/* dynamic bus assignment */
master->bus_num = -1;
/* number of slave select bits is required */
prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
if (!prop || len < sizeof(*prop)) {
dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
goto unmap_io;
}
master->num_chipselect = *prop;
/* SPI controller initializations */
xspi_init_hw(xspi->regs);
/* Register for SPI Interrupt */
rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
if (rc != 0) {
dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
goto unmap_io;
}
rc = spi_bitbang_start(&xspi->bitbang);
if (rc != 0) {
dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
goto free_irq;
}
dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
(unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
/* Add any subnodes on the SPI bus */
of_register_spi_devices(master, ofdev->node);
return rc;
free_irq:
free_irq(xspi->irq, xspi);
unmap_io:
iounmap(xspi->regs);
release_mem:
release_mem_region(r_mem->start, resource_size(r_mem));
put_master:
spi_master_put(master);
return rc;
}
static int __devexit xilinx_spi_remove(struct of_device *ofdev)
{
struct xilinx_spi *xspi;
struct spi_master *master;
struct resource r_mem;
master = platform_get_drvdata(ofdev);
xspi = spi_master_get_devdata(master);
spi_bitbang_stop(&xspi->bitbang);
free_irq(xspi->irq, xspi);
iounmap(xspi->regs);
if (!of_address_to_resource(ofdev->node, 0, &r_mem))
release_mem_region(r_mem.start, resource_size(&r_mem));
dev_set_drvdata(&ofdev->dev, 0);
spi_master_put(xspi->bitbang.master);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
static int __exit xilinx_spi_of_remove(struct of_device *op)
{
return xilinx_spi_remove(op);
}
static struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
{}
};
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
static struct of_platform_driver xilinx_spi_of_driver = {
.owner = THIS_MODULE,
.name = "xilinx-xps-spi",
.match_table = xilinx_spi_of_match,
.probe = xilinx_spi_of_probe,
.remove = __exit_p(xilinx_spi_of_remove),
.driver = {
.name = "xilinx-xps-spi",
.owner = THIS_MODULE,
},
};
static int __init xilinx_spi_init(void)
{
return of_register_platform_driver(&xilinx_spi_of_driver);
}
module_init(xilinx_spi_init);
static void __exit xilinx_spi_exit(void)
{
of_unregister_platform_driver(&xilinx_spi_of_driver);
}
module_exit(xilinx_spi_exit);
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION("Xilinx SPI driver");
MODULE_LICENSE("GPL");