mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-05 01:54:09 +08:00
ee2b805c8e
The definition of the SPI clock phase for the Motorola mode of the PL022 driver was incorrect: the spec had been interpreted as data being recieved on rising or falling edge of the clocks while the correct interpretation is that data can be recieved on the first or second edge transition, falling or rising depending on the polarity setting. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
125 lines
3.5 KiB
C
125 lines
3.5 KiB
C
/*
|
|
* arch/arm/mach-u300/spi.c
|
|
*
|
|
* Copyright (C) 2009 ST-Ericsson AB
|
|
* License terms: GNU General Public License (GPL) version 2
|
|
*
|
|
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
|
*/
|
|
#include <linux/device.h>
|
|
#include <linux/amba/bus.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/amba/pl022.h>
|
|
#include <linux/err.h>
|
|
#include "padmux.h"
|
|
|
|
/*
|
|
* The following is for the actual devices on the SSP/SPI bus
|
|
*/
|
|
#ifdef CONFIG_MACH_U300_SPIDUMMY
|
|
static void select_dummy_chip(u32 chipselect)
|
|
{
|
|
pr_debug("CORE: %s called with CS=0x%x (%s)\n",
|
|
__func__,
|
|
chipselect,
|
|
chipselect ? "unselect chip" : "select chip");
|
|
/*
|
|
* Here you would write the chip select value to the GPIO pins if
|
|
* this was a real chip (but this is a loopback dummy).
|
|
*/
|
|
}
|
|
|
|
struct pl022_config_chip dummy_chip_info = {
|
|
/* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */
|
|
.lbm = LOOPBACK_ENABLED,
|
|
/*
|
|
* available POLLING_TRANSFER and INTERRUPT_TRANSFER,
|
|
* DMA_TRANSFER does not work
|
|
*/
|
|
.com_mode = INTERRUPT_TRANSFER,
|
|
.iface = SSP_INTERFACE_MOTOROLA_SPI,
|
|
/* We can only act as master but SSP_SLAVE is possible in theory */
|
|
.hierarchy = SSP_MASTER,
|
|
/* 0 = drive TX even as slave, 1 = do not drive TX as slave */
|
|
.slave_tx_disable = 0,
|
|
/* LSB first */
|
|
.endian_tx = SSP_TX_LSB,
|
|
.endian_rx = SSP_RX_LSB,
|
|
.data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */
|
|
.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
|
|
.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
|
|
.clk_phase = SSP_CLK_SECOND_EDGE,
|
|
.clk_pol = SSP_CLK_POL_IDLE_LOW,
|
|
.ctrl_len = SSP_BITS_12,
|
|
.wait_state = SSP_MWIRE_WAIT_ZERO,
|
|
.duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
|
|
/*
|
|
* This is where you insert a call to a function to enable CS
|
|
* (usually GPIO) for a certain chip.
|
|
*/
|
|
.cs_control = select_dummy_chip,
|
|
};
|
|
#endif
|
|
|
|
static struct spi_board_info u300_spi_devices[] = {
|
|
#ifdef CONFIG_MACH_U300_SPIDUMMY
|
|
{
|
|
/* A dummy chip used for loopback tests */
|
|
.modalias = "spi-dummy",
|
|
/* Really dummy, pass in additional chip config here */
|
|
.platform_data = NULL,
|
|
/* This defines how the controller shall handle the device */
|
|
.controller_data = &dummy_chip_info,
|
|
/* .irq - no external IRQ routed from this device */
|
|
.max_speed_hz = 1000000,
|
|
.bus_num = 0, /* Only one bus on this chip */
|
|
.chip_select = 0,
|
|
/* Means SPI_CS_HIGH, change if e.g low CS */
|
|
.mode = 0,
|
|
},
|
|
#endif
|
|
};
|
|
|
|
static struct pl022_ssp_controller ssp_platform_data = {
|
|
/* If you have several SPI buses this varies, we have only bus 0 */
|
|
.bus_id = 0,
|
|
/* Set this to 1 when we think we got DMA working */
|
|
.enable_dma = 0,
|
|
/*
|
|
* On the APP CPU GPIO 4, 5 and 6 are connected as generic
|
|
* chip selects for SPI. (Same on U330, U335 and U365.)
|
|
* TODO: make sure the GPIO driver can select these properly
|
|
* and do padmuxing accordingly too.
|
|
*/
|
|
.num_chipselect = 3,
|
|
};
|
|
|
|
|
|
void __init u300_spi_init(struct amba_device *adev)
|
|
{
|
|
struct pmx *pmx;
|
|
|
|
adev->dev.platform_data = &ssp_platform_data;
|
|
/*
|
|
* Setup padmuxing for SPI. Since this must always be
|
|
* compiled into the kernel, pmx is never released.
|
|
*/
|
|
pmx = pmx_get(&adev->dev, U300_APP_PMX_SPI_SETTING);
|
|
|
|
if (IS_ERR(pmx))
|
|
dev_warn(&adev->dev, "Could not get padmux handle\n");
|
|
else {
|
|
int ret;
|
|
|
|
ret = pmx_activate(&adev->dev, pmx);
|
|
if (IS_ERR_VALUE(ret))
|
|
dev_warn(&adev->dev, "Could not activate padmuxing\n");
|
|
}
|
|
|
|
}
|
|
void __init u300_spi_register_board_devices(void)
|
|
{
|
|
/* Register any SPI devices */
|
|
spi_register_board_info(u300_spi_devices, ARRAY_SIZE(u300_spi_devices));
|
|
}
|