Skip to content

Commit

Permalink
Blackfin SPI Driver: Add GPIO controlled SPI Slave Select support
Browse files Browse the repository at this point in the history
Add support for GPIO controlled SPI Chip Selects.  To make use of this
feature, set chip_select = 0 and add a proper cs_gpio to your
controller_data.

struct spi_board_info
        .chip_select = 0

struct bfin5xx_spi_chip
        .cs_gpio = GPIO_P###

There are various SPI devices that require SPI MODE_0, and need to have
the Chip Selects asserted during the entire transfer.  Consider using
SPI_MODE_3 (SPI_CPHA | SPI_CPOL) if your device allows it.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Michael Hennerich authored and Linus Torvalds committed Apr 7, 2009
1 parent e7d02e3 commit 42c78b2
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 8 deletions.
1 change: 1 addition & 0 deletions arch/blackfin/include/asm/bfin5xx_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ struct bfin5xx_spi_chip {
u8 bits_per_word;
u8 cs_change_per_word;
u16 cs_chg_udelay; /* Some devices require 16-bit delays */
u32 cs_gpio;
};

#endif /* _SPI_CHANNEL_H_ */
40 changes: 32 additions & 8 deletions drivers/spi/spi_bfin5xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct chip_data {
u8 bits_per_word; /* 8 or 16 */
u8 cs_change_per_word;
u16 cs_chg_udelay; /* Some devices require > 255usec delay */
u32 cs_gpio;
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
Expand Down Expand Up @@ -177,22 +178,30 @@ static int bfin_spi_flush(struct driver_data *drv_data)
/* Chip select operation functions for cs_change flag */
static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip)
{
u16 flag = read_FLAG(drv_data);
if (likely(chip->chip_select_num)) {
u16 flag = read_FLAG(drv_data);

flag |= chip->flag;
flag &= ~(chip->flag << 8);
flag |= chip->flag;
flag &= ~(chip->flag << 8);

write_FLAG(drv_data, flag);
write_FLAG(drv_data, flag);
} else {
gpio_set_value(chip->cs_gpio, 0);
}
}

static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
{
u16 flag = read_FLAG(drv_data);
if (likely(chip->chip_select_num)) {
u16 flag = read_FLAG(drv_data);

flag &= ~chip->flag;
flag |= (chip->flag << 8);
flag &= ~chip->flag;
flag |= (chip->flag << 8);

write_FLAG(drv_data, flag);
write_FLAG(drv_data, flag);
} else {
gpio_set_value(chip->cs_gpio, 1);
}

/* Move delay here for consistency */
if (chip->cs_chg_udelay)
Expand Down Expand Up @@ -1036,6 +1045,7 @@ static int bfin_spi_setup(struct spi_device *spi)
struct bfin5xx_spi_chip *chip_info = NULL;
struct chip_data *chip;
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
int ret;

/* Abort device setup if requested features are not supported */
if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
Expand Down Expand Up @@ -1081,6 +1091,7 @@ static int bfin_spi_setup(struct spi_device *spi)
chip->bits_per_word = chip_info->bits_per_word;
chip->cs_change_per_word = chip_info->cs_change_per_word;
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
chip->cs_gpio = chip_info->cs_gpio;
}

/* translate common spi framework into our register */
Expand Down Expand Up @@ -1121,6 +1132,16 @@ static int bfin_spi_setup(struct spi_device *spi)
chip->flag = 1 << (spi->chip_select);
chip->chip_select_num = spi->chip_select;

if (chip->chip_select_num == 0) {
ret = gpio_request(chip->cs_gpio, spi->modalias);
if (ret) {
if (drv_data->dma_requested)
free_dma(drv_data->dma_channel);
return ret;
}
gpio_direction_output(chip->cs_gpio, 1);
}

switch (chip->bits_per_word) {
case 8:
chip->n_bytes = 1;
Expand Down Expand Up @@ -1186,6 +1207,9 @@ static void bfin_spi_cleanup(struct spi_device *spi)
peripheral_free(ssel[spi->master->bus_num]
[chip->chip_select_num-1]);

if (chip->chip_select_num == 0)
gpio_free(chip->cs_gpio);

kfree(chip);
}

Expand Down

0 comments on commit 42c78b2

Please sign in to comment.