#define DRV_NAME "bfin-spi"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
-#define DRV_DESC "Blackfin BF5xx on-chip SPI Controller Driver"
+#define DRV_DESC "Blackfin on-chip SPI Controller Driver"
#define DRV_VERSION "1.0"
MODULE_AUTHOR(DRV_AUTHOR);
return spi_baud;
}
-static int flush(struct driver_data *drv_data)
+static int bfin_spi_flush(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
}
/* Chip select operation functions for cs_change flag */
-static void cs_active(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip)
{
u16 flag = read_FLAG(drv_data);
write_FLAG(drv_data, flag);
}
-static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
{
u16 flag = read_FLAG(drv_data);
}
/* stop controller and re-config current chip*/
-static void restore_state(struct driver_data *drv_data)
+static void bfin_spi_restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
write_BAUD(drv_data, chip->baud);
bfin_spi_enable(drv_data);
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
}
/* used to kick off transfer in rx mode */
-static unsigned short dummy_read(struct driver_data *drv_data)
+static unsigned short bfin_spi_dummy_read(struct driver_data *drv_data)
{
unsigned short tmp;
tmp = read_RDBR(drv_data);
return tmp;
}
-static void null_writer(struct driver_data *drv_data)
+static void bfin_spi_null_writer(struct driver_data *drv_data)
{
u8 n_bytes = drv_data->n_bytes;
}
}
-static void null_reader(struct driver_data *drv_data)
+static void bfin_spi_null_reader(struct driver_data *drv_data)
{
u8 n_bytes = drv_data->n_bytes;
- dummy_read(drv_data);
+ bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
- dummy_read(drv_data);
+ bfin_spi_dummy_read(drv_data);
drv_data->rx += n_bytes;
}
}
-static void u8_writer(struct driver_data *drv_data)
+static void bfin_spi_u8_writer(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr8-s is 0x%x\n", read_STAT(drv_data));
cpu_relax();
}
-static void u8_cs_chg_writer(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
while (drv_data->tx < drv_data->tx_end) {
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
++drv_data->tx;
}
}
-static void u8_reader(struct driver_data *drv_data)
+static void bfin_spi_u8_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr-8 is 0x%x\n", read_STAT(drv_data));
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
- dummy_read(drv_data);
+ bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end - 1) {
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
++drv_data->rx;
}
-static void u8_cs_chg_reader(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
while (drv_data->rx < drv_data->rx_end) {
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
read_RDBR(drv_data); /* kick off */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
*(u8 *) (drv_data->rx) = read_SHAW(drv_data);
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
++drv_data->rx;
}
}
-static void u8_duplex(struct driver_data *drv_data)
+static void bfin_spi_u8_duplex(struct driver_data *drv_data)
{
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
}
}
-static void u8_cs_chg_duplex(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
while (drv_data->rx < drv_data->rx_end) {
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
cpu_relax();
*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
++drv_data->rx;
++drv_data->tx;
}
}
-static void u16_writer(struct driver_data *drv_data)
+static void bfin_spi_u16_writer(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr16 is 0x%x\n", read_STAT(drv_data));
cpu_relax();
}
-static void u16_cs_chg_writer(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
while (drv_data->tx < drv_data->tx_end) {
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
drv_data->tx += 2;
}
}
-static void u16_reader(struct driver_data *drv_data)
+static void bfin_spi_u16_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr-16 is 0x%x\n", read_STAT(drv_data));
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
- dummy_read(drv_data);
+ bfin_spi_dummy_read(drv_data);
while (drv_data->rx < (drv_data->rx_end - 2)) {
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
drv_data->rx += 2;
}
-static void u16_cs_chg_reader(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
- cs_active(drv_data, chip);
- dummy_read(drv_data);
+ bfin_spi_cs_active(drv_data, chip);
+ bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end - 2) {
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
}
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
cpu_relax();
drv_data->rx += 2;
}
-static void u16_duplex(struct driver_data *drv_data)
+static void bfin_spi_u16_duplex(struct driver_data *drv_data)
{
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
}
}
-static void u16_cs_chg_duplex(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_duplex(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
while (drv_data->tx < drv_data->tx_end) {
- cs_active(drv_data, chip);
+ bfin_spi_cs_active(drv_data, chip);
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
cpu_relax();
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
drv_data->rx += 2;
drv_data->tx += 2;
}
/* test if ther is more transfer to be done */
-static void *next_transfer(struct driver_data *drv_data)
+static void *bfin_spi_next_transfer(struct driver_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 giveback(struct driver_data *drv_data)
+static void bfin_spi_giveback(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
struct spi_transfer *last_transfer;
msg->state = NULL;
if (!drv_data->cs_change)
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
/* Not stop spi in autobuffer mode */
if (drv_data->tx_dma != 0xFFFF)
msg->complete(msg->context);
}
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
{
struct driver_data *drv_data = dev_id;
struct chip_data *chip = drv_data->cur_chip;
msg->actual_length += drv_data->len_in_bytes;
if (drv_data->cs_change)
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
/* Move to next transfer */
- msg->state = next_transfer(drv_data);
+ msg->state = bfin_spi_next_transfer(drv_data);
}
/* Schedule transfer tasklet */
return IRQ_HANDLED;
}
-static void pump_transfers(unsigned long data)
+static void bfin_spi_pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
struct spi_message *message = NULL;
if (message->state == ERROR_STATE) {
dev_dbg(&drv_data->pdev->dev, "transfer: we've hit an error\n");
message->status = -EIO;
- giveback(drv_data);
+ bfin_spi_giveback(drv_data);
return;
}
if (message->state == DONE_STATE) {
dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n");
message->status = 0;
- giveback(drv_data);
+ bfin_spi_giveback(drv_data);
return;
}
}
/* Setup the transfer state based on the type of transfer */
- if (flush(drv_data) == 0) {
+ if (bfin_spi_flush(drv_data) == 0) {
dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
message->status = -EIO;
- giveback(drv_data);
+ bfin_spi_giveback(drv_data);
return;
}
drv_data->n_bytes = 1;
width = CFG_SPI_WORDSIZE8;
drv_data->read = chip->cs_change_per_word ?
- u8_cs_chg_reader : u8_reader;
+ bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
drv_data->write = chip->cs_change_per_word ?
- u8_cs_chg_writer : u8_writer;
+ bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
drv_data->duplex = chip->cs_change_per_word ?
- u8_cs_chg_duplex : u8_duplex;
+ bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
break;
case 16:
drv_data->n_bytes = 2;
width = CFG_SPI_WORDSIZE16;
drv_data->read = chip->cs_change_per_word ?
- u16_cs_chg_reader : u16_reader;
+ bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
drv_data->write = chip->cs_change_per_word ?
- u16_cs_chg_writer : u16_writer;
+ bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
drv_data->duplex = chip->cs_change_per_word ?
- u16_cs_chg_duplex : u16_duplex;
+ bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
break;
default:
/* No change, the same as default setting */
drv_data->n_bytes = chip->n_bytes;
width = chip->width;
- drv_data->write = drv_data->tx ? chip->write : null_writer;
- drv_data->read = drv_data->rx ? chip->read : null_reader;
- drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+ drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer;
+ drv_data->read = drv_data->rx ? chip->read : bfin_spi_null_reader;
+ drv_data->duplex = chip->duplex ? chip->duplex : bfin_spi_null_writer;
break;
}
cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
}
dev_dbg(&drv_data->pdev->dev,
"transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
- drv_data->write, chip->write, null_writer);
+ drv_data->write, chip->write, bfin_spi_null_writer);
/* speed and width has been set on per message */
message->state = RUNNING_STATE;
write_STAT(drv_data, BIT_STAT_CLR);
cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
if (drv_data->cs_change)
- 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",
* in this mode
*/
message->status = 0;
- giveback(drv_data);
+ bfin_spi_giveback(drv_data);
return;
}
/* Update total byte transfered */
message->actual_length += drv_data->len_in_bytes;
/* Move to next transfer of this msg */
- message->state = next_transfer(drv_data);
+ message->state = bfin_spi_next_transfer(drv_data);
if (drv_data->cs_change)
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
}
/* Schedule next transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
}
/* pop a msg from queue and kick off real transfer */
-static void pump_messages(struct work_struct *work)
+static void bfin_spi_pump_messages(struct work_struct *work)
{
struct driver_data *drv_data;
unsigned long flags;
/* Setup the SSP using the per chip configuration */
drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- restore_state(drv_data);
+ bfin_spi_restore_state(drv_data);
list_del_init(&drv_data->cur_msg->queue);
* got a msg to transfer, queue it in drv_data->queue.
* And kick off message pumper
*/
-static int transfer(struct spi_device *spi, struct spi_message *msg)
+static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
unsigned long flags;
};
/* first setup for new devices */
-static int setup(struct spi_device *spi)
+static int bfin_spi_setup(struct spi_device *spi)
{
struct bfin5xx_spi_chip *chip_info = NULL;
struct chip_data *chip;
return -ENODEV;
}
if (set_dma_callback(drv_data->dma_channel,
- dma_irq_handler, drv_data) < 0) {
+ bfin_spi_dma_irq_handler, drv_data) < 0) {
dev_dbg(&spi->dev, "Unable to set dma callback\n");
return -EPERM;
}
chip->n_bytes = 1;
chip->width = CFG_SPI_WORDSIZE8;
chip->read = chip->cs_change_per_word ?
- u8_cs_chg_reader : u8_reader;
+ bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
chip->write = chip->cs_change_per_word ?
- u8_cs_chg_writer : u8_writer;
+ bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
chip->duplex = chip->cs_change_per_word ?
- u8_cs_chg_duplex : u8_duplex;
+ bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
break;
case 16:
chip->n_bytes = 2;
chip->width = CFG_SPI_WORDSIZE16;
chip->read = chip->cs_change_per_word ?
- u16_cs_chg_reader : u16_reader;
+ bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
chip->write = chip->cs_change_per_word ?
- u16_cs_chg_writer : u16_writer;
+ bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
chip->duplex = chip->cs_change_per_word ?
- u16_cs_chg_duplex : u16_duplex;
+ bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
break;
default:
dev_err(&spi->dev, "%d bits_per_word is not supported\n",
chip->bits_per_word);
- kfree(chip);
+ if (chip_info)
+ kfree(chip);
return -ENODEV;
}
peripheral_request(ssel[spi->master->bus_num]
[chip->chip_select_num-1], spi->modalias);
- cs_deactive(drv_data, chip);
+ bfin_spi_cs_deactive(drv_data, chip);
return 0;
}
* callback for spi framework.
* clean driver specific data
*/
-static void cleanup(struct spi_device *spi)
+static void bfin_spi_cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
kfree(chip);
}
-static inline int init_queue(struct driver_data *drv_data)
+static inline int bfin_spi_init_queue(struct driver_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
/* init transfer tasklet */
tasklet_init(&drv_data->pump_transfers,
- pump_transfers, (unsigned long)drv_data);
+ bfin_spi_pump_transfers, (unsigned long)drv_data);
/* init messages workqueue */
- INIT_WORK(&drv_data->pump_messages, pump_messages);
+ INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages);
drv_data->workqueue = create_singlethread_workqueue(
dev_name(drv_data->master->dev.parent));
if (drv_data->workqueue == NULL)
return 0;
}
-static inline int start_queue(struct driver_data *drv_data)
+static inline int bfin_spi_start_queue(struct driver_data *drv_data)
{
unsigned long flags;
return 0;
}
-static inline int stop_queue(struct driver_data *drv_data)
+static inline int bfin_spi_stop_queue(struct driver_data *drv_data)
{
unsigned long flags;
unsigned limit = 500;
return status;
}
-static inline int destroy_queue(struct driver_data *drv_data)
+static inline int bfin_spi_destroy_queue(struct driver_data *drv_data)
{
int status;
- status = stop_queue(drv_data);
+ status = bfin_spi_stop_queue(drv_data);
if (status != 0)
return status;
return 0;
}
-static int __init bfin5xx_spi_probe(struct platform_device *pdev)
+static int __init bfin_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bfin5xx_spi_master *platform_info;
master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
- master->cleanup = cleanup;
- master->setup = setup;
- master->transfer = transfer;
+ master->cleanup = bfin_spi_cleanup;
+ master->setup = bfin_spi_setup;
+ master->transfer = bfin_spi_transfer;
/* Find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
}
/* Initial and start queue */
- status = init_queue(drv_data);
+ status = bfin_spi_init_queue(drv_data);
if (status != 0) {
dev_err(dev, "problem initializing queue\n");
goto out_error_queue_alloc;
}
- status = start_queue(drv_data);
+ status = bfin_spi_start_queue(drv_data);
if (status != 0) {
dev_err(dev, "problem starting queue\n");
goto out_error_queue_alloc;
return status;
out_error_queue_alloc:
- destroy_queue(drv_data);
+ bfin_spi_destroy_queue(drv_data);
out_error_no_dma_ch:
iounmap((void *) drv_data->regs_base);
out_error_ioremap:
}
/* stop hardware and remove the driver */
-static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
+static int __devexit bfin_spi_remove(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
return 0;
/* Remove the queue */
- status = destroy_queue(drv_data);
+ status = bfin_spi_destroy_queue(drv_data);
if (status != 0)
return status;
}
#ifdef CONFIG_PM
-static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
- status = stop_queue(drv_data);
+ status = bfin_spi_stop_queue(drv_data);
if (status != 0)
return status;
return 0;
}
-static int bfin5xx_spi_resume(struct platform_device *pdev)
+static int bfin_spi_resume(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
bfin_spi_enable(drv_data);
/* Start the queue running */
- status = start_queue(drv_data);
+ status = bfin_spi_start_queue(drv_data);
if (status != 0) {
dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
return status;
return 0;
}
#else
-#define bfin5xx_spi_suspend NULL
-#define bfin5xx_spi_resume NULL
+#define bfin_spi_suspend NULL
+#define bfin_spi_resume NULL
#endif /* CONFIG_PM */
MODULE_ALIAS("platform:bfin-spi");
-static struct platform_driver bfin5xx_spi_driver = {
+static struct platform_driver bfin_spi_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .suspend = bfin5xx_spi_suspend,
- .resume = bfin5xx_spi_resume,
- .remove = __devexit_p(bfin5xx_spi_remove),
+ .suspend = bfin_spi_suspend,
+ .resume = bfin_spi_resume,
+ .remove = __devexit_p(bfin_spi_remove),
};
-static int __init bfin5xx_spi_init(void)
+static int __init bfin_spi_init(void)
{
- return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
+ return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
}
-module_init(bfin5xx_spi_init);
+module_init(bfin_spi_init);
-static void __exit bfin5xx_spi_exit(void)
+static void __exit bfin_spi_exit(void)
{
- platform_driver_unregister(&bfin5xx_spi_driver);
+ platform_driver_unregister(&bfin_spi_driver);
}
-module_exit(bfin5xx_spi_exit);
+module_exit(bfin_spi_exit);