diff options
author | Barry Song <barry.song@analog.com> | 2009-11-17 04:45:59 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-10-18 02:49:36 -0400 |
commit | d3cc71f71ae13596cb988e16bfa2b15f09fb7347 (patch) | |
tree | 6fcd5e9401931dbce719bcdfd1e5b4075f392598 | |
parent | 0d2c6de2255cb299fdd77d4543738adee45f4f3f (diff) |
spi/bfin_spi: redo GPIO CS handling
The common SPI layers take care of detecting CS conflicts and preventing
two devices from claiming the same CS. This causes problems for the GPIO
CS support we currently have as we are using CS0 to mean "GPIO CS". But
if we have multiple devices using a GPIO CS, the common SPI layers see
multiple devices using the virtual "CS0" and reject any such attempts.
To make both work, we introduce an offset define. This represents the
max number of hardware CS values that the SPI peripheral supports. If
the CS is below this limit, we know we can use the hardware CS. If it's
above, we treat it as a GPIO CS. This keeps the CS unique as seen by
the common code and prevents conflicts.
Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r-- | arch/blackfin/include/asm/bfin5xx_spi.h | 3 | ||||
-rw-r--r-- | drivers/spi/spi_bfin5xx.c | 40 |
2 files changed, 23 insertions, 20 deletions
diff --git a/arch/blackfin/include/asm/bfin5xx_spi.h b/arch/blackfin/include/asm/bfin5xx_spi.h index 126d25e2afa8..6f011dac378f 100644 --- a/arch/blackfin/include/asm/bfin5xx_spi.h +++ b/arch/blackfin/include/asm/bfin5xx_spi.h | |||
@@ -109,6 +109,8 @@ | |||
109 | #define CMD_SPI_GET_SYSTEMCLOCK 25 | 109 | #define CMD_SPI_GET_SYSTEMCLOCK 25 |
110 | #define CMD_SPI_SET_WRITECONTINUOUS 26 | 110 | #define CMD_SPI_SET_WRITECONTINUOUS 26 |
111 | 111 | ||
112 | #define MAX_CTRL_CS 8 /* cs in spi controller */ | ||
113 | |||
112 | /* device.platform_data for SSP controller devices */ | 114 | /* device.platform_data for SSP controller devices */ |
113 | struct bfin5xx_spi_master { | 115 | struct bfin5xx_spi_master { |
114 | u16 num_chipselect; | 116 | u16 num_chipselect; |
@@ -124,7 +126,6 @@ struct bfin5xx_spi_chip { | |||
124 | u8 enable_dma; | 126 | u8 enable_dma; |
125 | u8 bits_per_word; | 127 | u8 bits_per_word; |
126 | u16 cs_chg_udelay; /* Some devices require 16-bit delays */ | 128 | u16 cs_chg_udelay; /* Some devices require 16-bit delays */ |
127 | u32 cs_gpio; | ||
128 | /* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */ | 129 | /* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */ |
129 | u16 idle_tx_val; | 130 | u16 idle_tx_val; |
130 | u8 pio_interrupt; /* Enable spi data irq */ | 131 | u8 pio_interrupt; /* Enable spi data irq */ |
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 07044d7db9a4..278fe0a612c2 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -183,7 +183,7 @@ static int bfin_spi_flush(struct master_data *drv_data) | |||
183 | /* Chip select operation functions for cs_change flag */ | 183 | /* Chip select operation functions for cs_change flag */ |
184 | static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip) | 184 | static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip) |
185 | { | 185 | { |
186 | if (likely(chip->chip_select_num)) { | 186 | if (likely(chip->chip_select_num < MAX_CTRL_CS)) { |
187 | u16 flag = read_FLAG(drv_data); | 187 | u16 flag = read_FLAG(drv_data); |
188 | 188 | ||
189 | flag &= ~chip->flag; | 189 | flag &= ~chip->flag; |
@@ -196,7 +196,7 @@ static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data * | |||
196 | 196 | ||
197 | static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip) | 197 | static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip) |
198 | { | 198 | { |
199 | if (likely(chip->chip_select_num)) { | 199 | if (likely(chip->chip_select_num < MAX_CTRL_CS)) { |
200 | u16 flag = read_FLAG(drv_data); | 200 | u16 flag = read_FLAG(drv_data); |
201 | 201 | ||
202 | flag |= chip->flag; | 202 | flag |= chip->flag; |
@@ -214,20 +214,24 @@ static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data | |||
214 | /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ | 214 | /* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ |
215 | static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip) | 215 | static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip) |
216 | { | 216 | { |
217 | u16 flag = read_FLAG(drv_data); | 217 | if (chip->chip_select_num < MAX_CTRL_CS) { |
218 | u16 flag = read_FLAG(drv_data); | ||
218 | 219 | ||
219 | flag |= (chip->flag >> 8); | 220 | flag |= (chip->flag >> 8); |
220 | 221 | ||
221 | write_FLAG(drv_data, flag); | 222 | write_FLAG(drv_data, flag); |
223 | } | ||
222 | } | 224 | } |
223 | 225 | ||
224 | static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip) | 226 | static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip) |
225 | { | 227 | { |
226 | u16 flag = read_FLAG(drv_data); | 228 | if (chip->chip_select_num < MAX_CTRL_CS) { |
229 | u16 flag = read_FLAG(drv_data); | ||
227 | 230 | ||
228 | flag &= ~(chip->flag >> 8); | 231 | flag &= ~(chip->flag >> 8); |
229 | 232 | ||
230 | write_FLAG(drv_data, flag); | 233 | write_FLAG(drv_data, flag); |
234 | } | ||
231 | } | 235 | } |
232 | 236 | ||
233 | /* stop controller and re-config current chip*/ | 237 | /* stop controller and re-config current chip*/ |
@@ -1016,7 +1020,6 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
1016 | chip->ctl_reg = chip_info->ctl_reg; | 1020 | chip->ctl_reg = chip_info->ctl_reg; |
1017 | chip->bits_per_word = chip_info->bits_per_word; | 1021 | chip->bits_per_word = chip_info->bits_per_word; |
1018 | chip->cs_chg_udelay = chip_info->cs_chg_udelay; | 1022 | chip->cs_chg_udelay = chip_info->cs_chg_udelay; |
1019 | chip->cs_gpio = chip_info->cs_gpio; | ||
1020 | chip->idle_tx_val = chip_info->idle_tx_val; | 1023 | chip->idle_tx_val = chip_info->idle_tx_val; |
1021 | chip->pio_interrupt = chip_info->pio_interrupt; | 1024 | chip->pio_interrupt = chip_info->pio_interrupt; |
1022 | } | 1025 | } |
@@ -1036,8 +1039,11 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
1036 | * SPI_BAUD, not the real baudrate | 1039 | * SPI_BAUD, not the real baudrate |
1037 | */ | 1040 | */ |
1038 | chip->baud = hz_to_spi_baud(spi->max_speed_hz); | 1041 | chip->baud = hz_to_spi_baud(spi->max_speed_hz); |
1039 | chip->flag = (1 << (spi->chip_select)) << 8; | ||
1040 | chip->chip_select_num = spi->chip_select; | 1042 | chip->chip_select_num = spi->chip_select; |
1043 | if (chip->chip_select_num < MAX_CTRL_CS) | ||
1044 | chip->flag = (1 << spi->chip_select) << 8; | ||
1045 | else | ||
1046 | chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; | ||
1041 | 1047 | ||
1042 | switch (chip->bits_per_word) { | 1048 | switch (chip->bits_per_word) { |
1043 | case 8: | 1049 | case 8: |
@@ -1098,7 +1104,7 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
1098 | disable_irq(drv_data->spi_irq); | 1104 | disable_irq(drv_data->spi_irq); |
1099 | } | 1105 | } |
1100 | 1106 | ||
1101 | if (chip->chip_select_num == 0) { | 1107 | if (chip->chip_select_num >= MAX_CTRL_CS) { |
1102 | ret = gpio_request(chip->cs_gpio, spi->modalias); | 1108 | ret = gpio_request(chip->cs_gpio, spi->modalias); |
1103 | if (ret) { | 1109 | if (ret) { |
1104 | dev_err(&spi->dev, "gpio_request() error\n"); | 1110 | dev_err(&spi->dev, "gpio_request() error\n"); |
@@ -1115,8 +1121,7 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
1115 | spi_set_ctldata(spi, chip); | 1121 | spi_set_ctldata(spi, chip); |
1116 | 1122 | ||
1117 | dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); | 1123 | dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num); |
1118 | if (chip->chip_select_num > 0 && | 1124 | if (chip->chip_select_num < MAX_CTRL_CS) { |
1119 | chip->chip_select_num <= spi->master->num_chipselect) { | ||
1120 | ret = peripheral_request(ssel[spi->master->bus_num] | 1125 | ret = peripheral_request(ssel[spi->master->bus_num] |
1121 | [chip->chip_select_num-1], spi->modalias); | 1126 | [chip->chip_select_num-1], spi->modalias); |
1122 | if (ret) { | 1127 | if (ret) { |
@@ -1131,7 +1136,7 @@ static int bfin_spi_setup(struct spi_device *spi) | |||
1131 | return 0; | 1136 | return 0; |
1132 | 1137 | ||
1133 | pin_error: | 1138 | pin_error: |
1134 | if (chip->chip_select_num == 0) | 1139 | if (chip->chip_select_num >= MAX_CTRL_CS) |
1135 | gpio_free(chip->cs_gpio); | 1140 | gpio_free(chip->cs_gpio); |
1136 | else | 1141 | else |
1137 | peripheral_free(ssel[spi->master->bus_num] | 1142 | peripheral_free(ssel[spi->master->bus_num] |
@@ -1162,14 +1167,11 @@ static void bfin_spi_cleanup(struct spi_device *spi) | |||
1162 | if (!chip) | 1167 | if (!chip) |
1163 | return; | 1168 | return; |
1164 | 1169 | ||
1165 | if ((chip->chip_select_num > 0) | 1170 | if (chip->chip_select_num < MAX_CTRL_CS) { |
1166 | && (chip->chip_select_num <= spi->master->num_chipselect)) { | ||
1167 | peripheral_free(ssel[spi->master->bus_num] | 1171 | peripheral_free(ssel[spi->master->bus_num] |
1168 | [chip->chip_select_num-1]); | 1172 | [chip->chip_select_num-1]); |
1169 | bfin_spi_cs_disable(drv_data, chip); | 1173 | bfin_spi_cs_disable(drv_data, chip); |
1170 | } | 1174 | } else |
1171 | |||
1172 | if (chip->chip_select_num == 0) | ||
1173 | gpio_free(chip->cs_gpio); | 1175 | gpio_free(chip->cs_gpio); |
1174 | 1176 | ||
1175 | kfree(chip); | 1177 | kfree(chip); |