# HG changeset patch
# User Uri Shkolnik <[email protected]>
# Date 1231842832 -7200
# Node ID 924ce9a69a12352546ab13fe1298f45a868c9eb1
# Parent  4ba2960232322ae3a1448670bbf2c33a8ecacfda
SPI (SPP) driver for SMS based devices

From: Uri Shkolnik <[email protected]>

This patch provides SPI interface driver for SMS chip-set based devices.
The patch includes common SMS SPI code, and adapter driver for PXA310

Priority: normal

Signed-off-by: Uri Shkolnik <[email protected]>

diff -r 4ba296023232 -r 924ce9a69a12 linux/drivers/media/dvb/siano/smsdbg_prn.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsdbg_prn.h        Tue Jan 13 12:33:52 
2009 +0200
@@ -0,0 +1,56 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef _SMS_DBG_H_
+#define _SMS_DBG_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/************************************************************************/
+/* Debug Zones definitions.                                             */
+/************************************************************************/
+#undef PERROR
+#  define PERROR(fmt, args...) \
+       printk(KERN_ERR "spibus error: line %d- %s(): " fmt, __LINE__,\
+         __func__, ## args)
+#undef PWARNING
+#  define PWARNING(fmt, args...) \
+       printk(KERN_WARNING "spibus warning: line %d- %s(): " fmt, __LINE__,  \
+       __func__, ## args)
+
+/* the debug macro - conditional compilation from the makefile */
+#undef PDEBUG                  /* undef it, just in case */
+#ifdef SPIBUS_DEBUG
+#  define PDEBUG(fmt, args...) \
+       printk(KERN_DEBUG "spibus: line %d- %s(): " fmt, __LINE__, \
+        __func__, ## args)
+#else
+#  define PDEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+
+/* The following defines are used for printing and
+are mandatory for compilation. */
+#define TXT(str) str
+#define PRN_DBG(str) PDEBUG str
+#define PRN_ERR(str) PERROR str
+
+#endif /*_SMS_DBG_H_*/
diff -r 4ba296023232 -r 924ce9a69a12 
linux/drivers/media/dvb/siano/smsspicommon.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsspicommon.c      Tue Jan 13 12:33:52 
2009 +0200
@@ -0,0 +1,325 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#include "smsspicommon.h"
+#include "smsdbg_prn.h"
+
+static int smsspi_common_find_msg(struct _spi_dev *dev,
+               struct _rx_buffer_st *buf, int offset, int len,
+               int *unused_bytes)
+{
+       int i, missing_bytes;
+       int recieved_bytes, padded_msg_len;
+       int align_fix;
+       char *ptr = (char *)buf->ptr + offset;
+
+       PRN_DBG((TXT("entering with %d bytes.\n"), len));
+       missing_bytes = 0;
+       for (i = 0; i < len; i++, ptr++) {
+               switch (dev->rxState) {
+               case RxsWait_a5:
+                       dev->rxState =
+                           ((*ptr & 0xff) == 0xa5) ? RxsWait_5a : RxsWait_a5;
+                       dev->rxPacket.msg_offset =
+                           (unsigned long)ptr - (unsigned long)buf->ptr + 4;
+                       break;
+               case RxsWait_5a:
+                       dev->rxState =
+                           ((*ptr & 0xff) == 0x5a) ? RxsWait_e7 : RxsWait_a5;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsWait_e7:
+                       dev->rxState =
+                           ((*ptr & 0xff) == 0xe7) ? RxsWait_7e : RxsWait_a5;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsWait_7e:
+                       dev->rxState =
+                           ((*ptr & 0xff) == 0x7e) ? RxsTypeH : RxsWait_a5;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsTypeH:
+                       dev->rxPacket.msg_buf = buf;
+                       dev->rxPacket.msg_offset =
+                           (unsigned long)ptr - (unsigned long)buf->ptr;
+                       dev->rxState = RxsTypeL;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsTypeL:
+                       dev->rxState = RxsGetSrcId;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsGetSrcId:
+                       dev->rxState = RxsGetDstId;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsGetDstId:
+                       dev->rxState = RxsGetLenL;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsGetLenL:
+                       dev->rxState = RxsGetLenH;
+                       dev->rxPacket.msg_len = (*ptr & 0xff);
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsGetLenH:
+                       dev->rxState = RxsFlagsL;
+                       dev->rxPacket.msg_len += (*ptr & 0xff) << 8;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsFlagsL:
+                       dev->rxState = RxsFlagsH;
+                       dev->rxPacket.msg_flags = (*ptr & 0xff);
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsFlagsH:
+                       dev->rxState = RxsData;
+                       dev->rxPacket.msg_flags += (*ptr & 0xff) << 8;
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               case RxsData:
+                       recieved_bytes =
+                           len + offset - dev->rxPacket.msg_offset;
+                       padded_msg_len =
+                           ((dev->rxPacket.msg_len + 4 + SPI_PACKET_SIZE -
+                             1) >> SPI_PACKET_SIZE_BITS) <<
+                           SPI_PACKET_SIZE_BITS;
+                       if (recieved_bytes < padded_msg_len) {
+                               *unused_bytes = 0;
+                               return padded_msg_len - recieved_bytes;
+                       }
+                       dev->rxState = RxsWait_a5;
+                       if (dev->cb.msg_found_cb) {
+                               align_fix = 0;
+               if (dev->rxPacket.msg_flags & MSG_HDR_FLAG_SPLIT_MSG_HDR) {
+                       align_fix = (dev->rxPacket.msg_flags >> 8) & 0x3;
+                                       /* The FW alligned the message data
+                                       therefore - alligment bytes should be
+                                       thrown away. Throw the aligment bytes
+                                       by moving the header ahead over the
+                                       alligment bytes. */
+                                       if (align_fix) {
+                                               u16 length;
+                                               ptr =
+                                                   (char *)dev->rxPacket.
+                                                   msg_buf->ptr +
+                                                   dev->rxPacket.msg_offset;
+
+                                               /* Restore header to original
+                                               state before alignment changes
+                                               */
+                                               length =
+                                                   (ptr[5] << 8) | ptr[4];
+                                               length -= align_fix;
+                                               ptr[5] = length >> 8;
+                                               ptr[4] = length & 0xff;
+                                               /* Zero alignment flags */
+                                               ptr[7] &= 0xfc;
+
+                                               for (i = MSG_HDR_LEN - 1;
+                                                    i >= 0; i--) {
+                                                       ptr[i + align_fix] =
+                                                           ptr[i];
+                                               }
+                                               dev->rxPacket.msg_offset +=
+                                                   align_fix;
+                                       }
+                               }
+
+                               PRN_DBG((TXT
+                               ("Msg found and sent to callback func.\n")));
+                               dev->cb.msg_found_cb(dev->context,
+                                                    dev->rxPacket.msg_buf,
+                                                    dev->rxPacket.msg_offset,
+                                                    dev->rxPacket.msg_len -
+                                                    align_fix);
+                               *unused_bytes =
+                                   len + offset - dev->rxPacket.msg_offset -
+                                   dev->rxPacket.msg_len;
+                               if (*unused_bytes == 0)
+                                       *unused_bytes = -1;
+                               return 0;
+                       } else {
+                               PRN_DBG((TXT
+                ("Msg found but no callback. therefore - thrown away.\n")));
+                       }
+                       PRN_DBG((TXT("state %d.\n"), dev->rxState));
+                       break;
+               }
+       }
+
+       if (dev->rxState == RxsWait_a5) {
+               *unused_bytes = 0;
+               return 0;
+       } else {
+               /* Workaround to corner case: if the last byte of the buffer
+               is "a5" (first byte of the preamble), the host thinks it should
+               send another 256 bytes.  In case the a5 is the firmware
+               underflow byte, this will cause an infinite loop, so we check
+               for this case explicity. */
+               if ((dev->rxState == RxsWait_5a) && (*(ptr - 2) == 0xa5)) {
+                       dev->rxState = RxsWait_a5;
+                       *unused_bytes = 0;
+                       return 0;
+               }
+
+               if (dev->rxPacket.msg_offset >= (SPI_PACKET_SIZE + 4))
+                       /* adding 4 for the preamble. */
+               {               /*The packet will be copied to a new buffer
+                                  and rescaned by the state machine */
+                       *unused_bytes = dev->rxState - RxsWait_a5;
+                       dev->rxState = RxsWait_a5;
+                       dev->cb.free_rx_buf(dev->context, buf);
+                       return 0;
+               } else {
+                       /* report missing bytes and continue
+                          with message scan. */
+                       *unused_bytes = 0;
+                       return SPI_PACKET_SIZE;
+               }
+       }
+}
+
+void smsspi_common_transfer_msg(struct _spi_dev *dev, struct _spi_msg *txmsg,
+                               int padding_allowed)
+{
+       int len, bytes_to_transfer;
+       unsigned long tx_phy_addr;
+       int missing_bytes, tx_bytes;
+       int offset, unused_bytes;
+       int align_block;
+       char *txbuf;
+       struct _rx_buffer_st *buf, *tmp_buf;
+
+       len = 0;
+       if (!dev->cb.transfer_data_cb) {
+               PRN_ERR((TXT
+               ("function called while module is not initialized.\n")));
+               return;
+       }
+       if (txmsg == 0) {
+               bytes_to_transfer = SPI_PACKET_SIZE;
+               txbuf = 0;
+               tx_phy_addr = 0;
+               tx_bytes = 0;
+       } else {
+               tx_bytes = txmsg->len;
+               if (padding_allowed)
+                       bytes_to_transfer =
+                           (((tx_bytes + SPI_PACKET_SIZE -
+                              1) >> SPI_PACKET_SIZE_BITS) <<
+                            SPI_PACKET_SIZE_BITS);
+               else
+                       bytes_to_transfer = (((tx_bytes + 3) >> 2) << 2);
+               txbuf = txmsg->buf;
+               tx_phy_addr = txmsg->buf_phy_addr;
+       }
+       offset = 0;
+       unused_bytes = 0;
+       buf =
+           dev->cb.allocate_rx_buf(dev->context,
+                                   RX_PACKET_SIZE + SPI_PACKET_SIZE);
+       if (!buf) {
+               PRN_ERR((TXT("Failed to allocate RX buffer.\n")));
+               return;
+       }
+       while (bytes_to_transfer || unused_bytes) {
+               if ((unused_bytes <= 0) && (bytes_to_transfer > 0)) {
+                       len = min(bytes_to_transfer, RX_PACKET_SIZE);
+                       PRN_DBG((TXT("transfering block of %d bytes\n"), len));
+                       dev->cb.transfer_data_cb(dev->phy_context, txbuf,
+                                                tx_phy_addr,
+                                                (char *)buf->ptr + offset,
+                                                buf->phy_addr + offset, len);
+               }
+               missing_bytes =
+                   smsspi_common_find_msg(dev, buf, offset, len,
+                                          &unused_bytes);
+               if (bytes_to_transfer)
+                       bytes_to_transfer -= len;
+
+               if (tx_bytes)
+                       tx_bytes -= len;
+
+               if (missing_bytes)
+                       offset += len;
+
+               if (unused_bytes) {
+                       tmp_buf =
+                           dev->cb.allocate_rx_buf(dev->context,
+                                                   RX_PACKET_SIZE);
+                       if (!tmp_buf) {
+                               PRN_ERR((TXT
+                                        ("Failed to allocate RX buffer.\n")));
+                               return;
+                       }
+                       if (unused_bytes > 0) {
+                               /* Copy the remaining bytes to the end of
+                                  alingment block (256 bytes) so next read
+                                  will be alligned. */
+                               align_block =
+                                   (((unused_bytes + SPI_PACKET_SIZE -
+                                      1) >> SPI_PACKET_SIZE_BITS) <<
+                                    SPI_PACKET_SIZE_BITS);
+                               memset(tmp_buf->ptr, 0,
+                                      align_block - unused_bytes);
+                               memcpy((char *)tmp_buf->ptr +
+                                      (align_block - unused_bytes),
+                                      (char *)buf->ptr + offset + len -
+                                      unused_bytes, unused_bytes);
+                               len = align_block;
+                       }
+                       offset = 0;
+                       buf = tmp_buf;
+               }
+               if (tx_bytes <= 0) {
+                       txbuf = 0;
+                       tx_bytes = 0;
+               }
+               if (bytes_to_transfer < missing_bytes) {
+                       bytes_to_transfer =
+                           (((missing_bytes + SPI_PACKET_SIZE -
+                              1) >> SPI_PACKET_SIZE_BITS) <<
+                            SPI_PACKET_SIZE_BITS);
+                       PRN_DBG((TXT
+       ("a message was found, adding bytes to transfer, txmsg %d, total %d\n")
+                       , tx_bytes, bytes_to_transfer));
+               }
+       }
+       dev->cb.free_rx_buf(dev->context, buf);
+}
+
+int smsspicommon_init(struct _spi_dev *dev, void *context, void *phy_context,
+                     struct _spi_dev_cb_st *cb)
+{
+       PRN_DBG((TXT("entering.\n")));
+       if (cb->transfer_data_cb == 0 ||
+           cb->msg_found_cb == 0 ||
+           cb->allocate_rx_buf == 0 || cb->free_rx_buf == 0) {
+               PRN_ERR((TXT("Invalid input parameters of init routine.\n")));
+               return -1;
+       }
+       dev->context = context;
+       dev->phy_context = phy_context;
+       memcpy(&dev->cb, cb, sizeof(struct _spi_dev_cb_st));
+       dev->rxState = RxsWait_a5;
+       PRN_DBG((TXT("exiting.\n")));
+       return 0;
+}
diff -r 4ba296023232 -r 924ce9a69a12 
linux/drivers/media/dvb/siano/smsspicommon.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsspicommon.h      Tue Jan 13 12:33:52 
2009 +0200
@@ -0,0 +1,96 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#ifndef _SMS_SPI_COMMON_H_
+#define _SMS_SPI_COMMON_H_
+
+#define RX_PACKET_SIZE                 0x1000
+#define SPI_PACKET_SIZE_BITS           8
+#define SPI_PACKET_SIZE                (1<<SPI_PACKET_SIZE_BITS)
+#define SPI_MAX_CTRL_MSG_SIZE          0x100
+
+#define MSG_HDR_FLAG_SPLIT_MSG_HDR     0x0004
+#define MSG_HDR_LEN                    8
+
+enum _spi_rx_state {
+       RxsWait_a5 = 0,
+       RxsWait_5a,
+       RxsWait_e7,
+       RxsWait_7e,
+       RxsTypeH,
+       RxsTypeL,
+       RxsGetSrcId,
+       RxsGetDstId,
+       RxsGetLenL,
+       RxsGetLenH,
+       RxsFlagsL,
+       RxsFlagsH,
+       RxsData
+};
+
+struct _rx_buffer_st {
+       void *ptr;
+       unsigned long phy_addr;
+};
+
+struct _rx_packet_request {
+       struct _rx_buffer_st *msg_buf;
+       int msg_offset;
+       int msg_len;
+       int msg_flags;
+};
+
+struct _spi_dev_cb_st{
+       void (*transfer_data_cb) (void *context, unsigned char *, unsigned long,
+                                 unsigned char *, unsigned long, int);
+       void (*msg_found_cb) (void *, void *, int, int);
+       struct _rx_buffer_st *(*allocate_rx_buf) (void *, int);
+       void (*free_rx_buf) (void *, struct _rx_buffer_st *);
+};
+
+struct _spi_dev {
+       void *context;
+       void *phy_context;
+       struct _spi_dev_cb_st cb;
+       char *rxbuf;
+       enum _spi_rx_state rxState;
+       struct _rx_packet_request rxPacket;
+       char *internal_tx_buf;
+};
+
+struct _spi_msg {
+       char *buf;
+       unsigned long buf_phy_addr;
+       int len;
+};
+
+void smsspi_common_transfer_msg(struct _spi_dev *dev, struct _spi_msg *txmsg,
+                               int padding_allowed);
+int smsspicommon_init(struct _spi_dev *dev, void *contex, void *phy_context,
+                     struct _spi_dev_cb_st *cb);
+
+#if defined HEXDUMP_DEBUG && defined SPIBUS_DEBUG
+/*! dump a human readable print of a binary buffer */
+void smsspi_khexdump(char *buf, int len);
+#else
+#define smsspi_khexdump(buf, len)
+#endif
+
+#endif /*_SMS_SPI_COMMON_H_*/
diff -r 4ba296023232 -r 924ce9a69a12 linux/drivers/media/dvb/siano/smsspilog.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsspilog.c Tue Jan 13 12:33:52 2009 +0200
@@ -0,0 +1,445 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+/*!
+       \file   spibusdrv.c
+
+       \brief  spi bus driver module
+
+       This file contains implementation of the spi bus driver.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include "smscoreapi.h"
+#include "smsdbg_prn.h"
+#include "smsspicommon.h"
+#include "smsspiphy.h"
+
+#define SMS_INTR_PIN                   16  /* 0 for nova sip, 26 for vega */
+#define TX_BUFFER_SIZE                 0x200
+#define RX_BUFFER_SIZE                 (0x1000 + SPI_PACKET_SIZE + 0x100)
+#define NUM_RX_BUFFERS                 72
+
+struct _spi_device_st {
+       struct _spi_dev dev;
+       void *phy_dev;
+
+       struct completion write_operation;
+       struct list_head tx_queue;
+       int allocatedPackets;
+       int padding_allowed;
+       char *rxbuf;
+       dma_addr_t rxbuf_phy_addr;
+
+       struct smscore_device_t *coredev;
+       struct list_head txqueue;
+       char *txbuf;
+       dma_addr_t txbuf_phy_addr;
+};
+
+struct _smsspi_txmsg {
+       struct list_head node;  /*! internal management */
+       void *buffer;
+       size_t size;
+       int alignment;
+       int add_preamble;
+       struct completion completion;
+       void (*prewrite) (void *);
+       void (*postwrite) (void *);
+};
+
+struct _spi_device_st *spi_dev;
+
+static void spi_worker_thread(void *arg);
+static DECLARE_WORK(spi_work_queue, (void *)spi_worker_thread);
+static u8 smsspi_preamble[] = { 0xa5, 0x5a, 0xe7, 0x7e };
+static u8 smsspi_startup[] = { 0, 0, 0xde, 0xc1, 0xa5, 0x51, 0xf1, 0xed };
+static u32 default_type = SMS_NOVA_A0;
+static u32 intr_pin = SMS_INTR_PIN;
+
+module_param(default_type, int, 0644);
+MODULE_PARM_DESC(default_type, "default board type.");
+
+module_param(intr_pin, int, 0644);
+MODULE_PARM_DESC(intr_pin, "interrupt pin number.");
+
+/******************************************/
+static void spi_worker_thread(void *arg)
+{
+       struct _spi_device_st *spi_device = spi_dev;
+       struct _smsspi_txmsg *msg = NULL;
+       struct _spi_msg txmsg;
+
+       PDEBUG("worker start\n");
+       do {
+               /* do we have a msg to write ? */
+               if (!msg && !list_empty(&spi_device->txqueue))
+                       msg = (struct _smsspi_txmsg *)
+                                       list_entry(spi_device->txqueue.
+                                       next, struct _smsspi_txmsg, node);
+
+               if (msg) {
+                       if (msg->add_preamble) {
+                               txmsg.len =
+                                   min(msg->size + sizeof(smsspi_preamble),
+                                       (size_t) TX_BUFFER_SIZE);
+                               txmsg.buf = spi_device->txbuf;
+                               txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+                               memcpy(txmsg.buf, smsspi_preamble,
+                                      sizeof(smsspi_preamble));
+                               memcpy(&txmsg.buf[sizeof(smsspi_preamble)],
+                                      msg->buffer,
+                                      txmsg.len - sizeof(smsspi_preamble));
+                               msg->add_preamble = 0;
+                               msg->buffer +=
+                                   txmsg.len - sizeof(smsspi_preamble);
+                               msg->size -=
+                                   txmsg.len - sizeof(smsspi_preamble);
+                               /* zero out the rest of aligned buffer */
+                               memset(&txmsg.buf[txmsg.len], 0,
+                                      TX_BUFFER_SIZE - txmsg.len);
+                               smsspi_common_transfer_msg(&spi_device->dev,
+                                                          &txmsg, 1);
+                       } else {
+                               txmsg.len =
+                                   min(msg->size, (size_t) TX_BUFFER_SIZE);
+                               txmsg.buf = spi_device->txbuf;
+                               txmsg.buf_phy_addr = spi_device->txbuf_phy_addr;
+                               memcpy(txmsg.buf, msg->buffer, txmsg.len);
+
+                               msg->buffer += txmsg.len;
+                               msg->size -= txmsg.len;
+                               /* zero out the rest of aligned buffer */
+                               memset(&txmsg.buf[txmsg.len], 0,
+                                      TX_BUFFER_SIZE - txmsg.len);
+                               smsspi_common_transfer_msg(&spi_device->dev,
+                                                          &txmsg, 0);
+                       }
+
+               } else {
+                       smsspi_common_transfer_msg(&spi_device->dev, NULL, 1);
+               }
+
+               /* if there was write, have we finished ? */
+               if (msg && !msg->size) {
+                       /* call postwrite call back */
+                       if (msg->postwrite)
+                               msg->postwrite(spi_device);
+
+                       list_del(&msg->node);
+                       complete(&msg->completion);
+                       msg = NULL;
+               }
+               /* if there was read, did we read anything ? */
+
+       } while (!list_empty(&spi_device->txqueue) || msg);
+
+       PDEBUG("worker end\n");
+
+}
+
+static void msg_found(void *context, void *buf, int offset, int len)
+{
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct smscore_buffer_t *cb =
+           (struct smscore_buffer_t
+            *)(container_of(buf, struct smscore_buffer_t, p));
+
+       PDEBUG("entering\n");
+       cb->offset = offset;
+       cb->size = len;
+       /* PERROR ("buffer %p is sent back to core databuf=%p,
+               offset=%d.\n", cb, cb->p, cb->offset); */
+       smscore_onresponse(spi_device->coredev, cb);
+
+       PDEBUG("exiting\n");
+
+}
+
+static void smsspi_int_handler(void *context)
+{
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       PDEBUG("interrupt\n");
+       PREPARE_WORK(&spi_work_queue, (void *)spi_worker_thread);
+       spi_device->padding_allowed = 1;
+       schedule_work(&spi_work_queue);
+}
+
+static int smsspi_queue_message_and_wait(struct _spi_device_st *spi_device,
+                                        struct _smsspi_txmsg *msg)
+{
+       init_completion(&msg->completion);
+       list_add_tail(&msg->node, &spi_device->txqueue);
+       schedule_work(&spi_work_queue);
+       wait_for_completion(&msg->completion);
+
+       return 0;
+}
+
+static int smsspi_preload(void *context)
+{
+       struct _smsspi_txmsg msg;
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+
+       prepareForFWDnl(spi_device->phy_dev);
+       PDEBUG("Sending SPI init sequence\n");
+       msg.buffer = smsspi_startup;
+       msg.size = sizeof(smsspi_startup);
+       msg.alignment = 4;
+       msg.add_preamble = 0;
+       msg.prewrite = NULL;    /* smsspiphy_reduce_clock; */
+       msg.postwrite = NULL;
+
+       return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_postload(void *context)
+{
+       struct _Msg {
+               struct SmsMsgHdr_ST hdr;
+               u32 data[3];
+       } Msg = {
+               {
+               MSG_SMS_SPI_INT_LINE_SET_REQ, 0, HIF_TASK,
+                           sizeof(struct _Msg), 0}, {
+               0, intr_pin, 0}
+       };
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct _smsspi_txmsg msg;
+
+       PDEBUG("Sending SPI Set Interrupt command sequence\n");
+       fwDnlComplete(spi_device->phy_dev, 0);
+       msg.buffer = &Msg;
+       msg.size = sizeof(Msg);
+       msg.alignment = SPI_PACKET_SIZE;
+       msg.add_preamble = 1;
+       msg.prewrite = NULL;
+       msg.postwrite = NULL;   /* smsspiphy_restore_clock; */
+
+       return smsspi_queue_message_and_wait(context, &msg);
+}
+
+static int smsspi_write(void *context, void *txbuf, size_t len)
+{
+       struct _smsspi_txmsg msg;
+
+       msg.buffer = txbuf;
+       msg.size = len;
+       msg.prewrite = NULL;
+       msg.postwrite = NULL;
+
+       if (len > 0x1000) {
+               /* The FW is the only long message. Do not add preamble,
+               and do not padd it */
+               msg.alignment = 4;
+               msg.add_preamble = 0;
+               msg.prewrite = smschipreset;
+       } else {
+               msg.alignment = SPI_PACKET_SIZE;
+               msg.add_preamble = 1;
+       }
+       PDEBUG("Writing message to  SPI.\n");
+       PDEBUG("msg hdr: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x.\n",
+              ((u8 *) txbuf)[0], ((u8 *) txbuf)[1], ((u8 *) txbuf)[2],
+              ((u8 *) txbuf)[3], ((u8 *) txbuf)[4], ((u8 *) txbuf)[5],
+              ((u8 *) txbuf)[6], ((u8 *) txbuf)[7]);
+       return smsspi_queue_message_and_wait(context, &msg);
+}
+
+struct _rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+       struct smscore_buffer_t *buf;
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       if (size > RX_BUFFER_SIZE) {
+               PERROR("Requested size is bigger than max buffer size.\n");
+               return NULL;
+       }
+       buf = smscore_getbuffer(spi_device->coredev);
+       PDEBUG("Recieved Rx buf %p physical 0x%x (contained in %p)\n", buf->p,
+              buf->phys, buf);
+
+       /* note: this is not mistake! the rx_buffer_st is identical to part of
+          smscore_buffer_t and we return the address of the start of the
+          identical part */
+       return (struct _rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, struct _rx_buffer_st *buf)
+{
+       struct _spi_device_st *spi_device = (struct _spi_device_st *) context;
+       struct smscore_buffer_t *cb =
+           (struct smscore_buffer_t
+            *)(container_of(((void *)buf), struct smscore_buffer_t, p));
+       PDEBUG("buffer %p is released.\n", cb);
+       smscore_putbuffer(spi_device->coredev, cb);
+}
+
+/*! Release device STUB
+
+\param[in]     dev:            device control block
+\return                void
+*/
+static void smsspi_release(struct device *dev)
+{
+       PDEBUG("nothing to do\n");
+       /* Nothing to release */
+}
+
+static struct platform_device smsspi_device = {
+       .name = "smsspi",
+       .id = 1,
+       .dev = {
+               .release = smsspi_release,
+               },
+};
+
+int smsspi_register(void)
+{
+       struct smsdevice_params_t params;
+       int ret;
+       struct _spi_device_st *spi_device;
+       struct _spi_dev_cb_st common_cb;
+
+       PDEBUG("entering \n");
+
+       spi_device =
+           kmalloc(sizeof(struct _spi_device_st), GFP_KERNEL);
+       spi_dev = spi_device;
+
+       INIT_LIST_HEAD(&spi_device->txqueue);
+
+       ret = platform_device_register(&smsspi_device);
+       if (ret < 0) {
+               PERROR("platform_device_register failed\n");
+               return ret;
+       }
+
+       spi_device->txbuf =
+           dma_alloc_coherent(NULL, TX_BUFFER_SIZE,
+                              &spi_device->txbuf_phy_addr,
+                              GFP_KERNEL | GFP_DMA);
+       if (!spi_device->txbuf) {
+               printk(KERN_INFO "%s dma_alloc_coherent(...) failed\n",
+                      __func__);
+               ret = -ENOMEM;
+               goto txbuf_error;
+       }
+
+       spi_device->phy_dev =
+           smsspiphy_init(NULL, smsspi_int_handler, &spi_device);
+       if (spi_device->phy_dev == 0) {
+               printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+               goto phy_error;
+       }
+
+       common_cb.allocate_rx_buf = allocate_rx_buf;
+       common_cb.free_rx_buf = free_rx_buf;
+       common_cb.msg_found_cb = msg_found;
+       common_cb.transfer_data_cb = smsspibus_xfer;
+
+       ret =
+           smsspicommon_init(&spi_device->dev, spi_device, spi_device->phy_dev,
+                             &common_cb);
+       if (ret) {
+               printk(KERN_INFO "%s smsspiphy_init(...) failed\n", __func__);
+               goto common_error;
+       }
+
+       /* register in smscore */
+       memset(&params, 0, sizeof(params));
+       params.context = spi_device;
+       params.device = &smsspi_device.dev;
+       params.buffer_size = RX_BUFFER_SIZE;
+       params.num_buffers = NUM_RX_BUFFERS;
+       params.flags = SMS_DEVICE_NOT_READY;
+       params.sendrequest_handler = smsspi_write;
+       strcpy(params.devpath, "spi");
+       params.device_type = default_type;
+
+       if (0) {
+               /* device family */
+               /* params.setmode_handler = smsspi_setmode; */
+       } else {
+               params.flags =
+                   SMS_DEVICE_FAMILY2 | SMS_DEVICE_NOT_READY |
+                   SMS_ROM_NO_RESPONSE;
+               params.preload_handler = smsspi_preload;
+               params.postload_handler = smsspi_postload;
+       }
+
+       ret = smscore_register_device(&params, &spi_device->coredev);
+       if (ret < 0) {
+               printk(KERN_INFO "%s smscore_register_device(...) failed\n",
+                      __func__);
+               goto reg_device_error;
+       }
+
+       ret = smscore_start_device(spi_device->coredev);
+       if (ret < 0) {
+               printk(KERN_INFO "%s smscore_start_device(...) failed\n",
+                      __func__);
+               goto start_device_error;
+       }
+
+       PDEBUG("exiting\n");
+       return 0;
+
+start_device_error:
+       smscore_unregister_device(spi_device->coredev);
+
+reg_device_error:
+
+common_error:
+       smsspiphy_deinit(spi_device->phy_dev);
+
+phy_error:
+       dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+                         spi_device->txbuf_phy_addr);
+
+txbuf_error:
+       platform_device_unregister(&smsspi_device);
+
+       PDEBUG("exiting error %d\n", ret);
+
+       return ret;
+}
+
+void smsspi_unregister(void)
+{
+       struct _spi_device_st *spi_device = spi_dev;
+       PDEBUG("entering\n");
+
+       /* stop interrupts */
+       smsspiphy_deinit(spi_device->phy_dev);
+       smscore_unregister_device(spi_device->coredev);
+
+       dma_free_coherent(NULL, TX_BUFFER_SIZE, spi_device->txbuf,
+                         spi_device->txbuf_phy_addr);
+
+       platform_device_unregister(&smsspi_device);
+       PDEBUG("exiting\n");
+}
diff -r 4ba296023232 -r 924ce9a69a12 linux/drivers/media/dvb/siano/smsspiphy.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsspiphy.h Tue Jan 13 12:33:52 2009 +0200
@@ -0,0 +1,36 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_SPI_PHY_H__
+#define __SMS_SPI_PHY_H__
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+                   unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+                   unsigned long rxbuf_phy_addr, int len);
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+                    void *intr_context);
+void smsspiphy_deinit(void *context);
+void smschipreset(void *context);
+void WriteFWtoStellar(void *pSpiPhy, unsigned char *pFW, unsigned long Len);
+void prepareForFWDnl(void *pSpiPhy);
+void fwDnlComplete(void *context, int App);
+
+#endif /* __SMS_SPI_PHY_H__ */
diff -r 4ba296023232 -r 924ce9a69a12 
linux/drivers/media/dvb/siano/smsspiphy_pxa.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/siano/smsspiphy_pxa.c     Tue Jan 13 12:33:52 
2009 +0200
@@ -0,0 +1,435 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+#define PXA_310_LV
+
+#include <linux/kernel.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#ifdef PXA_310_LV
+#include <asm/arch/ssp.h>
+#include <asm/arch/mfp.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pxa3xx_gpio.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include "smsdbg_prn.h"
+
+#ifdef PXA_310_LV
+
+#define SSP_PORT 4
+#define SSP_CKEN CKEN_SSP4
+#define SMS_IRQ_GPIO MFP_PIN_GPIO93
+
+#if (SSP_PORT == 1)
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+#else
+#if (SSP_PORT == 2)
+#define SDCMR_RX DRCMR15
+#define SDCMR_TX DRCMR16
+#else
+#if (SSP_PORT == 3)
+#define SDCMR_RX DRCMR66
+#define SDCMR_TX DRCMR67
+#else
+#if (SSP_PORT == 4)
+#define SDCMR_RX DRCMRRXSADR
+#define SDCMR_TX DRCMRTXSADR
+#endif
+#endif
+#endif
+#endif
+#else /*PXA_310_LV */
+#define SSP_PORT 1
+#define SDCMR_RX DRCMRRXSSDR
+#define SDCMR_TX DRCMRTXSSDR
+
+#endif /*PXA_310_LV */
+
+/* Macros defining physical layer behaviour*/
+#ifdef PXA_310_LV
+#define CLOCK_FACTOR 1
+#else /*PXA_310_LV */
+#define CLOCK_FACTOR 2
+#endif /*PXA_310_LV */
+
+/* Macros for coding reuse */
+
+/*! macro to align the divider to the proper offset in the register bits */
+#define CLOCK_DIVIDER(i)((i-1)<<8)     /* 1-4096 */
+
+/*! DMA related macros */
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+
+#define SSP_TIMEOUT_SCALE (769)
+#define SSP_TIMEOUT(x) ((x*10000)/SSP_TIMEOUT_SCALE)
+
+#define SPI_PACKET_SIZE 256
+
+/* physical layer variables */
+/*! global bus data */
+struct spiphy_dev_s {
+       struct ssp_dev sspdev;  /*!< ssp port configuration */
+       struct completion transfer_in_process;
+       void (*interruptHandler) (void *);
+       void *intr_context;
+       struct device *dev;     /*!< device model stuff */
+       int rx_dma_channel;
+       int tx_dma_channel;
+       int rx_buf_len;
+       int tx_buf_len;
+};
+
+/*!
+invert the endianness of a single 32it integer
+
+\param[in]             u: word to invert
+
+\return                the inverted word
+*/
+static inline u32 invert_bo(u32 u)
+{
+       return ((u & 0xff) << 24) | ((u & 0xff00) << 8) | ((u & 0xff0000) >> 8)
+               | ((u & 0xff000000) >> 24);
+}
+
+/*!
+invert the endianness of a data buffer
+
+\param[in]             buf: buffer to invert
+\param[in]             len: buffer length
+
+\return                the inverted word
+*/
+
+static int invert_endianness(char *buf, int len)
+{
+       int i;
+       u32 *ptr = (u32 *) buf;
+
+       len = (len + 3) / 4;
+       for (i = 0; i < len; i++, ptr++)
+               *ptr = invert_bo(*ptr);
+
+       return 4 * ((len + 3) & (~3));
+}
+
+/*! Map DMA buffers when request starts
+
+\return        error status
+*/
+static unsigned long dma_map_buf(struct spiphy_dev_s *spiphy_dev, char *buf,
+               int len, int direction)
+{
+       unsigned long phyaddr;
+       /* map dma buffers */
+       if (!buf) {
+               PERROR(" NULL buffers to map\n");
+               return 0;
+       }
+       /* map buffer */
+       phyaddr = dma_map_single(spiphy_dev->dev, buf, len, direction);
+       if (dma_mapping_error(phyaddr)) {
+               PERROR("exiting  with error\n");
+               return 0;
+       }
+       return phyaddr;
+}
+
+static irqreturn_t spibus_interrupt(int irq, void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       PDEBUG("recieved interrupt from device dev=%p.\n", context);
+       if (spiphy_dev->interruptHandler)
+               spiphy_dev->interruptHandler(spiphy_dev->intr_context);
+       return IRQ_HANDLED;
+
+}
+
+/*!    DMA controller callback - called only on BUS error condition
+
+\param[in]     channel: DMA channel with error
+\param[in]     data: Unused
+\param[in]     regs: Unused
+\return                void
+*/
+static void spibus_dma_handler(int channel, void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       u32 irq_status = DCSR(channel) & DMA_INT_MASK;
+
+       PDEBUG("recieved interrupt from dma channel %d irq status %x.\n",
+              channel, irq_status);
+       if (irq_status & DCSR_BUSERR) {
+               PERROR("bus error!!! resetting channel %d\n", channel);
+
+               DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+               DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+       }
+       DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+       complete(&spiphy_dev->transfer_in_process);
+}
+
+void smsspibus_xfer(void *context, unsigned char *txbuf,
+                   unsigned long txbuf_phy_addr, unsigned char *rxbuf,
+                   unsigned long rxbuf_phy_addr, int len)
+{
+       /* DMA burst is 8 bytes, therefore we need tmp buffer that size. */
+       unsigned long tmp[2];
+       unsigned long txdma;
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+
+       /* program the controller */
+       if (txbuf)
+               invert_endianness(txbuf, len);
+
+       tmp[0] = -1;
+       tmp[1] = -1;
+
+       /* map RX buffer */
+
+       if (!txbuf)
+               txdma =
+                   dma_map_buf(spiphy_dev, (char *)tmp, sizeof(tmp),
+                               DMA_TO_DEVICE);
+       else
+               txdma = txbuf_phy_addr;
+
+       init_completion(&spiphy_dev->transfer_in_process);
+       /* configure DMA Controller */
+       DCSR(spiphy_dev->rx_dma_channel) = RESET_DMA_CHANNEL;
+       DSADR(spiphy_dev->rx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+       DTADR(spiphy_dev->rx_dma_channel) = rxbuf_phy_addr;
+       DCMD(spiphy_dev->rx_dma_channel) = DCMD_INCTRGADDR | DCMD_FLOWSRC
+           | DCMD_WIDTH4 | DCMD_ENDIRQEN | DCMD_BURST8 | len;
+       PDEBUG("rx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+              spiphy_dev->rx_dma_channel, __PREG(SSDR_P(SSP_PORT)),
+              (unsigned int)rxbuf_phy_addr, DCMD(spiphy_dev->rx_dma_channel));
+       spiphy_dev->rx_buf_len = len;
+
+       DCSR(spiphy_dev->tx_dma_channel) = RESET_DMA_CHANNEL;
+       DTADR(spiphy_dev->tx_dma_channel) = __PREG(SSDR_P(SSP_PORT));
+       DSADR(spiphy_dev->tx_dma_channel) = txdma;
+       if (txbuf) {
+               DCMD(spiphy_dev->tx_dma_channel) =
+                   DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_WIDTH4
+                   /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+               spiphy_dev->tx_buf_len = len;
+       } else {
+               DCMD(spiphy_dev->tx_dma_channel) = DCMD_FLOWTRG
+                   | DCMD_WIDTH4 /* | DCMD_ENDIRQEN */  | DCMD_BURST8 | len;
+               spiphy_dev->tx_buf_len = 4;
+       }
+
+       PDEBUG("tx channel=%d, src=0x%x, dst=0x%x, cmd=0x%x\n",
+              spiphy_dev->tx_dma_channel, (unsigned int)txdma,
+              __PREG(SSDR_P(SSP_PORT)), DCMD(spiphy_dev->tx_dma_channel));
+       /* DALGN - DMA ALIGNMENT REG. */
+       if (rxbuf_phy_addr & 0x7)
+               DALGN |= (1 << spiphy_dev->rx_dma_channel);
+       else
+               DALGN &= ~(1 << spiphy_dev->rx_dma_channel);
+       if (txdma & 0x7)
+               DALGN |= (1 << spiphy_dev->tx_dma_channel);
+       else
+               DALGN &= ~(1 << spiphy_dev->tx_dma_channel);
+
+       /* Start DMA controller */
+       DCSR(spiphy_dev->rx_dma_channel) |= DCSR_RUN;
+       DCSR(spiphy_dev->tx_dma_channel) |= DCSR_RUN;
+       PDEBUG("DMA running. wait for completion.\n");
+       wait_for_completion(&spiphy_dev->transfer_in_process);
+       PDEBUG("DMA complete.\n");
+       invert_endianness(rxbuf, len);
+}
+
+void smschipreset(void *context)
+{
+
+}
+
+void *smsspiphy_init(void *context, void (*smsspi_interruptHandler) (void *),
+                    void *intr_context)
+{
+       int ret;
+       struct spiphy_dev_s *spiphy_dev;
+       u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+       PDEBUG("entering\n");
+
+       spiphy_dev = kmalloc(sizeof(struct spiphy_dev_s), GFP_KERNEL);
+
+       ret = ssp_init(&spiphy_dev->sspdev, SSP_PORT, 0);
+       if (ret) {
+               PERROR("ssp_init failed. error %d", ret);
+               goto error_sspinit;
+       }
+#ifdef PXA_310_LV
+       pxa3xx_mfp_set_afds(SMS_IRQ_GPIO, MFP_AF0, MFP_DS03X);
+       pxa3xx_gpio_set_rising_edge_detect(SMS_IRQ_GPIO, 1);
+       pxa3xx_gpio_set_direction(SMS_IRQ_GPIO, GPIO_DIR_IN);
+#else /*PXA_310_LV */
+       /* receive input interrupts from the SMS 1000 on J32 pin 11 */
+       pxa_gpio_mode(22 | GPIO_IN);
+#endif /*PXA_310_LV */
+       speed = CLOCK_DIVIDER(CLOCK_FACTOR); /* clock divisor for this mode */
+       /* 32bit words in the fifo */
+       mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+       /* SSCR1 = flags */
+       flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE |
+        SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;  /* | SSCR1_TIE */
+
+       ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+       ssp_disable(&(spiphy_dev->sspdev));
+#ifdef PXA_310_LV
+
+       pxa3xx_mfp_set_afds(MFP_PIN_GPIO95, MFP_AF1, MFP_DS03X);
+       pxa3xx_mfp_set_afds(MFP_PIN_GPIO96, MFP_AF1, MFP_DS03X);
+       pxa3xx_mfp_set_afds(MFP_PIN_GPIO97, MFP_AF1, MFP_DS03X);
+       pxa3xx_mfp_set_afds(MFP_PIN_GPIO98, MFP_AF1, MFP_DS03X);
+#else /*PXA_310_LV */
+       pxa_gpio_mode(GPIO23_SCLK_MD);
+       pxa_gpio_mode(GPIO24_SFRM_MD);
+       pxa_gpio_mode(GPIO25_STXD_MD);
+       pxa_gpio_mode(GPIO26_SRXD_MD);
+#endif /*PXA_310_LV */
+       /* setup the dma */
+       spiphy_dev->rx_dma_channel =
+           pxa_request_dma("spibusdrv_rx", DMA_PRIO_HIGH, spibus_dma_handler,
+                           spiphy_dev);
+       if (spiphy_dev->rx_dma_channel < 0) {
+               ret = -EBUSY;
+               PERROR("Could not get RX DMA channel.\n");
+               goto error_rxdma;
+       }
+       spiphy_dev->tx_dma_channel =
+           pxa_request_dma("spibusdrv_tx", DMA_PRIO_HIGH, spibus_dma_handler,
+                           spiphy_dev);
+       if (spiphy_dev->tx_dma_channel < 0) {
+               ret = -EBUSY;
+               PERROR("Could not get TX DMA channel.\n");
+               goto error_txdma;
+       }
+
+       SDCMR_RX = DRCMR_MAPVLD | spiphy_dev->rx_dma_channel;
+       SDCMR_TX = DRCMR_MAPVLD | spiphy_dev->tx_dma_channel;
+
+       PDEBUG("dma rx channel: %d, dma tx channel: %d\n",
+              spiphy_dev->rx_dma_channel, spiphy_dev->tx_dma_channel);
+       /* enable the clock */
+
+       spiphy_dev->interruptHandler = smsspi_interruptHandler;
+       spiphy_dev->intr_context = intr_context;
+#ifdef PXA_310_LV
+       set_irq_type(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), IRQT_FALLING);
+       ret =
+           request_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spibus_interrupt,
+                       SA_INTERRUPT, "SMSSPI", spiphy_dev);
+#else /*PXA_310_LV */
+       set_irq_type(IRQ_GPIO(22), IRQT_FALLING);
+       ret =
+           request_irq(IRQ_GPIO(22), spibus_interrupt, SA_INTERRUPT, "SMSSPI",
+                       &(g_spidata.sspdev));
+#endif /*PXA_310_LV */
+       if (ret) {
+               PERROR("Could not get interrupt for SMS device. status =%d\n",
+                      ret);
+               goto error_irq;
+       }
+
+       ssp_enable(&(spiphy_dev->sspdev));
+       PDEBUG("exiting\n");
+       return spiphy_dev;
+error_irq:
+       if (spiphy_dev->tx_dma_channel >= 0)
+               pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+error_txdma:
+       if (spiphy_dev->rx_dma_channel >= 0)
+               pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+error_rxdma:
+       ssp_exit(&spiphy_dev->sspdev);
+error_sspinit:
+       PDEBUG("exiting on error\n");
+       return 0;
+}
+
+int smsspiphy_deinit(void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       PDEBUG("entering\n");
+
+       /* disable the spi port */
+       ssp_flush(&spiphy_dev->sspdev);
+       ssp_disable(&spiphy_dev->sspdev);
+
+       /*  release DMA resources */
+       if (spiphy_dev->rx_dma_channel >= 0)
+               pxa_free_dma(spiphy_dev->rx_dma_channel);
+
+       if (spiphy_dev->tx_dma_channel >= 0)
+               pxa_free_dma(spiphy_dev->tx_dma_channel);
+
+       /* release Memory resources */
+#ifdef PXA_310_LV
+       free_irq(IRQ_GPIO(MFP2GPIO(SMS_IRQ_GPIO)), spiphy_dev);
+#else /*PXA_310_LV */
+       free_irq(IRQ_GPIO(22), &spiphy_dev->sspdev);
+#endif /*PXA_310_LV */
+       ssp_exit(&spiphy_dev->sspdev);
+       PDEBUG("exiting\n");
+       return 0;
+}
+
+void smsspiphy_set_config(struct spiphy_dev_s *spiphy_dev, int clock_divider)
+{
+       u32 mode, flags, speed, psp_flags = 0;
+       ssp_disable(&spiphy_dev->sspdev);
+       /* clock divisor for this mode. */
+       speed = CLOCK_DIVIDER(clock_divider);
+       /* 32bit words in the fifo */
+       mode = SSCR0_Motorola | SSCR0_DataSize(16) | SSCR0_EDSS;
+       flags = SSCR1_RxTresh(1) | SSCR1_TxTresh(1) | SSCR1_TSRE |
+                SSCR1_RSRE | SSCR1_RIE | SSCR1_TRAIL;  /* | SSCR1_TIE */
+       ssp_config(&spiphy_dev->sspdev, mode, flags, psp_flags, speed);
+       ssp_enable(&spiphy_dev->sspdev);
+}
+
+void prepareForFWDnl(void *context)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 2);
+       msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+       struct spiphy_dev_s *spiphy_dev = (struct spiphy_dev_s *) context;
+       smsspiphy_set_config(spiphy_dev, 1);
+       msleep(100);
+}



      
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to