/*
* Blackfin On-Chip SPI Driver
*
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
#define DONE_STATE ((void *)2)
#define ERROR_STATE ((void *)-1)
-struct master_data;
+struct bfin_spi_master_data;
-struct transfer_ops {
- void (*write) (struct master_data *);
- void (*read) (struct master_data *);
- void (*duplex) (struct master_data *);
+struct bfin_spi_transfer_ops {
+ void (*write) (struct bfin_spi_master_data *);
+ void (*read) (struct bfin_spi_master_data *);
+ void (*duplex) (struct bfin_spi_master_data *);
};
-struct master_data {
+struct bfin_spi_master_data {
/* Driver model hookup */
struct platform_device *pdev;
/* Current message transfer state info */
struct spi_message *cur_msg;
struct spi_transfer *cur_transfer;
- struct slave_data *cur_chip;
+ struct bfin_spi_slave_data *cur_chip;
size_t len_in_bytes;
size_t len;
void *tx;
u16 flag_reg;
int cs_change;
- const struct transfer_ops *ops;
+ const struct bfin_spi_transfer_ops *ops;
};
-struct slave_data {
+struct bfin_spi_slave_data {
u16 ctl_reg;
u16 baud;
u16 flag;
u32 cs_gpio;
u16 idle_tx_val;
u8 pio_interrupt; /* use spi data irq */
- const struct transfer_ops *ops;
+ const struct bfin_spi_transfer_ops *ops;
};
#define DEFINE_SPI_REG(reg, off) \
-static inline u16 read_##reg(struct master_data *drv_data) \
+static inline u16 read_##reg(struct bfin_spi_master_data *drv_data) \
{ return bfin_read16(drv_data->regs_base + off); } \
-static inline void write_##reg(struct master_data *drv_data, u16 v) \
+static inline void write_##reg(struct bfin_spi_master_data *drv_data, u16 v) \
{ bfin_write16(drv_data->regs_base + off, v); }
DEFINE_SPI_REG(CTRL, 0x00)
DEFINE_SPI_REG(BAUD, 0x14)
DEFINE_SPI_REG(SHAW, 0x18)
-static void bfin_spi_enable(struct master_data *drv_data)
+static void bfin_spi_enable(struct bfin_spi_master_data *drv_data)
{
u16 cr;
write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
}
-static void bfin_spi_disable(struct master_data *drv_data)
+static void bfin_spi_disable(struct bfin_spi_master_data *drv_data)
{
u16 cr;
return spi_baud;
}
-static int bfin_spi_flush(struct master_data *drv_data)
+static int bfin_spi_flush(struct bfin_spi_master_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
}
/* Chip select operation functions for cs_change flag */
-static void bfin_spi_cs_active(struct master_data *drv_data, struct slave_data *chip)
+static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip)
{
if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
u16 flag = read_FLAG(drv_data);
}
}
-static void bfin_spi_cs_deactive(struct master_data *drv_data, struct slave_data *chip)
+static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data,
+ struct bfin_spi_slave_data *chip)
{
if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
u16 flag = read_FLAG(drv_data);
}
/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
-static inline void bfin_spi_cs_enable(struct master_data *drv_data, struct slave_data *chip)
+static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data,
+ struct bfin_spi_slave_data *chip)
{
if (chip->chip_select_num < MAX_CTRL_CS) {
u16 flag = read_FLAG(drv_data);
}
}
-static inline void bfin_spi_cs_disable(struct master_data *drv_data, struct slave_data *chip)
+static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data,
+ struct bfin_spi_slave_data *chip)
{
if (chip->chip_select_num < MAX_CTRL_CS) {
u16 flag = read_FLAG(drv_data);
}
/* stop controller and re-config current chip*/
-static void bfin_spi_restore_state(struct master_data *drv_data)
+static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data)
{
- struct slave_data *chip = drv_data->cur_chip;
+ struct bfin_spi_slave_data *chip = drv_data->cur_chip;
/* Clear status and disable clock */
write_STAT(drv_data, BIT_STAT_CLR);
}
/* used to kick off transfer in rx mode and read unwanted RX data */
-static inline void bfin_spi_dummy_read(struct master_data *drv_data)
+static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data)
{
(void) read_RDBR(drv_data);
}
-static void bfin_spi_u8_writer(struct master_data *drv_data)
+static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data)
{
/* clear RXS (we check for RXS inside the loop) */
bfin_spi_dummy_read(drv_data);
}
}
-static void bfin_spi_u8_reader(struct master_data *drv_data)
+static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data)
{
u16 tx_val = drv_data->cur_chip->idle_tx_val;
}
}
-static void bfin_spi_u8_duplex(struct master_data *drv_data)
+static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data)
{
/* discard old RX data and clear RXS */
bfin_spi_dummy_read(drv_data);
}
}
-static const struct transfer_ops bfin_transfer_ops_u8 = {
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
.write = bfin_spi_u8_writer,
.read = bfin_spi_u8_reader,
.duplex = bfin_spi_u8_duplex,
};
-static void bfin_spi_u16_writer(struct master_data *drv_data)
+static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data)
{
/* clear RXS (we check for RXS inside the loop) */
bfin_spi_dummy_read(drv_data);
}
}
-static void bfin_spi_u16_reader(struct master_data *drv_data)
+static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data)
{
u16 tx_val = drv_data->cur_chip->idle_tx_val;
}
}
-static void bfin_spi_u16_duplex(struct master_data *drv_data)
+static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data)
{
/* discard old RX data and clear RXS */
bfin_spi_dummy_read(drv_data);
}
}
-static const struct transfer_ops bfin_transfer_ops_u16 = {
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
.write = bfin_spi_u16_writer,
.read = bfin_spi_u16_reader,
.duplex = bfin_spi_u16_duplex,
};
-/* test if ther is more transfer to be done */
-static void *bfin_spi_next_transfer(struct master_data *drv_data)
+/* test if there is more transfer to be done */
+static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
{
struct spi_message *msg = drv_data->cur_msg;
struct spi_transfer *trans = drv_data->cur_transfer;
* caller already set message->status;
* dma and pio irqs are blocked give finished message back
*/
-static void bfin_spi_giveback(struct master_data *drv_data)
+static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
{
- struct slave_data *chip = drv_data->cur_chip;
+ struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
/* spi data irq handler */
static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
{
- struct master_data *drv_data = dev_id;
- struct slave_data *chip = drv_data->cur_chip;
+ struct bfin_spi_master_data *drv_data = dev_id;
+ struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
int n_bytes = drv_data->n_bytes;
static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
{
- struct master_data *drv_data = dev_id;
- struct slave_data *chip = drv_data->cur_chip;
+ struct bfin_spi_master_data *drv_data = dev_id;
+ struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
unsigned long timeout;
unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
static void bfin_spi_pump_transfers(unsigned long data)
{
- struct master_data *drv_data = (struct master_data *)data;
+ struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data;
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
- struct slave_data *chip = NULL;
+ struct bfin_spi_slave_data *chip = NULL;
unsigned int bits_per_word;
u16 cr, cr_width, dma_width, dma_config;
u32 tranf_success = 1;
drv_data->n_bytes = 1;
drv_data->len = transfer->len;
cr_width = 0;
- drv_data->ops = &bfin_transfer_ops_u8;
- } else {
+ drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
+ } else if (bits_per_word == 16) {
drv_data->n_bytes = 2;
drv_data->len = (transfer->len) >> 1;
cr_width = BIT_CTL_WORDSIZE;
- drv_data->ops = &bfin_transfer_ops_u16;
+ drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
+ } else {
+ dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
+ message->status = -EINVAL;
+ bfin_spi_giveback(drv_data);
+ return;
}
cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
cr |= cr_width;
dev_dbg(&drv_data->pdev->dev,
"transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n",
- drv_data->ops, chip->ops, &bfin_transfer_ops_u8);
+ drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8);
message->state = RUNNING_STATE;
dma_config = 0;
write_BAUD(drv_data, chip->baud);
write_STAT(drv_data, BIT_STAT_CLR);
- if (drv_data->cs_change)
- bfin_spi_cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
dev_dbg(&drv_data->pdev->dev,
"now pumping a transfer: width is %d, len is %d\n",
/* pop a msg from queue and kick off real transfer */
static void bfin_spi_pump_messages(struct work_struct *work)
{
- struct master_data *drv_data;
+ struct bfin_spi_master_data *drv_data;
unsigned long flags;
- drv_data = container_of(work, struct master_data, pump_messages);
+ drv_data = container_of(work, struct bfin_spi_master_data, pump_messages);
/* Lock queue and check for queue work */
spin_lock_irqsave(&drv_data->lock, flags);
*/
static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
- struct master_data *drv_data = spi_master_get_devdata(spi->master);
+ struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
static int bfin_spi_setup(struct spi_device *spi)
{
struct bfin5xx_spi_chip *chip_info;
- struct slave_data *chip = NULL;
- struct master_data *drv_data = spi_master_get_devdata(spi->master);
+ struct bfin_spi_slave_data *chip = NULL;
+ struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
u16 bfin_ctl_reg;
int ret = -EINVAL;
}
/* translate common spi framework into our register */
+ if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
+ dev_err(&spi->dev, "unsupported spi modes detected\n");
+ goto error;
+ }
if (spi->mode & SPI_CPOL)
chip->ctl_reg |= BIT_CTL_CPOL;
if (spi->mode & SPI_CPHA)
*/
chip->baud = hz_to_spi_baud(spi->max_speed_hz);
chip->chip_select_num = spi->chip_select;
- if (chip->chip_select_num < MAX_CTRL_CS)
+ if (chip->chip_select_num < MAX_CTRL_CS) {
+ if (!(spi->mode & SPI_CPHA))
+ dev_warn(&spi->dev, "Warning: SPI CPHA not set:"
+ " Slave Select not under software control!\n"
+ " See Documentation/blackfin/bfin-spi-notes.txt");
+
chip->flag = (1 << spi->chip_select) << 8;
- else
+ } else
chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS;
if (chip->enable_dma && chip->pio_interrupt) {
*/
static void bfin_spi_cleanup(struct spi_device *spi)
{
- struct slave_data *chip = spi_get_ctldata(spi);
- struct master_data *drv_data = spi_master_get_devdata(spi->master);
+ struct bfin_spi_slave_data *chip = spi_get_ctldata(spi);
+ struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
if (!chip)
return;
spi_set_ctldata(spi, NULL);
}
-static inline int bfin_spi_init_queue(struct master_data *drv_data)
+static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
return 0;
}
-static inline int bfin_spi_start_queue(struct master_data *drv_data)
+static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
{
unsigned long flags;
return 0;
}
-static inline int bfin_spi_stop_queue(struct master_data *drv_data)
+static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
{
unsigned long flags;
unsigned limit = 500;
return status;
}
-static inline int bfin_spi_destroy_queue(struct master_data *drv_data)
+static inline int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
{
int status;
struct device *dev = &pdev->dev;
struct bfin5xx_spi_master *platform_info;
struct spi_master *master;
- struct master_data *drv_data;
+ struct bfin_spi_master_data *drv_data;
struct resource *res;
int status = 0;
/* stop hardware and remove the driver */
static int __devexit bfin_spi_remove(struct platform_device *pdev)
{
- struct master_data *drv_data = platform_get_drvdata(pdev);
+ struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
if (!drv_data)
#ifdef CONFIG_PM
static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct master_data *drv_data = platform_get_drvdata(pdev);
+ struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
status = bfin_spi_stop_queue(drv_data);
static int bfin_spi_resume(struct platform_device *pdev)
{
- struct master_data *drv_data = platform_get_drvdata(pdev);
+ struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
write_CTRL(drv_data, drv_data->ctrl_reg);
{
return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
}
-module_init(bfin_spi_init);
+subsys_initcall(bfin_spi_init);
static void __exit bfin_spi_exit(void)
{