123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- * netup_unidvb_spi.c
- *
- * Internal SPI driver for NetUP Universal Dual DVB-CI
- *
- * Copyright (C) 2014 NetUP Inc.
- * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
- * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include "netup_unidvb.h"
- #include <linux/spi/spi.h>
- #include <linux/spi/flash.h>
- #include <linux/mtd/partitions.h>
- #include <mtd/mtd-abi.h>
- #define NETUP_SPI_CTRL_IRQ 0x1000
- #define NETUP_SPI_CTRL_IMASK 0x2000
- #define NETUP_SPI_CTRL_START 0x8000
- #define NETUP_SPI_CTRL_LAST_CS 0x4000
- #define NETUP_SPI_TIMEOUT 6000
- enum netup_spi_state {
- SPI_STATE_START,
- SPI_STATE_DONE,
- };
- struct netup_spi_regs {
- __u8 data[1024];
- __le16 control_stat;
- __le16 clock_divider;
- } __packed __aligned(1);
- struct netup_spi {
- struct device *dev;
- struct spi_master *master;
- struct netup_spi_regs __iomem *regs;
- u8 __iomem *mmio;
- spinlock_t lock;
- wait_queue_head_t waitq;
- enum netup_spi_state state;
- };
- static char netup_spi_name[64] = "fpga";
- static struct mtd_partition netup_spi_flash_partitions = {
- .name = netup_spi_name,
- .size = 0x1000000, /* 16MB */
- .offset = 0,
- .mask_flags = MTD_CAP_ROM
- };
- static struct flash_platform_data spi_flash_data = {
- .name = "netup0_m25p128",
- .parts = &netup_spi_flash_partitions,
- .nr_parts = 1,
- };
- static struct spi_board_info netup_spi_board = {
- .modalias = "m25p128",
- .max_speed_hz = 11000000,
- .chip_select = 0,
- .mode = SPI_MODE_0,
- .platform_data = &spi_flash_data,
- };
- irqreturn_t netup_spi_interrupt(struct netup_spi *spi)
- {
- u16 reg;
- unsigned long flags;
- if (!spi)
- return IRQ_NONE;
- spin_lock_irqsave(&spi->lock, flags);
- reg = readw(&spi->regs->control_stat);
- if (!(reg & NETUP_SPI_CTRL_IRQ)) {
- spin_unlock_irqrestore(&spi->lock, flags);
- dev_dbg(&spi->master->dev,
- "%s(): not mine interrupt\n", __func__);
- return IRQ_NONE;
- }
- writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
- reg = readw(&spi->regs->control_stat);
- writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
- spi->state = SPI_STATE_DONE;
- wake_up(&spi->waitq);
- spin_unlock_irqrestore(&spi->lock, flags);
- dev_dbg(&spi->master->dev,
- "%s(): SPI interrupt handled\n", __func__);
- return IRQ_HANDLED;
- }
- static int netup_spi_transfer(struct spi_master *master,
- struct spi_message *msg)
- {
- struct netup_spi *spi = spi_master_get_devdata(master);
- struct spi_transfer *t;
- int result = 0;
- u32 tr_size;
- /* reset CS */
- writew(NETUP_SPI_CTRL_LAST_CS, &spi->regs->control_stat);
- writew(0, &spi->regs->control_stat);
- list_for_each_entry(t, &msg->transfers, transfer_list) {
- tr_size = t->len;
- while (tr_size) {
- u32 frag_offset = t->len - tr_size;
- u32 frag_size = (tr_size > sizeof(spi->regs->data)) ?
- sizeof(spi->regs->data) : tr_size;
- int frag_last = 0;
- if (list_is_last(&t->transfer_list,
- &msg->transfers) &&
- frag_offset + frag_size == t->len) {
- frag_last = 1;
- }
- if (t->tx_buf) {
- memcpy_toio(spi->regs->data,
- t->tx_buf + frag_offset,
- frag_size);
- } else {
- memset_io(spi->regs->data,
- 0, frag_size);
- }
- spi->state = SPI_STATE_START;
- writew((frag_size & 0x3ff) |
- NETUP_SPI_CTRL_IMASK |
- NETUP_SPI_CTRL_START |
- (frag_last ? NETUP_SPI_CTRL_LAST_CS : 0),
- &spi->regs->control_stat);
- dev_dbg(&spi->master->dev,
- "%s(): control_stat 0x%04x\n",
- __func__, readw(&spi->regs->control_stat));
- wait_event_timeout(spi->waitq,
- spi->state != SPI_STATE_START,
- msecs_to_jiffies(NETUP_SPI_TIMEOUT));
- if (spi->state == SPI_STATE_DONE) {
- if (t->rx_buf) {
- memcpy_fromio(t->rx_buf + frag_offset,
- spi->regs->data, frag_size);
- }
- } else {
- if (spi->state == SPI_STATE_START) {
- dev_dbg(&spi->master->dev,
- "%s(): transfer timeout\n",
- __func__);
- } else {
- dev_dbg(&spi->master->dev,
- "%s(): invalid state %d\n",
- __func__, spi->state);
- }
- result = -EIO;
- goto done;
- }
- tr_size -= frag_size;
- msg->actual_length += frag_size;
- }
- }
- done:
- msg->status = result;
- spi_finalize_current_message(master);
- return result;
- }
- static int netup_spi_setup(struct spi_device *spi)
- {
- return 0;
- }
- int netup_spi_init(struct netup_unidvb_dev *ndev)
- {
- struct spi_master *master;
- struct netup_spi *nspi;
- master = spi_alloc_master(&ndev->pci_dev->dev,
- sizeof(struct netup_spi));
- if (!master) {
- dev_err(&ndev->pci_dev->dev,
- "%s(): unable to alloc SPI master\n", __func__);
- return -EINVAL;
- }
- nspi = spi_master_get_devdata(master);
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->bus_num = -1;
- master->num_chipselect = 1;
- master->transfer_one_message = netup_spi_transfer;
- master->setup = netup_spi_setup;
- spin_lock_init(&nspi->lock);
- init_waitqueue_head(&nspi->waitq);
- nspi->master = master;
- nspi->regs = (struct netup_spi_regs __iomem *)(ndev->bmmio0 + 0x4000);
- writew(2, &nspi->regs->clock_divider);
- writew(NETUP_UNIDVB_IRQ_SPI, ndev->bmmio0 + REG_IMASK_SET);
- ndev->spi = nspi;
- if (spi_register_master(master)) {
- ndev->spi = NULL;
- dev_err(&ndev->pci_dev->dev,
- "%s(): unable to register SPI bus\n", __func__);
- return -EINVAL;
- }
- snprintf(netup_spi_name,
- sizeof(netup_spi_name),
- "fpga_%02x:%02x.%01x",
- ndev->pci_bus,
- ndev->pci_slot,
- ndev->pci_func);
- if (!spi_new_device(master, &netup_spi_board)) {
- ndev->spi = NULL;
- dev_err(&ndev->pci_dev->dev,
- "%s(): unable to create SPI device\n", __func__);
- return -EINVAL;
- }
- dev_dbg(&ndev->pci_dev->dev, "%s(): SPI init OK\n", __func__);
- return 0;
- }
- void netup_spi_release(struct netup_unidvb_dev *ndev)
- {
- u16 reg;
- unsigned long flags;
- struct netup_spi *spi = ndev->spi;
- if (!spi)
- return;
- spin_lock_irqsave(&spi->lock, flags);
- reg = readw(&spi->regs->control_stat);
- writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat);
- reg = readw(&spi->regs->control_stat);
- writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat);
- spin_unlock_irqrestore(&spi->lock, flags);
- spi_unregister_master(spi->master);
- ndev->spi = NULL;
- }
|