USB: Add driver for NXP ISP1301 USB transceiver
authorRoland Stigge <stigge@antcom.de>
Sun, 29 Apr 2012 14:47:04 +0000 (16:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 May 2012 17:33:02 +0000 (13:33 -0400)
This new driver registers the NXP ISP1301 chip via the I2C subsystem.  The chip
is the USB transceiver shared by ohci-nxp, lpc32xx_udc (gadget) and
isp1301_omap.

ISP1301 is a very low-level driver that primarily separates out the I2C client
registration of the ISP1301 chip (including instantiation via DT), used by
other drivers, and declares the chip's registers. It's only a helper driver for
some OHCI and USB device drivers.  The driver can be considered as a register
set extension of ohci-nxp, lpc32xx-udc and isp1301_omap, which in turn know
best what to do with the low level functionality (individual ISP1301 registers
and timing, see the different initialization strategies in those drivers).
Those drivers previously internally duplicated ISP1301 register definitions
which is solved by this new isp1301 driver. The ISP1301 registers exposed via
isp1301.h can be accessed by other drivers using it with standard i2c_smbus_*()
accesses.

Following patches let the respective USB host and gadget drivers use this
driver, instead of duplicating ISP1301 handling.

Signed-off-by: Roland Stigge <stigge@antcom.de>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/devicetree/bindings/usb/isp1301.txt [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/phy/Kconfig [new file with mode: 0644]
drivers/usb/phy/Makefile [new file with mode: 0644]
drivers/usb/phy/isp1301.c [new file with mode: 0644]
include/linux/usb/isp1301.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/usb/isp1301.txt b/Documentation/devicetree/bindings/usb/isp1301.txt
new file mode 100644 (file)
index 0000000..5405d99
--- /dev/null
@@ -0,0 +1,25 @@
+* NXP ISP1301 USB transceiver
+
+Required properties:
+- compatible: must be "nxp,isp1301"
+- reg: I2C address of the ISP1301 device
+
+Optional properties of devices using ISP1301:
+- transceiver: phandle of isp1301 - this helps the ISP1301 driver to find the
+               ISP1301 instance associated with the respective USB driver
+
+Example:
+
+       isp1301: usb-transceiver@2c {
+               compatible = "nxp,isp1301";
+               reg = <0x2c>;
+       };
+
+       usbd@31020000 {
+               compatible = "nxp,lpc3220-udc";
+               reg = <0x31020000 0x300>;
+               interrupt-parent = <&mic>;
+               interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+               transceiver = <&isp1301>;
+               status = "okay";
+       };
index 76316a33061b91b48a62a60f6be1b921227c6ed8..4473ae51ddb42c971da4081d5d4ad3cd5687a2ab 100644 (file)
@@ -177,6 +177,8 @@ source "drivers/usb/serial/Kconfig"
 
 source "drivers/usb/misc/Kconfig"
 
+source "drivers/usb/phy/Kconfig"
+
 source "drivers/usb/atm/Kconfig"
 
 source "drivers/usb/gadget/Kconfig"
index 53a7bc07dd8d7cd92d8ed940aa09cfb597b8f6d7..77c835a1523926de10c0c1c9dca39d402ff7c29d 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_USB_MICROTEK)    += image/
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
 obj-$(CONFIG_USB)              += misc/
+obj-$(CONFIG_USB)              += phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)        += early/
 
 obj-$(CONFIG_USB_ATM)          += atm/
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
new file mode 100644 (file)
index 0000000..3cfabcb
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Physical Layer USB driver configuration
+#
+comment "USB Physical Layer drivers"
+       depends on USB
+
+config USB_ISP1301
+       tristate "NXP ISP1301 USB transceiver support"
+       depends on USB
+       depends on I2C
+       help
+         Say Y here to add support for the NXP ISP1301 USB transceiver driver.
+         This chip is typically used as USB transceiver for USB host, gadget
+         and OTG drivers (to be selected separately).
+
+         To compile this driver as a module, choose M here: the
+         module will be called isp1301.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644 (file)
index 0000000..eca095b
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for physical layer USB drivers
+#
+
+ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_ISP1301)              += isp1301.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
new file mode 100644 (file)
index 0000000..b19f493
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * This program 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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#define DRV_NAME               "isp1301"
+
+#define ISP1301_I2C_ADDR       0x2C
+
+static const unsigned short normal_i2c[] = {
+       ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id isp1301_id[] = {
+       { "isp1301", 0 },
+       { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int isp1301_probe(struct i2c_client *client,
+                        const struct i2c_device_id *i2c_id)
+{
+       isp1301_i2c_client = client;
+       return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+       .driver = {
+               .name = DRV_NAME,
+       },
+       .probe = isp1301_probe,
+       .remove = isp1301_remove,
+       .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+       struct device_node *node = (struct device_node *)data;
+       return (dev->of_node == node) &&
+               (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+       if (node) { /* reference of ISP1301 I2C node via DT */
+               struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+                                                    node, match);
+               if (!dev)
+                       return NULL;
+               return to_i2c_client(dev);
+       } else { /* non-DT: only one ISP1301 chip supported */
+               return isp1301_i2c_client;
+       }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/isp1301.h b/include/linux/usb/isp1301.h
new file mode 100644 (file)
index 0000000..d3a851c
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_USB_ISP1301_H
+#define __LINUX_USB_ISP1301_H
+
+#include <linux/of.h>
+
+/* I2C Register definitions: */
+
+#define ISP1301_I2C_MODE_CONTROL_1     0x04    /* u8 read, set, +1 clear */
+
+#define MC1_SPEED_REG                  (1 << 0)
+#define MC1_SUSPEND_REG                        (1 << 1)
+#define MC1_DAT_SE0                    (1 << 2)
+#define MC1_TRANSPARENT                        (1 << 3)
+#define MC1_BDIS_ACON_EN               (1 << 4)
+#define MC1_OE_INT_EN                  (1 << 5)
+#define MC1_UART_EN                    (1 << 6)
+#define MC1_MASK                       0x7f
+
+#define ISP1301_I2C_MODE_CONTROL_2     0x12    /* u8 read, set, +1 clear */
+
+#define MC2_GLOBAL_PWR_DN              (1 << 0)
+#define MC2_SPD_SUSP_CTRL              (1 << 1)
+#define MC2_BI_DI                      (1 << 2)
+#define MC2_TRANSP_BDIR0               (1 << 3)
+#define MC2_TRANSP_BDIR1               (1 << 4)
+#define MC2_AUDIO_EN                   (1 << 5)
+#define MC2_PSW_EN                     (1 << 6)
+#define MC2_EN2V7                      (1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_1      0x06    /* u8 read, set, +1 clear */
+
+#define OTG1_DP_PULLUP                 (1 << 0)
+#define OTG1_DM_PULLUP                 (1 << 1)
+#define OTG1_DP_PULLDOWN               (1 << 2)
+#define OTG1_DM_PULLDOWN               (1 << 3)
+#define OTG1_ID_PULLDOWN               (1 << 4)
+#define OTG1_VBUS_DRV                  (1 << 5)
+#define OTG1_VBUS_DISCHRG              (1 << 6)
+#define OTG1_VBUS_CHRG                 (1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_2      0x10    /* u8 readonly */
+
+#define OTG_B_SESS_END                 (1 << 6)
+#define OTG_B_SESS_VLD                 (1 << 7)
+
+#define ISP1301_I2C_INTERRUPT_SOURCE   0x8
+#define ISP1301_I2C_INTERRUPT_LATCH    0xA
+#define ISP1301_I2C_INTERRUPT_FALLING  0xC
+#define ISP1301_I2C_INTERRUPT_RISING   0xE
+
+#define INT_VBUS_VLD                   (1 << 0)
+#define INT_SESS_VLD                   (1 << 1)
+#define INT_DP_HI                      (1 << 2)
+#define INT_ID_GND                     (1 << 3)
+#define INT_DM_HI                      (1 << 4)
+#define INT_ID_FLOAT                   (1 << 5)
+#define INT_BDIS_ACON                  (1 << 6)
+#define INT_CR_INT                     (1 << 7)
+
+#define ISP1301_I2C_REG_CLEAR_ADDR     1       /* Register Address Modifier */
+
+struct i2c_client *isp1301_get_client(struct device_node *node);
+
+#endif /* __LINUX_USB_ISP1301_H */