summaryrefslogtreecommitdiffstats
path: root/drivers/spi/amba-pl022.c
diff options
context:
space:
mode:
authorKevin Wells2010-09-16 15:18:50 +0200
committerGrant Likely2010-10-13 05:37:37 +0200
commitbde435a9ca376d0b7809768ca803dbf14416b9c1 (patch)
treedd9678beb7c219922ad9b94db0e8f0a804ae2ab4 /drivers/spi/amba-pl022.c
parentspi: change to new flag variable (diff)
downloadkernel-qcow2-linux-bde435a9ca376d0b7809768ca803dbf14416b9c1.tar.gz
kernel-qcow2-linux-bde435a9ca376d0b7809768ca803dbf14416b9c1.tar.xz
kernel-qcow2-linux-bde435a9ca376d0b7809768ca803dbf14416b9c1.zip
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>
Diffstat (limited to 'drivers/spi/amba-pl022.c')
-rw-r--r--drivers/spi/amba-pl022.c121
1 files changed, 53 insertions, 68 deletions
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index db0c67908d2b..59c90f3ccc26 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -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);