[PATCH 4/4][v2] Basic configuration module for Le88266 Zarlink SLIC

Sandeep Singh Sandeep at freescale.com
Tue Mar 5 07:41:37 EST 2013


 - Basic driver which does minimum intialization of the Le88266 SLIC device.
 - The code was originally borrowed from Zarlink driver implementation.
 - It is not full fledged SLIC driver code, it just does basic
   initialization which is required to setup a voice data path between
   channels. This is just enough to test and demonstrate TDM functionality
   on Freescale platforms using TDM Test Module.
 - For full fledged VoIP type of use case proper SLIC driver will be required
   which handles all the functionalities of the device.
 - Going forward this driver will be replaced by Opoen source Zarlink APIs.

Signed-off-by: Sandeep Singh <Sandeep at freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal at freescale.com>
---
 drivers/tdm/Kconfig                  |    1 +
 drivers/tdm/Makefile                 |    2 +-
 drivers/tdm/line_ctrl/Kconfig        |   12 +
 drivers/tdm/line_ctrl/Makefile       |    5 +
 drivers/tdm/line_ctrl/slic_zarlink.c |  715 ++++++++++++++++++++++++++++++++++
 drivers/tdm/line_ctrl/slic_zarlink.h |  131 +++++++
 6 files changed, 865 insertions(+), 1 deletions(-)
 create mode 100644 drivers/tdm/line_ctrl/Kconfig
 create mode 100644 drivers/tdm/line_ctrl/Makefile
 create mode 100644 drivers/tdm/line_ctrl/slic_zarlink.c
 create mode 100644 drivers/tdm/line_ctrl/slic_zarlink.h

diff --git a/drivers/tdm/Kconfig b/drivers/tdm/Kconfig
index f430adc..434ad6e 100644
--- a/drivers/tdm/Kconfig
+++ b/drivers/tdm/Kconfig
@@ -24,4 +24,5 @@ config TDM_DEBUG_CORE
 
 source drivers/tdm/test/Kconfig
 source drivers/tdm/device/Kconfig
+source drivers/tdm/line_ctrl/Kconfig
 endif # TDM
diff --git a/drivers/tdm/Makefile b/drivers/tdm/Makefile
index d73fbbd..ea66fff 100644
--- a/drivers/tdm/Makefile
+++ b/drivers/tdm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the TDM core.
 #
 
-obj-$(CONFIG_TDM)		+= tdm-core.o device/
+obj-$(CONFIG_TDM)		+= tdm-core.o device/ line_ctrl/
 obj-$(CONFIG_TDM_TEST)		+= test/
 ifeq ($(CONFIG_TDM_DEBUG_CORE),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/tdm/line_ctrl/Kconfig b/drivers/tdm/line_ctrl/Kconfig
new file mode 100644
index 0000000..e7421b9
--- /dev/null
+++ b/drivers/tdm/line_ctrl/Kconfig
@@ -0,0 +1,12 @@
+#
+# TDM line control driver config file
+#
+
+menu "Line Control Devices"
+
+config SLIC_ZARLINK
+	tristate "Zarlink Slic intialization Module"
+		default n
+		---help---
+		  This module initialize and configure the zarlink slic
+endmenu
diff --git a/drivers/tdm/line_ctrl/Makefile b/drivers/tdm/line_ctrl/Makefile
new file mode 100644
index 0000000..91e8916
--- /dev/null
+++ b/drivers/tdm/line_ctrl/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the TDM line control drivers.
+#
+
+obj-y		+= slic_zarlink.o
diff --git a/drivers/tdm/line_ctrl/slic_zarlink.c b/drivers/tdm/line_ctrl/slic_zarlink.c
new file mode 100644
index 0000000..579d2ab
--- /dev/null
+++ b/drivers/tdm/line_ctrl/slic_zarlink.c
@@ -0,0 +1,715 @@
+/*
+ * drivers/tdm/line_ctrl/slic_zarlink.c
+ *
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * SLIC Line Control Module for Zarlink SLICs.
+ * This  is a slic control and initialization module.
+ *
+ * Author:Poonam Aggrwal<poonam.aggrwal at freescale.com>
+ *        Hemant Agrawal <hemant at freescale.com>
+ *        Rajesh Gumasta <rajesh.gumasta at freescale.com>
+ *
+ * Modified by Sandeep Kr Singh <sandeep at freescale.com>
+ *    1. Changed SPI cmnds to restrict transaction length to 1 byte.
+ *    2. Updated probe which now does not relies on modalias.
+ *
+ * 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 driver was created solely by Freescale, without the assistance,
+ * support or intellectual property of Zarlink Semiconductor.  No maintenance
+ * or support will be provided by Zarlink Semiconductor regarding this driver
+ *
+ * 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, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ /* Note that this is a complete rewrite of Poonam's slic code.
+    But we have used so much of her original code and ideas that it seems
+    only fair to recognize her as co-author -- Rajesh & Hemant */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include "slic_zarlink.h"
+#include <linux/tdm.h>
+
+#define DRV_DESC "FREESCALE DEVELOPED ZARLINK SLIC DRIVER"
+#define DRV_NAME "legerity"
+
+#define MAX_NUM_OF_SLICS 10
+#define SLIC_TRANS_LEN 1
+#define TDM_PHY_SLIC	1
+#define TDM_PHY_E1	2
+#define TDM_PHY_T1	3
+
+#define TESTING_PRODUCT_CODE
+
+static struct spi_device *g_spi;
+struct spi_transfer t;
+
+struct slic_channel {
+	unsigned int ch1_rx_slot, ch1_tx_slot, ch2_rx_slot, ch2_tx_slot;
+};
+struct slic_channel slic_ch[MAX_NUM_OF_SLICS];
+static int num_slics;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Poonam Aggrwal<poonam.aggrwal at freescale.com>");
+MODULE_DESCRIPTION(DRV_DESC);
+
+static void
+slic_cmd(struct spi_device *spi, unsigned char channel, unsigned char cmd,
+		unsigned char len, unsigned char *cmdData)
+{
+	unsigned char ecCmd = WRITE_CHANNEL_ENABLE;
+	unsigned char cmdLen;
+
+	/* Write EC command */
+	spi_write(spi, &ecCmd, SLIC_TRANS_LEN);
+
+	/* write EC value */
+	spi_write(spi, &channel, SLIC_TRANS_LEN);
+
+	/* write command */
+	spi_write(spi, &cmd, SLIC_TRANS_LEN);
+
+	/* If read command or write command */
+	if (cmd & 0x01) {
+		for (cmdLen = 0; cmdLen < len; cmdLen++)
+			spi_read(spi, &cmdData[cmdLen], SLIC_TRANS_LEN);
+		}
+	else {
+		for (cmdLen = 0; cmdLen < len; cmdLen++)
+			spi_write(spi, &cmdData[cmdLen], SLIC_TRANS_LEN);
+	}
+}
+
+static void get_slic_product_code(struct spi_device *spi)
+{
+	u8 tx = READ_PRODUCT_CODE;
+	u8 rx = 0x00;
+
+	spi_write(spi, &tx, SLIC_TRANS_LEN);
+	spi_read(spi, &rx, SLIC_TRANS_LEN);
+	printk(KERN_INFO "SLIC: product code 1 read is  %x\n", rx);
+
+	spi_read(spi, &rx, SLIC_TRANS_LEN);
+	printk(KERN_INFO "SLIC: product code 2 read is  %x\n", rx);
+
+	tx = WRITE_CHANNEL_ENABLE;
+	spi_write(spi, &tx, SLIC_TRANS_LEN);
+	spi_read(spi, &rx, SLIC_TRANS_LEN);
+	printk(KERN_INFO "SLIC: config read is  %x\n", rx);
+
+	tx = READ_DEVICE_CONFIGURATION;
+	spi_write(spi, &tx, SLIC_TRANS_LEN);
+	spi_read(spi, &rx, SLIC_TRANS_LEN);
+	printk(KERN_INFO "SLIC: config read is  %x\n", rx);
+
+	return;
+}
+
+static int slic_init_configure(struct fsl_tdm_adapt_cfg *tdm_config)
+{
+	char temp1 = 0;
+	char temp2[2];
+	char temp3[3];
+	unsigned char cad[4];
+	unsigned char len;
+	unsigned char channel_id;
+	struct spi_device *spi = g_spi;
+	int slic_id = num_slics;
+
+	temp3[0] = 0x04;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, HW_RESET, len, &temp3[0]);
+
+#ifdef TESTING_PRODUCT_CODE
+	get_slic_product_code(spi);
+#endif
+	temp3[0] = 0x80;
+	switch (tdm_config->tdm_tx_clk) {
+	case 2048000:
+		temp3[0] = temp3[0] | 0x02;
+		break;
+	default:
+		temp3[0] = 0x82;
+	}
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_DEVICE_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x7f;
+	temp3[1] = 0xff;
+	len = 0x02;
+	slic_cmd(spi, CHANNEL1, WRITE_INT_MASK, len, &temp3[0]);
+
+	temp3[0] = 0xff;
+	temp3[1] = 0xff;
+	len = 0x02;
+	slic_cmd(spi, CHANNEL1, WRITE_INT_MASK, len, &temp3[0]);
+
+	temp3[0] = 0x40;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_TXRXCLKSLOT_TXCLKEDGE, len,
+			&temp3[0]);
+
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SYSTEM_STATE, len, &temp3[0]);
+
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL2, WRITE_SYSTEM_STATE, len, &temp3[0]);
+
+	/* Put the Switching regulators in disabled mode */
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_CTRL, len,
+			&temp3[0]);
+
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_CTRL, len,
+			&temp3[0]);
+
+	temp3[0] = 0x3;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SYSTEM_STATE_CFG, len,
+			&temp3[0]);
+
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SYSTEM_STATE, len, &temp3[0]);
+
+	temp3[0] = 0x3;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL2, WRITE_SYSTEM_STATE_CFG, len,
+			&temp3[0]);
+
+	temp3[0] = 0x0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL2, WRITE_SYSTEM_STATE, len, &temp3[0]);
+
+	temp3[0] = 0x2b;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SYSTEM_STATE, len, &temp3[0]);
+
+	temp3[0] = 0x80;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_OPERATING_FUNCTION, len,
+			&temp3[0]);
+
+	temp3[0] = 0xe0;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_OPERATING_CONDITIONS, len,
+			&temp3[0]);
+
+	temp3[0] = 0x1;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	/* Set Switching Paramenters as for Le88266
+	 * 1. BSI[1:0] = 00b (sense pin VBL is SWVSY, VBH is SWVSZ)
+	 * 2. SWFS[1:0] = 00b (setting frequency as 384kHz in high power mode)
+	 * 3. SWYV[4:0] = 00101b (setting to -25V)
+	 * 4. SWZV[4:0] = 00000b (setting to 0V)
+	 */
+	temp3[0] = 0x00;
+	temp3[1] = 0x05;
+	temp3[2] = 0x00;
+	len = 0x03;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_PARAMS, len,
+			&temp3[0]);
+
+	/* Put the Switching regulators in
+	 * 1. Regulator Y & Z in low power state
+	 * 2. Over voltage protection enabled
+	 */
+	temp3[0] = 0x15;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_CTRL, len,
+			&temp3[0]);
+
+	/* Wait 20ms before switching from low power to high power */
+	mdelay(20);
+
+	temp3[0] = 0x9;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0xb;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0xb;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x1;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x1;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL2, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x2;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x2;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x3;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	temp3[0] = 0x3;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_CONVERTER_CFG, len, &temp3[0]);
+
+	/* Set Switching Paramenters as for Le88266
+	 * 1. BSI[1:0] = 00b (sense pin VBL is SWVSY, VBH is SWVSZ)
+	 * 2. SWFS[1:0] = 00b (setting frequency as 384kHz in high power mode)
+	 * 3. SWYV[4:0] = 00101b (setting to -25V)
+	 * 4. SWZV[4:0] = 00000b (setting to 0V)
+	 */
+	temp3[0] = 0x00;
+	temp3[1] = 0x05;
+	temp3[2] = 0x00;
+	len = 0x03;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_PARAMS, len,
+			&temp3[0]);
+
+	/* Put the Switching regulators in
+	 * 1. Regulator Y & Z in high power state
+	 * 2. Over voltage protection enabled
+	 */
+	temp3[0] = 0x1f;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_SWITCH_REGULATOR_CTRL, len,
+			&temp3[0]);
+
+	/* Setting the channel specific parameters */
+	for (channel_id = CHANNEL1; channel_id <= CHANNEL2; channel_id++) {
+
+		/* Set the IO direction to Output - to energise the fxo
+		 * relay */
+		temp3[0] = 0x1;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_IO_DIRECTION, len,
+				&temp3[0]);
+
+		temp3[0] = 0x0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_IO_DATA, len,
+				&temp3[0]);
+
+		temp3[0] = 0x0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		len = sizeof(dataset_cadenceTimer) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_CADENCE_TIMER, len,
+				&dataset_cadenceTimer[0]);
+
+		temp3[0] = 0x2;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0xc0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x0;
+		temp3[1] = 0x2;
+		len = 0x02;
+		slic_cmd(spi, channel_id, WRITE_DC_CALIBRATION, len,
+			       &temp3[0]);
+
+		temp3[0] = 0x0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE, len,
+				&temp3[0]);
+
+		len = sizeof(dataset_writeLoopParams) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id,
+				WRITE_LOOP_SUPERVISION_PARAMS, len,
+				&dataset_writeLoopParams[0]);
+
+		temp3[0] = 0x13;
+		temp3[1] = 0x8;
+		len = 0x02;
+		slic_cmd(spi, channel_id, WRITE_DC_FEED_PARAMS, len,
+				&temp3[0]);
+
+		len = sizeof(dataset1_for_nooperation) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_NO_OPERATION, len,
+				&dataset1_for_nooperation[0]);
+
+		temp3[0] = 0x3f;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_FUNCTION,
+				len, &temp3[0]);
+
+		len = sizeof(dataset2_for_nooperation) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_NO_OPERATION, len,
+				&dataset2_for_nooperation[0]);
+
+		temp3[0] = 0x2;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		len = sizeof(dataset_internalCfgReg3) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_INTERNAL_CFG_REG3 ,
+				len, &dataset_internalCfgReg3[0]);
+
+		len = sizeof(dataset3_for_nooperation) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_NO_OPERATION, len,
+				&dataset3_for_nooperation[0]);
+
+		temp3[0] = 0xbf;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_FUNCTION,
+				len, &temp3[0]);
+
+		temp3[0] = 0xc0;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x6;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0x6;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0xc0;
+		len = 0x1;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x16;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0xc0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x16;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0x3f;
+		if (channel_id == CHANNEL1)
+			temp3[1] = 0xff;
+		else
+			temp3[1] = 0xbf;
+		len = 0x02;
+		slic_cmd(spi, channel_id, WRITE_INT_MASK, len,
+				&temp3[0]);
+
+		temp3[0] = 0x16;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp3[0]);
+
+		temp3[0] = 0xc0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x0;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_CONDITIONS,
+				len, &temp3[0]);
+
+		temp3[0] = 0x0;
+		temp3[1] = 0x2;
+		len = 0x02;
+		slic_cmd(spi, channel_id, WRITE_DC_CALIBRATION, len,
+				&temp3[0]);
+
+		temp3[0] = 0x2b;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE, len,
+				&temp3[0]);
+
+	}
+	/* Reading the Device Configuration register */
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, READ_DEVICE_CONFIGURATION, len,
+			&temp1);
+	printk(KERN_INFO "DEV reg is %x\n", temp1);
+
+	/* Enabling interrupt by writing into Device Configuration Register */
+	temp1 &= 0x7F;
+	len = 0x01;
+	slic_cmd(spi, CHANNEL1, WRITE_DEVICE_CFG, len, &temp1);
+
+	/*  Reading the Device Configuration register */
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, READ_DEVICE_CONFIGURATION, len,
+			&temp1);
+	printk(KERN_INFO "DEV reg after is %x\n", temp1);
+
+	/*  Reading the Mask register */
+	len = 0x2;
+	slic_cmd(spi, CHANNEL1, READ_INT_MASK, len, &temp2[0]);
+	printk(KERN_INFO "Mask reg before setting is %x %x\n",
+					 temp2[0], temp2[1]);
+
+	/*  Writing into the mask register */
+	temp2[0] = 0xF6;
+	temp2[1] = 0xF6;
+	len = 0x2;
+	slic_cmd(spi, CHANNEL1, WRITE_INT_MASK, len, &temp2[0]);
+
+	/*  Reading the Mask register */
+	len = 0x2;
+	slic_cmd(spi, CHANNEL1, READ_INT_MASK, len, &temp2[0]);
+	printk(KERN_INFO "Mask reg after setting is %x %x\n",
+					 temp2[0], temp2[1]);
+
+	temp1 = slic_id*4;
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, WRITE_TX_TIME_SLOT, len, &temp1);
+
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, READ_TX_TIME_SLOT, len, &temp1);
+	printk(KERN_INFO "Read Tx Timeslot for CH1 is %x\n", temp1);
+
+	temp1 = slic_id*4 + 2;
+	len = 0x1;
+	slic_cmd(spi, CHANNEL2, WRITE_TX_TIME_SLOT, len, &temp1);
+
+	len = 0x1;
+	slic_cmd(spi, CHANNEL2, READ_TX_TIME_SLOT, len, &temp1);
+	printk(KERN_INFO "Read Tx Timeslot for CH2 is %x\n", temp1);
+
+	temp1 = slic_id*4;
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, WRITE_RX_TIME_SLOT, len, &temp1);
+
+	len = 0x1;
+	slic_cmd(spi, CHANNEL1, READ_RX_TIME_SLOT, len, &temp1);
+	printk(KERN_INFO "Read Rx Timeslot for CH1 is %x\n", temp1);
+
+	temp1 = slic_id*4 + 2;
+	len = 0x1;
+	slic_cmd(spi, CHANNEL2, WRITE_RX_TIME_SLOT, len, &temp1);
+
+	len = 0x1;
+	slic_cmd(spi, CHANNEL2, READ_RX_TIME_SLOT, len, &temp1);
+	printk(KERN_INFO "Read Rx Timeslot for CH2 is %x\n", temp1);
+
+	for (channel_id = CHANNEL1; channel_id <= CHANNEL2; channel_id++) {
+
+		temp1 &= 0xBF;
+		temp1 |= 0x80;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_OPERATING_FUNCTION,
+				len, &temp1);
+
+		len = 0x01;
+		slic_cmd(spi, channel_id, READ_OPERATING_FUNCTION,
+				len, &temp1);
+		printk(KERN_INFO "Operating Fun for channel %d is %x\n",
+				channel_id, temp1);
+
+		/* Install Timers */
+		len = 0x04;
+		slic_cmd(spi, channel_id, READ_CADENCE_TIMER,	len,
+				&cad[0]);
+		printk(KERN_INFO "Cadence Timer Reg for CH%d before is %x %x"
+				"%x %x\n", channel_id, cad[0], cad[1], cad[2],
+			       cad[3]);
+
+		len = sizeof(set_cadenceTimer) / sizeof(unsigned char);
+		slic_cmd(spi, channel_id, WRITE_CADENCE_TIMER, len,
+				&set_cadenceTimer[0]);
+
+		len = 0x04;
+		slic_cmd(spi, channel_id, READ_CADENCE_TIMER , len,
+				&cad[0]);
+		printk(KERN_INFO "Cadence Timer Reg for CH%d after is %x %x"
+				"%x %x\n", channel_id, cad[0], cad[1], cad[2],
+				cad[3]);
+		temp1 = 0x20;
+		len = 0x01;
+		slic_cmd(spi, channel_id, WRITE_SYSTEM_STATE_CFG,
+				len, &temp1);
+
+		slic_cmd(spi, channel_id, READ_SYSTEM_STATE_CFG,
+				len, &temp1);
+		printk(KERN_INFO "Switching control for channel %d is %x\n",
+				channel_id, temp1);
+	}
+	num_slics++;
+	return 0;
+}
+
+void configure_spi_pdata(struct spi_device *spi)
+{
+	struct slic_platform_data *spi_slic_pdata;
+	static int num_slic;
+
+	spi_slic_pdata = kzalloc(sizeof(*spi_slic_pdata), GFP_KERNEL);
+	if (spi_slic_pdata == NULL)
+		return;
+
+	spi->dev.platform_data = spi_slic_pdata;
+
+	spi_slic_pdata->ch1_rx_slot = CH1_RX_SLOT_NUM + num_slic;
+	spi_slic_pdata->ch1_tx_slot = CH1_TX_SLOT_NUM + num_slic;
+	spi_slic_pdata->ch2_rx_slot = CH2_RX_SLOT_NUM + num_slic;
+	spi_slic_pdata->ch2_tx_slot = CH2_TX_SLOT_NUM + num_slic;
+	pr_info("SLIC config success\n");
+	num_slic = num_slic + SLIC_SLOT_OFFSET;
+
+}
+static int slic_remove(struct spi_device *spi)
+{
+
+	printk(KERN_INFO "SLIC module uninstalled\n");
+	return 0;
+}
+
+static int slic_probe(struct spi_device *spi)
+{
+	int ret = 0;
+	struct slic_platform_data *data;
+	struct tdm_phy_priv *p_tdm_phy_priv;
+	struct device_node *np = spi->dev.of_node;
+	const phandle *phandle_prop;
+	g_spi = spi;
+
+	printk(KERN_INFO "SLIC probed!\n");
+
+	p_tdm_phy_priv = kzalloc(sizeof(struct tdm_phy_priv), GFP_KERNEL);
+	if (!p_tdm_phy_priv) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	if (of_device_is_compatible(np, "tdm-phy-slic")) {
+		p_tdm_phy_priv->type = TDM_PHY_SLIC;
+		printk(KERN_INFO "TDM Phy type: SLIC\n");
+	} else if (of_device_is_compatible(np, "tdm-phy-e1")) {
+		p_tdm_phy_priv->type = TDM_PHY_E1;
+		printk(KERN_INFO "TDM Phy type: E1\n");
+	} else if (of_device_is_compatible(np, "tdm-phy-t1")) {
+		p_tdm_phy_priv->type = TDM_PHY_T1;
+		printk(KERN_INFO "TDM Phy type: T1\n");
+	} else {
+		printk(KERN_ERR "TDM_PHY: Unknown device type\n");
+		goto err_device_type;
+	}
+
+	p_tdm_phy_priv->device = &spi->dev;
+	p_tdm_phy_priv->phy.np = np;
+	p_tdm_phy_priv->phy.configure_phy = slic_init_configure;
+	phandle_prop = of_get_property(np, "phandle", NULL);
+	if (!phandle_prop)
+		printk(KERN_ERR "Can't get phy handle\n");
+	else {
+		p_tdm_phy_priv->phy.phandle_prop = (void *)phandle_prop;
+		add_tdm_phy(&p_tdm_phy_priv->phy);
+	}
+	spi->bits_per_word = 8;
+
+	if (num_slics >= MAX_NUM_OF_SLICS) {
+		printk(KERN_ERR "Exceeded the max number of slics\n");
+		return ret;
+	}
+
+	/* Initialize the SLIC */
+	configure_spi_pdata(spi);
+	data = spi->dev.platform_data;
+	slic_ch[num_slics].ch1_tx_slot = data->ch1_tx_slot;
+	slic_ch[num_slics].ch1_rx_slot = data->ch1_rx_slot;
+	slic_ch[num_slics].ch2_tx_slot = data->ch2_tx_slot;
+	slic_ch[num_slics].ch2_rx_slot = data->ch2_rx_slot;
+
+err_device_type:
+	kfree(p_tdm_phy_priv);
+err_alloc:
+	return ret;
+}
+
+static const struct of_device_id slic_match[] = {
+	{
+	 .compatible = "zarlink,le88266",
+	 },
+	{},
+};
+
+static struct spi_driver slic_driver = {
+	.driver = {
+		   .name = "legerity",
+		   .bus = &spi_bus_type,
+		   .owner = THIS_MODULE,
+		   .of_match_table = slic_match,
+		   },
+	.probe = slic_probe,
+	.remove = slic_remove,
+
+};
+
+static int __init slic_init(void)
+{
+	int ret;
+	printk(KERN_INFO "SLIC: " DRV_DESC "\n");
+	printk(KERN_INFO  "####################################################"
+			"\n# This driver was created solely by Freescale,     #"
+			"\n# without the assistance, support or intellectual  #"
+			"\n# property of Zarlink Semiconductor. No            #"
+			"\n# maintenance or support will be provided by       #"
+			"\n# Zarlink  Semiconductor regarding this driver.    #"
+			"\n####################################################"
+		"\n");
+
+	ret = spi_register_driver(&slic_driver);
+	if (ret != 0)
+		printk(KERN_ERR "%s spi_register_driver failed\n",
+							__func__);
+	return ret;
+}
+
+static void __exit slic_exit(void)
+{
+	spi_unregister_driver(&slic_driver);
+}
+
+module_init(slic_init);
+module_exit(slic_exit);
diff --git a/drivers/tdm/line_ctrl/slic_zarlink.h b/drivers/tdm/line_ctrl/slic_zarlink.h
new file mode 100644
index 0000000..1a44590
--- /dev/null
+++ b/drivers/tdm/line_ctrl/slic_zarlink.h
@@ -0,0 +1,131 @@
+/*
+ * drivers/tdm/line/slic_zarlink.h
+ *
+ * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This is the header file for the SLIC  Driver Module
+ * drivers/tdm/line/slic_zarlink.c.
+ *
+ * Author: Rajesh Gumasta<rajesh.gumasta at freescale.com>
+ *
+ * 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, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef SLIC_ZARLINK_H
+#define SLIC_ZARLINK_H
+
+struct slic_platform_data {
+	unsigned int ch1_rx_slot;
+	unsigned int ch1_tx_slot;
+	unsigned int ch2_rx_slot;
+	unsigned int ch2_tx_slot;
+};
+
+/* SLIC channel configuration */
+#define CH1_RX_SLOT_NUM		0
+#define CH1_TX_SLOT_NUM		0
+#define CH2_RX_SLOT_NUM		2
+#define CH2_TX_SLOT_NUM		2
+
+#define SLIC_SLOT_OFFSET	2
+
+/* commands to the SLIC */
+#define CHANNEL1			0x01
+#define CHANNEL2			0x02
+#define HW_RESET			0x04
+#define WRITE_NO_OPERATION		0x06
+#define WRITE_TX_TIME_SLOT		0x40
+#define READ_TX_TIME_SLOT		0x41
+#define WRITE_RX_TIME_SLOT		0x42
+#define READ_RX_TIME_SLOT		0x43
+#define WRITE_TXRXCLKSLOT_TXCLKEDGE	0x44
+#define WRITE_DEVICE_CFG		0x46
+#define READ_DEVICE_CONFIGURATION	0x47
+#define WRITE_CHANNEL_ENABLE		0X4A
+#define WRITE_IO_DATA			0x52
+#define WRITE_IO_DIRECTION		0x54
+#define WRITE_SYSTEM_STATE		0x56
+#define WRITE_OPERATING_FUNCTION	0x60
+#define READ_OPERATING_FUNCTION		0x61
+#define WRITE_SYSTEM_STATE_CFG		0x68
+#define READ_SYSTEM_STATE_CFG		0x69
+#define WRITE_INT_MASK			0x6C
+#define READ_INT_MASK			0x6D
+#define WRITE_OPERATING_CONDITIONS	0x70
+#define READ_PRODUCT_CODE		0X73
+#define WRITE_CONVERTER_CFG		0xA6
+#define WRITE_LOOP_SUPERVISION_PARAMS	0xC2
+#define WRITE_DC_FEED_PARAMS		0xC6
+#define WRITE_CADENCE_TIMER		0xE0
+#define READ_CADENCE_TIMER		0xE1
+#define WRITE_SWITCH_REGULATOR_PARAMS	0xE4
+#define WRITE_SWITCH_REGULATOR_CTRL	0xE6
+#define WRITE_INTERNAL_CFG_REG3		0xF2
+#define WRITE_DC_CALIBRATION		0xFC
+
+/* Dataset1 for no operation command */
+static unsigned char dataset1_for_nooperation[] = {
+					0xca, 0xfa, 0x98, 0xca, 0xb9,
+					0xa2, 0x4c, 0x2b, 0xa2, 0xa3,
+					0xa2, 0xae, 0x2b, 0x9a, 0x23,
+					0xca, 0x26, 0x9f, 0x1,  0x8a,
+					0x1d, 0x1,  0x1,  0x11, 0x1,
+					0x90, 0x1,  0x90, 0x1,  0x90,
+					0x1,  0x90, 0x1,  0x90, 0x88,
+					0xd8, 0x70, 0x7a, 0x87, 0x23,
+					0x3f, 0x4a, 0x97, 0x5a, 0xa7,
+					0x5a, 0xaf, 0x82, 0x22, 0xe0,
+					0x80, 0x32, 0x10, 0x50, 0x10,
+					0x86, 0xa2, 0x63, 0x23, 0xbb,
+					0x2a, 0xa4, 0x29, 0x7d, 0x87,
+					0x2a, 0xfa, 0x8f, 0x29, 0xf0,
+					0x96, 0x2e, 0x1
+};
+
+/* Dataset2 for no operation command */
+static unsigned char dataset2_for_nooperation[] = {
+					0xd2, 0x0,  0x0,  0x0,  0x0,
+					0x36, 0x36, 0xb9, 0x0,  0x0,
+					0x0,  0x0,  0x68, 0x0
+};
+
+/* Dataset3 for no operation command */
+static unsigned char dataset3_for_nooperation[] = {
+					0xc2, 0x1b, 0x84, 0xb4, 0x5,
+					0xc6, 0x8,  0x8
+};
+
+/* Dataset for internal configuration register 3 command */
+static unsigned char dataset_internalCfgReg3[] = {
+					0x10, 0x1,  0x0, 0x0
+};
+
+/* Dataset for cadence timer command */
+static unsigned char dataset_cadenceTimer[] = {
+					0x3f, 0xff, 0x0,  0x0
+};
+
+/* Dataset for Loop parameters command */
+static unsigned char dataset_writeLoopParams[] = {
+					0x1b, 0x84, 0xb3, 0x5
+};
+
+/* Dataset1 for cadence timer command */
+static unsigned char set_cadenceTimer[] = {
+					0x01, 0x90, 0x03, 0x20
+};
+
+#endif
-- 
1.7.6.GIT





More information about the linux-arm-kernel mailing list