]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
Add various OMAP SSI drivers
authorTony Lindgren <tony@atomide.com>
Mon, 9 May 2005 21:26:03 +0000 (14:26 -0700)
committerTony Lindgren <tony@atomide.com>
Mon, 9 May 2005 21:26:03 +0000 (14:26 -0700)
Adds various OMAP SSI drivers.

Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/Kconfig
drivers/Kconfig
drivers/ssi/Kconfig [new file with mode: 0644]
drivers/ssi/Makefile [new file with mode: 0644]
drivers/ssi/omap-tsc2101.c [new file with mode: 0644]
drivers/ssi/omap-tsc2101.h [new file with mode: 0644]
drivers/ssi/omap-uwire.c [new file with mode: 0644]
drivers/ssi/omap-uwire.h [new file with mode: 0644]

index 66aa67f67c5cee75d212308c58c5bd34dc9e6db8..708207cdb85f398fd34d6443691bc72b9842402e 100644 (file)
@@ -731,6 +731,8 @@ source "drivers/usb/Kconfig"
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 endmenu
 
 source "fs/Kconfig"
index ed41d9036bfc374c261d3d800bea543f191e3b70..9041f180edcdd7b942980853cffacba32d276b40 100644 (file)
@@ -58,4 +58,6 @@ source "drivers/mmc/Kconfig"
 
 source "drivers/infiniband/Kconfig"
 
+source "drivers/ssi/Kconfig"
+
 endmenu
diff --git a/drivers/ssi/Kconfig b/drivers/ssi/Kconfig
new file mode 100644 (file)
index 0000000..7c80040
--- /dev/null
@@ -0,0 +1,17 @@
+menu "Synchronous Serial Interfaces (SSI)"
+
+config OMAP_UWIRE
+       depends on ARCH_OMAP1
+       tristate "MicroWire support on OMAP"
+       ---help---
+         Say Y here if you want support for the MicroWire interface
+         on an OMAP processor.
+
+config OMAP_TSC2101
+       depends on ARCH_OMAP1 || ARCH_OMAP24XX
+       tristate "TSC2101 codec support for Touchscreen and audio"
+       select OMAP_UWIRE if MACH_OMAP_H3 || MACH_OMAP_H2
+       ---help---
+         Say Y here if you want support for the TSC2101 codec.  It is
+         needed for touchscreen and audio on OMAP1610 and 1710.
+endmenu
diff --git a/drivers/ssi/Makefile b/drivers/ssi/Makefile
new file mode 100644 (file)
index 0000000..c63cf2b
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the SSI drivers
+#
+
+obj-$(CONFIG_OMAP_UWIRE)        += omap-uwire.o
+obj-$(CONFIG_OMAP_TSC2101)      += omap-tsc2101.o
diff --git a/drivers/ssi/omap-tsc2101.c b/drivers/ssi/omap-tsc2101.c
new file mode 100644 (file)
index 0000000..00d2ce5
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.c
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Modified for common hooks for Audio and Touchscreen
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/hardware/tsc2101.h>
+#include <asm/arch/gpioexpander.h>
+
+#include "omap-tsc2101.h"
+
+#if CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#else
+#error "Unsupported configuration"
+#endif
+
+#define SPIO 1
+
+static int count;
+static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED;
+static struct clk  * tsc2101_mclk_ck;
+
+static int omap_tsc2101_configure(void);
+
+/* FIXME: add driver model usage to powerdown the tsc2101 on suspend */
+/* Clock  -Hard coding for the time being */
+#define CLK_SOFT_REQ_REG_BASE  (0xFFFE0800+0x34)
+#define SOFT_COM_MCK0_REQ_MASK (0x1<<6)
+
+int omap_tsc2101_enable(void)
+{
+       int ret = 0;
+
+       spin_lock(&tsc2101_lock);
+       if (count++ == 0) {
+               int ret = 0;
+               /* set the Mux to provide MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_ON);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_ON);
+                       }
+               }
+
+               /* Get the MCLK */
+               tsc2101_mclk_ck = clk_get(NULL, "mclk");
+               if (NULL == tsc2101_mclk_ck) {
+                       printk(KERN_ERR "Unable to get the clock MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               if (clk_set_rate(tsc2101_mclk_ck, 12000000)) {
+                       printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");;
+                       ret = -EPERM;
+                       goto done;
+               }
+               clk_enable(tsc2101_mclk_ck);
+
+               ret = omap_tsc2101_configure();
+
+               /* Lock the module */
+               if (!ret && !try_module_get(THIS_MODULE)) {
+                       printk(KERN_CRIT "Failed to get TSC module\n");
+                       ret = -ESTALE;
+               }
+       }
+
+done:
+       spin_unlock(&tsc2101_lock);
+       return ret;
+}
+
+void omap_tsc2101_disable(void)
+{
+       spin_lock(&tsc2101_lock);
+       if (--count == 0) {
+               int ret = 0;
+               /* Remove the Mux to Stop MCLK to TSC2101 */
+               if (machine_is_omap_h3()) {
+                       ret = omap_cfg_reg(V5_1710_MCLK_OFF);
+               } else {
+                       if (machine_is_omap_h2()) {
+                               ret = omap_cfg_reg(R10_1610_MCLK_OFF);
+                       }
+               }
+
+               /* Release the MCLK */
+               clk_disable(tsc2101_mclk_ck);
+               clk_put(tsc2101_mclk_ck);
+               tsc2101_mclk_ck = NULL;
+
+               module_put(THIS_MODULE);
+       }
+       spin_unlock(&tsc2101_lock);
+}
+
+void omap_tsc2101_write(int page, u8 address, u16 data)
+{
+
+       int ret = 0;
+
+       if (machine_is_omap_h2()) {
+               ret =
+                   omap_uwire_data_transfer(1, 
+                                            (((page) << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(1, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+       if (machine_is_omap_h3()) {
+
+               ret =
+                   omap_uwire_data_transfer(0, ((page << 11) | (address << 5)),
+                                            16, 0, NULL, 1);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+               ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0);
+               if (ret) {
+                       printk(KERN_ERR
+                              "uwire-write returned error for address %x\n",
+                              address);
+                       return;
+               }
+       }
+
+}
+
+void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs)
+{
+       int cs = 0, i;
+       if (machine_is_omap_h2()) {
+               cs = 1;
+       }
+       if (machine_is_omap_h3()) {
+               cs = 0;
+       }
+       (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11)
+                                           | (startaddress << 5)),
+                                      16, 0, NULL, 1);
+       for (i = 0; i < (numregs - 1); i++, data++) {
+               omap_uwire_data_transfer(cs, 0, 0, 16, data, 1);
+       }
+       omap_uwire_data_transfer(cs, 0, 0, 16, data, 0);
+}
+
+u16 omap_tsc2101_read(int page, u8 address)
+{
+       u16 ret;
+       omap_tsc2101_reads(page, address, &ret, 1);
+       return ret;
+}
+
+/* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */
+static int omap_tsc2101_configure(void)
+{
+       unsigned long uwire_flags = 0;
+
+#if CONFIG_MACH_OMAP_H3
+       int err = 0;
+       u8 ioExpanderVal = 0;
+
+       if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) {
+               printk(" Error reading from I/O EXPANDER \n");
+               return err;
+       }
+       ioExpanderVal |= 0x8;
+
+       if ((err = write_gpio_expa(ioExpanderVal, 0x24))) {
+               printk(KERN_ERR ": Error writing to I/O EXPANDER \n");
+               return err;
+       }
+#endif
+
+       if (machine_is_omap_h2()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+               omap_uwire_configure_mode(1, uwire_flags);
+       }
+       if (machine_is_omap_h3()) {
+               uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE;
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_uwire_configure_mode(0, uwire_flags);
+       }
+
+       /* Configure MCLK enable */
+       omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2);  
+
+       return 0;
+}
+
+EXPORT_SYMBOL(omap_tsc2101_enable);
+EXPORT_SYMBOL(omap_tsc2101_read);
+EXPORT_SYMBOL(omap_tsc2101_reads);
+EXPORT_SYMBOL(omap_tsc2101_write);
+EXPORT_SYMBOL(omap_tsc2101_disable);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-tsc2101.h b/drivers/ssi/omap-tsc2101.h
new file mode 100644 (file)
index 0000000..f6b40b8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * linux/drivers/ssi/omap-tsc2101.h
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Provided common hooks for Audio and Touchscreen
+ */
+
+#ifndef __OMAP_TSC2101_H
+#define __OMAP_TSC2101_H
+
+extern u16 omap_tsc2101_read(int page, u8 address);
+extern void omap_tsc2101_reads(int page, u8 startaddress, u16 * data,
+                              int numregs);
+extern void omap_tsc2101_write(int page, u8 address, u16 data);
+
+extern void omap_tsc2101_disable(void);
+extern int omap_tsc2101_enable(void);
+
+#endif
diff --git a/drivers/ssi/omap-uwire.c b/drivers/ssi/omap-uwire.c
new file mode 100644 (file)
index 0000000..b9e182a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     uWire interface driver for the OMAP Platform
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Ported to 2.6 uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjölä <juha.yrjola@nokia.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  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h>  /* OMAP730_IO_CONF registers */
+
+#include "omap-uwire.h"
+
+/* uWire Registers: */
+#define UWIRE_BASE    0xFFFB3000
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR     0x00
+#define UWIRE_RDR     0x00
+#define UWIRE_CSR     0x01
+#define UWIRE_SR1     0x02
+#define UWIRE_SR2     0x03
+#define UWIRE_SR3     0x04
+#define UWIRE_SR4     0x05
+#define UWIRE_SR5     0x06
+
+static unsigned short uwire_flags[4];
+static unsigned long uwire_base = io_p2v(UWIRE_BASE);
+static spinlock_t uwire_lock;
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+       __raw_writew(val, uwire_base + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+       return __raw_readw(uwire_base + (idx << uwire_idx_shift));
+}
+
+void omap_uwire_configure_mode(int cs, unsigned long flags)
+{
+       u16 w, val = 0;
+       int shift, reg;
+
+       BUG_ON(cs > 3);
+
+       val = flags & 0x3f;
+       if (flags & UWIRE_CLK_INVERTED)
+               val ^= 0x03;
+       if (cs & 1)
+               shift = 6;
+       else
+               shift = 0;
+       if (cs <= 1)
+               reg = UWIRE_SR1;
+       else
+               reg = UWIRE_SR2;
+       spin_lock(&uwire_lock);
+       w = uwire_read_reg(reg);
+       w &= ~(0x3f << shift);
+       w |= val << shift;
+       uwire_write_reg(reg, w);
+       spin_unlock(&uwire_lock);
+
+       uwire_flags[cs] = flags;
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+       u16 w;
+       int c = 0;
+       unsigned long max_jiffies = jiffies + HZ;
+
+       for (;;) {
+               w = uwire_read_reg(UWIRE_CSR);
+               if ((w & mask) == val)
+                       break;
+               if (time_after(jiffies, max_jiffies)) {
+                       printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n",
+                              __FUNCTION__, w, mask, val);
+                       return -1;
+               }
+               c++;
+               if (might_not_catch && c > 64)
+                       break;
+       }
+       return 0;
+}
+
+int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size,
+                            u16 *rx_buf, int leave_cs_active)
+{
+       u16 ret = -1, w;
+       u16 mask;
+
+       BUG_ON(cs > 3);
+       BUG_ON(rx_size && !rx_buf);
+
+       spin_lock(&uwire_lock);
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       if (uwire_flags[cs] & UWIRE_CLK_INVERTED)
+               uwire_write_reg(UWIRE_SR4, 1);
+       else
+               uwire_write_reg(UWIRE_SR4, 0);
+
+       w = cs << 10;
+       w |= 1 << 12;                           /* CS_CMD : activate CS */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Shift data to 16bit MSb and place it in TX register. */
+       uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size));
+
+       if (wait_uwire_csr_flag(1 << 14, 0, 0))
+               goto exit;
+
+       w = rx_size | (tx_size << 5) | (cs << 10);
+       w |= (1 << 12) | (1 << 13);
+       /* Start uWire read/write */
+       uwire_write_reg(UWIRE_CSR, w);
+
+       /* Wait till read/write actually starts.
+        * This is needed at high (>=60MHz) MPU frequencies
+        * REVISIT: But occasionally we won't have time to catch it
+        */
+       if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1))
+               goto exit;
+
+       /* Wait for both transfers to be completed */
+       mask = 1 << 14;                 /* CSRB : reg busy */
+       w = 0;
+       if (rx_size) {
+               mask |= 1 << 15;        /* RDRB : reg busy */
+               w |= 1 << 15;
+       }
+
+       if (wait_uwire_csr_flag(mask, w, 0))
+               goto exit;
+
+       if (rx_size)
+               *rx_buf = uwire_read_reg(UWIRE_RDR);
+
+       if (!leave_cs_active)
+               uwire_write_reg(UWIRE_CSR, cs << 10);
+
+       ret = 0;
+
+exit:
+       spin_unlock(&uwire_lock);
+       return ret;
+}
+
+static int __init omap_uwire_init(void)
+{
+       spin_lock_init(&uwire_lock);
+       if (cpu_is_omap730())
+               uwire_idx_shift = 1;
+       else
+               uwire_idx_shift = 2;
+
+       uwire_write_reg(UWIRE_SR3, 1);
+       if (machine_is_omap_h2() || machine_is_omap_osk()) {
+               /* defaults: W21 SDO, U18 SDI, V19 SCL */
+               omap_cfg_reg(N14_1610_UWIRE_CS0);
+               omap_cfg_reg(N15_1610_UWIRE_CS1);
+       }
+       if (machine_is_omap_perseus2()) {
+               /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+               int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+               omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+       }
+       return 0;
+}
+
+static void __exit omap_uwire_exit(void)
+{
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+EXPORT_SYMBOL(omap_uwire_configure_mode);
+EXPORT_SYMBOL(omap_uwire_data_transfer);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ssi/omap-uwire.h b/drivers/ssi/omap-uwire.h
new file mode 100644 (file)
index 0000000..a0d24bc
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ARCH_OMAP_UWIRE_H
+#define __ARCH_OMAP_UWIRE_H
+
+#define UWIRE_READ_FALLING_EDGE                0x0000
+#define UWIRE_READ_RISING_EDGE         0x0001
+#define UWIRE_WRITE_FALLING_EDGE       0x0000
+#define UWIRE_WRITE_RISING_EDGE                0x0002
+#define UWIRE_CS_ACTIVE_LOW            0x0000
+#define UWIRE_CS_ACTIVE_HIGH           0x0004
+#define UWIRE_FREQ_DIV_2               0x0000
+#define UWIRE_FREQ_DIV_4               0x0008
+#define UWIRE_FREQ_DIV_8               0x0010
+#define UWIRE_CHK_READY                        0x0020
+#define UWIRE_CLK_INVERTED             0x0040
+
+/*
+ * uWire for OMAP declarations
+ */
+extern void omap_uwire_configure_mode(int cs, unsigned long flags);
+
+/* NOTE: Make sure you don't call this from an interrupt handler! */
+extern int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size,
+                                   int rx_size, u16 *rx_buf,
+                                   int leave_cs_active);
+
+#endif