From: Uri Shkolnik <urishk@yahoo.com>
To: Linux-dvb <linux-dvb@linuxtv.org>
Subject: [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices.
Date: Wed, 19 Nov 2008 01:03:04 -0800 (PST) [thread overview]
Message-ID: <270647.42507.qm@web38807.mail.mud.yahoo.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 202 bytes --]
This patch provides SPI interface driver for SMS chip-set based devices.
The patch includes common SMS SPI code, and adapter driver for PXA310
Signed-off-by: Uri Shkolnik <uris@siano-ms.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: smsspi_patch.diff --]
[-- Type: text/x-diff; name="smsspi_patch.diff", Size: 78514 bytes --]
This patch provides SPI interface driver for SMS chip-set based devices.
The patch includes common SMS SPI code, and adapter driver for PXA310
Signed-off-by: Uri Shkolnik <uris@siano-ms.com>
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsdbg_prn.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsdbg_prn.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsdbg_prn.h 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsdbg_prn.h 2008-11-18 18:14:34.000000000 +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 -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c 2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,326 @@
+/****************************************************************
+
+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, 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;
+ if (align_fix) {
+ /* 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. */
+ ptr =
+ (char *)dev->rxPacket.
+ msg_buf->ptr +
+ dev->rxPacket.msg_offset;
+
+ /* Restore header to original
+ state before alignment changes
+ */
+ u16 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;
+ 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,
+ 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(spi_dev_cb_st));
+ dev->rxState = RxsWait_a5;
+ PRN_DBG((TXT("exiting.\n")));
+ return 0;
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.c~ 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.c~ 2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,326 @@
+/****************************************************************
+
+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, 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;
+ if (align_fix) {
+ /* 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. */
+ ptr =
+ (char *)dev->rxPacket.
+ msg_buf->ptr +
+ dev->rxPacket.msg_offset;
+
+ /* Restore header to original
+ state before alignment changes
+ */
+ u16 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;
+ 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,
+ 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(spi_dev_cb_st));
+ dev->rxState = RxsWait_a5;
+ PRN_DBG((TXT("exiting.\n")));
+ return 0;
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspicommon.h 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspicommon.h 2008-11-18 18:13:37.000000000 +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
+} spi_rx_state;
+
+struct {
+ void *ptr;
+ unsigned long phy_addr;
+} rx_buffer_st;
+
+struct _rx_packet_request {
+ rx_buffer_st *msg_buf;
+ int msg_offset;
+ int msg_len;
+ int msg_flags;
+} rx_packet_request;
+
+struct {
+ void (*transfer_data_cb) (void *context, unsigned char *, unsigned long,
+ unsigned char *, unsigned long, int);
+ void (*msg_found_cb) (void *, void *, int, int);
+ rx_buffer_st *(*allocate_rx_buf) (void *, int);
+ void (*free_rx_buf) (void *, rx_buffer_st *);
+} spi_dev_cb_st;
+
+struct spi_dev {
+ void *context;
+ void *phy_context;
+ spi_dev_cb_st cb;
+ char *rxbuf;
+ spi_rx_state rxState;
+ rx_packet_request rxPacket;
+ char *internal_tx_buf;
+} spi_dev_st;
+
+struct spi_msg {
+ char *buf;
+ unsigned long buf_phy_addr;
+ int len;
+} spi_msg_st;
+
+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,
+ 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 -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c 2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,446 @@
+/****************************************************************
+
+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 {
+ 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;
+} spi_device_st;
+
+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 *);
+} smsspi_txmsg_t;
+
+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)
+{
+ spi_device_st *spi_device = spi_dev;
+ smsspi_txmsg_t *msg = NULL;
+ spi_msg_st txmsg;
+
+ PDEBUG("worker start\n");
+ do {
+ /* do we have a msg to write ? */
+ if (!msg && !list_empty(&spi_device->txqueue))
+ msg =
+ (smsspi_txmsg_t *) list_entry(spi_device->txqueue.
+ next, smsspi_txmsg_t,
+ 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)
+{
+ spi_device_st *spi_device = (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)
+{
+ spi_device_st *spi_device = (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(spi_device_st *spi_device,
+ smsspi_txmsg_t *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)
+{
+ smsspi_txmsg_t msg;
+ spi_device_st *spi_device = (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}
+ };
+ spi_device_st *spi_device = (spi_device_st *) context;
+ smsspi_txmsg_t 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)
+{
+ smsspi_txmsg_t 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);
+}
+
+rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+ struct smscore_buffer_t *buf;
+ spi_device_st *spi_device = (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 (rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, rx_buffer_st *buf)
+{
+ spi_device_st *spi_device = (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;
+ spi_device_st *spi_device;
+ spi_dev_cb_st common_cb;
+
+ PDEBUG("entering \n");
+
+ spi_device =
+ kmalloc(sizeof(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(¶ms, 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(¶ms, &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)
+{
+ 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 -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspilog.c~ 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspilog.c~ 2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,446 @@
+/****************************************************************
+
+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 {
+ 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;
+} spi_device_st;
+
+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 *);
+} smsspi_txmsg_t;
+
+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)
+{
+ spi_device_st *spi_device = spi_dev;
+ smsspi_txmsg_t *msg = NULL;
+ spi_msg_st txmsg;
+
+ PDEBUG("worker start\n");
+ do {
+ /* do we have a msg to write ? */
+ if (!msg && !list_empty(&spi_device->txqueue))
+ msg =
+ (smsspi_txmsg_t *) list_entry(spi_device->txqueue.
+ next, smsspi_txmsg_t,
+ 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)
+{
+ spi_device_st *spi_device = (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)
+{
+ spi_device_st *spi_device = (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(spi_device_st *spi_device,
+ smsspi_txmsg_t *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)
+{
+ smsspi_txmsg_t msg;
+ spi_device_st *spi_device = (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}
+ };
+ spi_device_st *spi_device = (spi_device_st *) context;
+ smsspi_txmsg_t 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)
+{
+ smsspi_txmsg_t 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);
+}
+
+rx_buffer_st *allocate_rx_buf(void *context, int size)
+{
+ struct smscore_buffer_t *buf;
+ spi_device_st *spi_device = (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 (rx_buffer_st *) &buf->p;
+}
+
+static void free_rx_buf(void *context, rx_buffer_st *buf)
+{
+ spi_device_st *spi_device = (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;
+ spi_device_st *spi_device;
+ spi_dev_cb_st common_cb;
+
+ PDEBUG("entering \n");
+
+ spi_device =
+ (spi_device_st *) kmalloc(sizeof(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(¶ms, 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(¶ms, &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)
+{
+ 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 -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy.h v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy.h
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy.h 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy.h 2008-11-18 18:13:37.000000000 +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 -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c 2008-11-18 18:13:37.000000000 +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 {
+ 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;
+} spiphy_dev_st;
+
+/*!
+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(spiphy_dev_st *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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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;
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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;
+ spiphy_dev_st *spiphy_dev;
+ u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+ PDEBUG("entering\n");
+
+ spiphy_dev = kmalloc(sizeof(spiphy_dev_st), 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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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(spiphy_dev_st *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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+ smsspiphy_set_config(spiphy_dev, 2);
+ msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+ smsspiphy_set_config(spiphy_dev, 1);
+ msleep(100);
+}
diff -uNr v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~
--- v4l-dvb-c5f976cab011/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~ 1970-01-01 02:00:00.000000000 +0200
+++ v4l-dvb-c5f976cab011_0003/linux/drivers/media/dvb/siano/smsspiphy_pxa.c~ 2008-11-18 18:13:37.000000000 +0200
@@ -0,0 +1,434 @@
+/****************************************************************
+
+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 {
+ 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;
+} spiphy_dev_st;
+
+/*!
+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(spiphy_dev_st *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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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;
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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;
+ spiphy_dev_st *spiphy_dev;
+ u32 mode = 0, flags = 0, psp_flags = 0, speed = 0;
+ PDEBUG("entering\n");
+
+ spiphy_dev = kmalloc(sizeof(spiphy_dev_st), 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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) 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(spiphy_dev_st *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)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+ smsspiphy_set_config(spiphy_dev, 2);
+ msleep(100);
+}
+
+void fwDnlComplete(void *context, int App)
+{
+ spiphy_dev_st *spiphy_dev = (spiphy_dev_st *) context;
+ smsspiphy_set_config(spiphy_dev, 1);
+ msleep(100);
+}
[-- Attachment #3: Type: text/plain, Size: 150 bytes --]
_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
next reply other threads:[~2008-11-19 9:03 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-11-19 9:03 Uri Shkolnik [this message]
2008-11-19 10:24 ` [linux-dvb] [PATCH 2/5] SPI interface driver for Siano's SMS chip-set based devices Christophe Thommeret
2008-11-19 11:53 ` Uri Shkolnik
2008-11-19 12:40 ` [linux-dvb] [PATCH 1/2] Siano's SMS subsystems API - SmsHost support Uri Shkolnik
2008-11-19 17:35 ` Andrea Venturi
2008-11-19 18:00 ` Uri Shkolnik
2008-11-23 10:09 ` Andrea Venturi
2008-12-05 19:08 ` BOUWSMA Barry
2008-12-05 20:20 ` Uri Shkolnik
2008-12-06 11:49 ` BOUWSMA Barry
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=270647.42507.qm@web38807.mail.mud.yahoo.com \
--to=urishk@yahoo.com \
--cc=linux-dvb@linuxtv.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.