spi/pl022: Add spi->mode support to AMBA SPI driver

This patch adds spi->mode support for the AMBA pl022 driver and
allows spidev to correctly alter SPI modes. Unused fields used in
the pl022 header file for the pl022_config_chip have been removed.

The ab8500 client driver selects the data transfer size instead
of the platform data.

For platforms that use the amba pl022 driver, the unused fields
in the controller data structure have been removed and the .mode
field in the SPI board info structure is used instead.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
Tested-by: Linus Walleij <linus.walleij@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
Kevin Wells 2010-09-16 06:18:50 -07:00 committed by Grant Likely
parent fadcf49b9b
commit bde435a9ca
7 changed files with 63 additions and 99 deletions

View File

@ -172,18 +172,12 @@ static void phy3250_spi_cs_set(u32 control)
}
static struct pl022_config_chip spi0_chip_info = {
.lbm = LOOPBACK_DISABLED,
.com_mode = INTERRUPT_TRANSFER,
.iface = SSP_INTERFACE_MOTOROLA_SPI,
.hierarchy = SSP_MASTER,
.slave_tx_disable = 0,
.endian_tx = SSP_TX_LSB,
.endian_rx = SSP_RX_LSB,
.data_size = SSP_DATA_BITS_8,
.rx_lev_trig = SSP_RX_4_OR_MORE_ELEM,
.tx_lev_trig = SSP_TX_4_OR_MORE_EMPTY_LOC,
.clk_phase = SSP_CLK_FIRST_EDGE,
.clk_pol = SSP_CLK_POL_IDLE_LOW,
.ctrl_len = SSP_BITS_8,
.wait_state = SSP_MWIRE_WAIT_ZERO,
.duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@ -239,6 +233,7 @@ static int __init phy3250_spi_board_register(void)
.max_speed_hz = 5000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
.platform_data = &eeprom,
.controller_data = &spi0_chip_info,
},

View File

@ -46,7 +46,6 @@ static ssize_t dummy_looptest(struct device *dev,
* struct, this is just used here to alter the behaviour of the chip
* in order to perform tests.
*/
struct pl022_config_chip *chip_info = spi->controller_data;
int status;
u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD,
0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05,
@ -72,7 +71,7 @@ static ssize_t dummy_looptest(struct device *dev,
* Force chip to 8 bit mode
* WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
*/
chip_info->data_size = SSP_DATA_BITS_8;
spi->bits_per_word = 8;
/* You should NOT DO THIS EITHER */
spi->master->setup(spi);
@ -159,7 +158,7 @@ static ssize_t dummy_looptest(struct device *dev,
* Force chip to 16 bit mode
* WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
*/
chip_info->data_size = SSP_DATA_BITS_16;
spi->bits_per_word = 16;
/* You should NOT DO THIS EITHER */
spi->master->setup(spi);

View File

@ -30,8 +30,6 @@ static void select_dummy_chip(u32 chipselect)
}
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
@ -42,14 +40,8 @@ struct pl022_config_chip dummy_chip_info = {
.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,
@ -75,7 +67,7 @@ static struct spi_board_info u300_spi_devices[] = {
.bus_num = 0, /* Only one bus on this chip */
.chip_select = 0,
/* Means SPI_CS_HIGH, change if e.g low CS */
.mode = 0,
.mode = SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP,
},
#endif
};

View File

@ -55,19 +55,13 @@ static void ab4500_spi_cs_control(u32 command)
}
struct pl022_config_chip ab4500_chip_info = {
.lbm = LOOPBACK_DISABLED,
.com_mode = INTERRUPT_TRANSFER,
.iface = SSP_INTERFACE_MOTOROLA_SPI,
/* we can act as master only */
.hierarchy = SSP_MASTER,
.slave_tx_disable = 0,
.endian_rx = SSP_RX_MSB,
.endian_tx = SSP_TX_MSB,
.data_size = SSP_DATA_BITS_24,
.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_HIGH,
.cs_control = ab4500_spi_cs_control,
};
@ -83,7 +77,7 @@ static struct spi_board_info u8500_spi_devices[] = {
.max_speed_hz = 12000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
.mode = SPI_MODE_3,
.irq = IRQ_DB8500_AB8500,
},
};

View File

@ -83,6 +83,11 @@ static int __devinit ab8500_spi_probe(struct spi_device *spi)
struct ab8500 *ab8500;
int ret;
spi->bits_per_word = 24;
ret = spi_setup(spi);
if (ret < 0)
return ret;
ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
if (!ab8500)
return -ENOMEM;

View File

@ -1595,12 +1595,6 @@ static int destroy_queue(struct pl022 *pl022)
static int verify_controller_parameters(struct pl022 *pl022,
struct pl022_config_chip *chip_info)
{
if ((chip_info->lbm != LOOPBACK_ENABLED)
&& (chip_info->lbm != LOOPBACK_DISABLED)) {
dev_err(chip_info->dev,
"loopback Mode is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI)
|| (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) {
dev_err(chip_info->dev,
@ -1626,24 +1620,6 @@ static int verify_controller_parameters(struct pl022 *pl022,
"cpsdvsr is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->endian_rx != SSP_RX_MSB)
&& (chip_info->endian_rx != SSP_RX_LSB)) {
dev_err(chip_info->dev,
"RX FIFO endianess is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->endian_tx != SSP_TX_MSB)
&& (chip_info->endian_tx != SSP_TX_LSB)) {
dev_err(chip_info->dev,
"TX FIFO endianess is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->data_size < SSP_DATA_BITS_4)
|| (chip_info->data_size > SSP_DATA_BITS_32)) {
dev_err(chip_info->dev,
"DATA Size is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->com_mode != INTERRUPT_TRANSFER)
&& (chip_info->com_mode != DMA_TRANSFER)
&& (chip_info->com_mode != POLLING_TRANSFER)) {
@ -1663,20 +1639,6 @@ static int verify_controller_parameters(struct pl022 *pl022,
"TX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
if (chip_info->iface == SSP_INTERFACE_MOTOROLA_SPI) {
if ((chip_info->clk_phase != SSP_CLK_FIRST_EDGE)
&& (chip_info->clk_phase != SSP_CLK_SECOND_EDGE)) {
dev_err(chip_info->dev,
"Clock Phase is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->clk_pol != SSP_CLK_POL_IDLE_LOW)
&& (chip_info->clk_pol != SSP_CLK_POL_IDLE_HIGH)) {
dev_err(chip_info->dev,
"Clock Polarity is configured incorrectly\n");
return -EINVAL;
}
}
if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
if ((chip_info->ctrl_len < SSP_BITS_4)
|| (chip_info->ctrl_len > SSP_BITS_32)) {
@ -1825,23 +1787,14 @@ static int calculate_effective_freq(struct pl022 *pl022,
* controller hardware here, that is not done until the actual transfer
* commence.
*/
/* FIXME: JUST GUESSING the spi->mode bits understood by this driver */
#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_LOOP)
static int pl022_setup(struct spi_device *spi)
{
struct pl022_config_chip *chip_info;
struct chip_data *chip;
int status = 0;
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
if (spi->mode & ~MODEBITS) {
dev_dbg(&spi->dev, "unsupported mode bits %x\n",
spi->mode & ~MODEBITS);
return -EINVAL;
}
unsigned int bits = spi->bits_per_word;
u32 tmp;
if (!spi->max_speed_hz)
return -EINVAL;
@ -1884,18 +1837,12 @@ static int pl022_setup(struct spi_device *spi)
* Set controller data default values:
* Polling is supported by default
*/
chip_info->lbm = LOOPBACK_DISABLED;
chip_info->com_mode = POLLING_TRANSFER;
chip_info->iface = SSP_INTERFACE_MOTOROLA_SPI;
chip_info->hierarchy = SSP_SLAVE;
chip_info->slave_tx_disable = DO_NOT_DRIVE_TX;
chip_info->endian_tx = SSP_TX_LSB;
chip_info->endian_rx = SSP_RX_LSB;
chip_info->data_size = SSP_DATA_BITS_12;
chip_info->rx_lev_trig = SSP_RX_1_OR_MORE_ELEM;
chip_info->tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC;
chip_info->clk_phase = SSP_CLK_SECOND_EDGE;
chip_info->clk_pol = SSP_CLK_POL_IDLE_LOW;
chip_info->ctrl_len = SSP_BITS_8;
chip_info->wait_state = SSP_MWIRE_WAIT_ZERO;
chip_info->duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX;
@ -1933,12 +1880,16 @@ static int pl022_setup(struct spi_device *spi)
chip->xfer_type = chip_info->com_mode;
chip->cs_control = chip_info->cs_control;
if (chip_info->data_size <= 8) {
dev_dbg(&spi->dev, "1 <= n <=8 bits per word\n");
if (bits <= 3) {
/* PL022 doesn't support less than 4-bits */
status = -ENOTSUPP;
goto err_config_params;
} else if (bits <= 8) {
dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n");
chip->n_bytes = 1;
chip->read = READING_U8;
chip->write = WRITING_U8;
} else if (chip_info->data_size <= 16) {
} else if (bits <= 16) {
dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
chip->n_bytes = 2;
chip->read = READING_U16;
@ -1955,6 +1906,7 @@ static int pl022_setup(struct spi_device *spi)
dev_err(&spi->dev,
"a standard pl022 can only handle "
"1 <= n <= 16 bit words\n");
status = -ENOTSUPP;
goto err_config_params;
}
}
@ -1987,6 +1939,8 @@ static int pl022_setup(struct spi_device *spi)
/* Special setup for the ST micro extended control registers */
if (pl022->vendor->extended_cr) {
u32 etx;
if (pl022->vendor->pl023) {
/* These bits are only in the PL023 */
SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
@ -2002,29 +1956,51 @@ static int pl022_setup(struct spi_device *spi)
SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
SSP_CR1_MASK_MWAIT_ST, 6);
}
SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
SSP_WRITE_BITS(chip->cr0, bits - 1,
SSP_CR0_MASK_DSS_ST, 0);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx,
SSP_CR1_MASK_RENDN_ST, 4);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx,
SSP_CR1_MASK_TENDN_ST, 5);
if (spi->mode & SPI_LSB_FIRST) {
tmp = SSP_RX_LSB;
etx = SSP_TX_LSB;
} else {
tmp = SSP_RX_MSB;
etx = SSP_TX_MSB;
}
SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4);
SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5);
SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
SSP_CR1_MASK_RXIFLSEL_ST, 7);
SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
SSP_CR1_MASK_TXIFLSEL_ST, 10);
} else {
SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
SSP_WRITE_BITS(chip->cr0, bits - 1,
SSP_CR0_MASK_DSS, 0);
SSP_WRITE_BITS(chip->cr0, chip_info->iface,
SSP_CR0_MASK_FRF, 4);
}
/* Stuff that is common for all versions */
SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
if (spi->mode & SPI_CPOL)
tmp = SSP_CLK_POL_IDLE_HIGH;
else
tmp = SSP_CLK_POL_IDLE_LOW;
SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6);
if (spi->mode & SPI_CPHA)
tmp = SSP_CLK_SECOND_EDGE;
else
tmp = SSP_CLK_FIRST_EDGE;
SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7);
SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
/* Loopback is available on all versions except PL023 */
if (!pl022->vendor->pl023)
SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
if (!pl022->vendor->pl023) {
if (spi->mode & SPI_LOOP)
tmp = LOOPBACK_ENABLED;
else
tmp = LOOPBACK_DISABLED;
SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0);
}
SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
@ -2033,6 +2009,7 @@ static int pl022_setup(struct spi_device *spi)
spi_set_ctldata(spi, chip);
return status;
err_config_params:
spi_set_ctldata(spi, NULL);
err_first_setup:
kfree(chip);
return status;
@ -2095,6 +2072,14 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
master->setup = pl022_setup;
master->transfer = pl022_transfer;
/*
* Supports mode 0-3, loopback, and active low CS. Transfers are
* always MS bit first on the original pl022.
*/
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
if (pl022->vendor->extended_cr)
master->mode_bits |= SPI_LSB_FIRST;
dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
status = amba_request_regions(adev, NULL);

View File

@ -277,19 +277,13 @@ struct pl022_ssp_controller {
*/
struct pl022_config_chip {
struct device *dev;
enum ssp_loopback lbm;
enum ssp_interface iface;
enum ssp_hierarchy hierarchy;
bool slave_tx_disable;
struct ssp_clock_params clk_freq;
enum ssp_rx_endian endian_rx;
enum ssp_tx_endian endian_tx;
enum ssp_data_size data_size;
enum ssp_mode com_mode;
enum ssp_rx_level_trig rx_lev_trig;
enum ssp_tx_level_trig tx_lev_trig;
enum ssp_spi_clk_phase clk_phase;
enum ssp_spi_clk_pol clk_pol;
enum ssp_microwire_ctrl_len ctrl_len;
enum ssp_microwire_wait_state wait_state;
enum ssp_duplex duplex;