linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] misc: adds support the FSA9480 USB Switch
@ 2010-08-31 10:28 Minkyu Kang
       [not found] ` <4C7CD95A.5040309-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Minkyu Kang @ 2010-08-31 10:28 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ

The FSA9480 is a USB port accessory detector and switch.
This patch adds support the FSA9480 USB Switch.

Signed-off-by: Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 drivers/misc/Kconfig    |    9 +
 drivers/misc/Makefile   |    1 +
 drivers/misc/fsa9480.c  |  556 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fsa9480.h |   40 ++++
 4 files changed, 606 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/fsa9480.c
 create mode 100644 include/linux/fsa9480.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0b591b6..191137e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -390,6 +390,15 @@ config BMP085
 	  To compile this driver as a module, choose M here: the
 	  module will be called bmp085.
 
+config USB_SWITCH_FSA9480
+	tristate "FSA9480 USB Switch"
+	depends on I2C
+	help
+	  The FSA9480 is a USB port accessory detector and switch.
+	  The FSA9480 is fully controlled using I2C and enables USB data,
+	  stereo and mono audio, video, microphone and UART data to use
+	  a common connector port.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 255a80d..071b380 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -35,3 +35,4 @@ obj-y				+= eeprom/
 obj-y				+= cb710/
 obj-$(CONFIG_VMWARE_BALLOON)	+= vmware_balloon.o
 obj-$(CONFIG_ARM_CHARLCD)	+= arm-charlcd.o
+obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
new file mode 100644
index 0000000..c140410
--- /dev/null
+++ b/drivers/misc/fsa9480.c
@@ -0,0 +1,556 @@
+/*
+ * fsa9480.c - FSA9480 micro USB switch device driver
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ * Wonguk Jeong <wonguk.jeong-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/fsa9480.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* FSA9480 I2C registers */
+#define FSA9480_REG_DEVID		0x01
+#define FSA9480_REG_CTRL		0x02
+#define FSA9480_REG_INT1		0x03
+#define FSA9480_REG_INT2		0x04
+#define FSA9480_REG_INT1_MASK		0x05
+#define FSA9480_REG_INT2_MASK		0x06
+#define FSA9480_REG_ADC			0x07
+#define FSA9480_REG_TIMING1		0x08
+#define FSA9480_REG_TIMING2		0x09
+#define FSA9480_REG_DEV_T1		0x0a
+#define FSA9480_REG_DEV_T2		0x0b
+#define FSA9480_REG_BTN1		0x0c
+#define FSA9480_REG_BTN2		0x0d
+#define FSA9480_REG_CK			0x0e
+#define FSA9480_REG_CK_INT1		0x0f
+#define FSA9480_REG_CK_INT2		0x10
+#define FSA9480_REG_CK_INTMASK1		0x11
+#define FSA9480_REG_CK_INTMASK2		0x12
+#define FSA9480_REG_MANSW1		0x13
+#define FSA9480_REG_MANSW2		0x14
+
+/* Control */
+#define CON_SWITCH_OPEN		(1 << 4)
+#define CON_RAW_DATA		(1 << 3)
+#define CON_MANUAL_SW		(1 << 2)
+#define CON_WAIT		(1 << 1)
+#define CON_INT_MASK		(1 << 0)
+#define CON_MASK		(CON_SWITCH_OPEN | CON_RAW_DATA | \
+				CON_MANUAL_SW | CON_WAIT)
+
+/* Device Type 1 */
+#define DEV_USB_OTG		(1 << 7)
+#define DEV_DEDICATED_CHG	(1 << 6)
+#define DEV_USB_CHG		(1 << 5)
+#define DEV_CAR_KIT		(1 << 4)
+#define DEV_UART		(1 << 3)
+#define DEV_USB			(1 << 2)
+#define DEV_AUDIO_2		(1 << 1)
+#define DEV_AUDIO_1		(1 << 0)
+
+#define DEV_T1_USB_MASK		(DEV_USB_OTG | DEV_USB)
+#define DEV_T1_UART_MASK	(DEV_UART)
+#define DEV_T1_CHARGER_MASK	(DEV_DEDICATED_CHG | DEV_USB_CHG)
+
+/* Device Type 2 */
+#define DEV_AV			(1 << 6)
+#define DEV_TTY			(1 << 5)
+#define DEV_PPD			(1 << 4)
+#define DEV_JIG_UART_OFF	(1 << 3)
+#define DEV_JIG_UART_ON		(1 << 2)
+#define DEV_JIG_USB_OFF		(1 << 1)
+#define DEV_JIG_USB_ON		(1 << 0)
+
+#define DEV_T2_USB_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
+#define DEV_T2_UART_MASK	(DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+#define DEV_T2_JIG_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
+				DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+
+/*
+ * Manual Switch
+ * D- [7:5] / D+ [4:2]
+ * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
+ */
+#define SW_VAUDIO		((4 << 5) | (4 << 2))
+#define SW_UART			((3 << 5) | (3 << 2))
+#define SW_AUDIO		((2 << 5) | (2 << 2))
+#define SW_DHOST		((1 << 5) | (1 << 2))
+#define SW_AUTO			((0 << 5) | (0 << 2))
+
+/* Interrupt 1 */
+#define INT_DETACH		(1 << 1)
+#define INT_ATTACH		(1 << 0)
+
+struct fsa9480_usbsw {
+	struct i2c_client		*client;
+	struct fsa9480_platform_data	*pdata;
+	struct work_struct		work;
+	int				dev1;
+	int				dev2;
+	int				mansw;
+};
+
+static struct fsa9480_usbsw *chip;
+
+static int fsa9480_write_reg(struct i2c_client *client,
+		int reg, int value)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int fsa9480_read_reg(struct i2c_client *client, int reg)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int fsa9480_read_irq(struct i2c_client *client, int *value)
+{
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(client,
+			FSA9480_REG_INT1, 2, (u8 *)value);
+	*value &= 0xffff;
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+void fsa9480_set_switch(const char *buf)
+{
+	struct fsa9480_usbsw *usbsw = chip;
+	struct i2c_client *client = usbsw->client;
+	unsigned int value;
+	unsigned int path = 0;
+
+	value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
+
+	if (!strncmp(buf, "VAUDIO", 6)) {
+		path = SW_VAUDIO;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "UART", 4)) {
+		path = SW_UART;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "AUDIO", 5)) {
+		path = SW_AUDIO;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "DHOST", 5)) {
+		path = SW_DHOST;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "AUTO", 4)) {
+		path = SW_AUTO;
+		value |= CON_MANUAL_SW;
+	} else {
+		printk(KERN_ERR "Wrong command\n");
+		return;
+	}
+
+	usbsw->mansw = path;
+	fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
+}
+EXPORT_SYMBOL_GPL(fsa9480_set_switch);
+
+ssize_t fsa9480_get_switch(char *buf)
+{
+	struct fsa9480_usbsw *usbsw = chip;
+	struct i2c_client *client = usbsw->client;
+	unsigned int value;
+
+	value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
+
+	if (value == SW_VAUDIO)
+		return sprintf(buf, "VAUDIO\n");
+	else if (value == SW_UART)
+		return sprintf(buf, "UART\n");
+	else if (value == SW_AUDIO)
+		return sprintf(buf, "AUDIO\n");
+	else if (value == SW_DHOST)
+		return sprintf(buf, "DHOST\n");
+	else if (value == SW_AUTO)
+		return sprintf(buf, "AUTO\n");
+	else
+		return sprintf(buf, "%x", value);
+}
+EXPORT_SYMBOL_GPL(fsa9480_get_switch);
+
+static ssize_t fsa9480_show_status(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
+	struct i2c_client *client = usbsw->client;
+	int devid, ctrl, adc, dev1, dev2, intr,
+	    intmask1, intmask2, time1, time2, mansw1;
+
+	devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
+	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
+	adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
+	intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
+	intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
+	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+	time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
+	time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
+	mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
+
+	fsa9480_read_irq(client, &intr);
+
+	return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
+			"ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
+			"INT(%04x), INTMASK(%02x, %02x)\n"
+			"TIMING(%02x, %02x), MANSW1(%02x)\n",
+			devid, ctrl, adc, dev1, dev2, intr,
+			intmask1, intmask2, time1, time2, mansw1);
+}
+
+static ssize_t fsa9480_show_manualsw(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return fsa9480_get_switch(buf);
+
+}
+
+static ssize_t fsa9480_set_manualsw(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	fsa9480_set_switch(buf);
+
+	return count;
+}
+
+static DEVICE_ATTR(status, S_IRUGO, fsa9480_show_status, NULL);
+static DEVICE_ATTR(switch, S_IRUGO | S_IWUGO,
+		fsa9480_show_manualsw, fsa9480_set_manualsw);
+
+static struct attribute *fsa9480_attributes[] = {
+	&dev_attr_status.attr,
+	&dev_attr_switch.attr,
+	NULL
+};
+
+static const struct attribute_group fsa9480_group = {
+	.attrs = fsa9480_attributes,
+};
+
+static irqreturn_t fsa9480_irq_handler(int irq, void *data)
+{
+	struct fsa9480_usbsw *usbsw = data;
+
+	if (!work_pending(&usbsw->work)) {
+		disable_irq_nosync(irq);
+		schedule_work(&usbsw->work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr)
+{
+	int val1, val2, ctrl;
+	struct fsa9480_platform_data *pdata = usbsw->pdata;
+	struct i2c_client *client = usbsw->client;
+
+	val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
+
+	dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n",
+			intr, val1, val2);
+
+	if (!intr)
+		goto out;
+
+	if (intr & INT_ATTACH) {	/* Attached */
+		/* USB */
+		if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) {
+			if (pdata->usb_cb)
+				pdata->usb_cb(FSA9480_ATTACHED);
+
+			if (usbsw->mansw) {
+				fsa9480_write_reg(client,
+					FSA9480_REG_MANSW1, usbsw->mansw);
+			}
+		}
+
+		/* UART */
+		if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) {
+			if (pdata->uart_cb)
+				pdata->uart_cb(FSA9480_ATTACHED);
+
+			if (!(ctrl & CON_MANUAL_SW)) {
+				fsa9480_write_reg(client,
+					FSA9480_REG_MANSW1, SW_UART);
+			}
+		}
+
+		/* CHARGER */
+		if (val1 & DEV_T1_CHARGER_MASK) {
+			if (pdata->charger_cb)
+				pdata->charger_cb(FSA9480_ATTACHED);
+		}
+
+		/* JIG */
+		if (val2 & DEV_T2_JIG_MASK) {
+			if (pdata->jig_cb)
+				pdata->jig_cb(FSA9480_ATTACHED);
+		}
+	} else if (intr & INT_DETACH) {	/* Detached */
+		/* USB */
+		if (usbsw->dev1 & DEV_T1_USB_MASK ||
+			usbsw->dev2 & DEV_T2_USB_MASK) {
+			if (pdata->usb_cb)
+				pdata->usb_cb(FSA9480_DETACHED);
+		}
+
+		/* UART */
+		if (usbsw->dev1 & DEV_T1_UART_MASK ||
+			usbsw->dev2 & DEV_T2_UART_MASK) {
+			if (pdata->uart_cb)
+				pdata->uart_cb(FSA9480_DETACHED);
+		}
+
+		/* CHARGER */
+		if (usbsw->dev1 & DEV_T1_CHARGER_MASK) {
+			if (pdata->charger_cb)
+				pdata->charger_cb(FSA9480_DETACHED);
+		}
+
+		/* JIG */
+		if (usbsw->dev2 & DEV_T2_JIG_MASK) {
+			if (pdata->jig_cb)
+				pdata->jig_cb(FSA9480_DETACHED);
+		}
+	}
+
+	usbsw->dev1 = val1;
+	usbsw->dev2 = val2;
+
+out:
+	ctrl &= ~CON_INT_MASK;
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
+}
+
+static void fsa9480_work_cb(struct work_struct *work)
+{
+	int intr;
+	struct fsa9480_usbsw *usbsw =
+		container_of(work, struct fsa9480_usbsw, work);
+	struct i2c_client *client = usbsw->client;
+
+	/* clear interrupt */
+	fsa9480_read_irq(client, &intr);
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, intr);
+
+	enable_irq(client->irq);
+}
+
+static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw)
+{
+	struct fsa9480_platform_data *pdata = usbsw->pdata;
+	struct i2c_client *client = usbsw->client;
+	int ret;
+	int intr;
+	unsigned int ctrl = CON_MASK;
+
+	/* clear interrupt */
+	fsa9480_read_irq(client, &intr);
+
+	/* unmask interrupt (attach/detach only) */
+	fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc);
+	fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f);
+
+	usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
+
+	if (usbsw->mansw)
+		ctrl &= ~CON_MANUAL_SW;	/* Manual Switching Mode */
+
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
+
+	INIT_WORK(&usbsw->work, fsa9480_work_cb);
+
+	if (pdata && pdata->cfg_gpio)
+		pdata->cfg_gpio();
+
+	if (client->irq) {
+		ret = request_irq(client->irq, fsa9480_irq_handler,
+				IRQF_TRIGGER_LOW | IRQF_DISABLED,
+				"fsa9480 micro USB", usbsw);
+		if (ret) {
+			dev_err(&client->dev, "failed to reqeust IRQ\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int __devinit fsa9480_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct fsa9480_usbsw *usbsw;
+	int ret = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL);
+	if (!usbsw) {
+		dev_err(&client->dev, "failed to allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	usbsw->client = client;
+	usbsw->pdata = client->dev.platform_data;
+
+	chip = usbsw;
+
+	i2c_set_clientdata(client, usbsw);
+
+	ret = fsa9480_irq_init(usbsw);
+	if (ret)
+		goto fail1;
+
+	ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group);
+	if (ret) {
+		dev_err(&client->dev,
+				"failed to create fsa9480 attribute group\n");
+		goto fail2;
+	}
+
+	/* ADC Detect Time: 500ms */
+	fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6);
+
+	if (chip->pdata->reset_cb)
+		chip->pdata->reset_cb();
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, INT_ATTACH);
+
+	return 0;
+
+fail2:
+	if (client->irq)
+		free_irq(client->irq, NULL);
+fail1:
+	i2c_set_clientdata(client, NULL);
+	kfree(usbsw);
+	return ret;
+}
+
+static int __devexit fsa9480_remove(struct i2c_client *client)
+{
+	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
+	if (client->irq)
+		free_irq(client->irq, NULL);
+	i2c_set_clientdata(client, NULL);
+
+	sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
+	kfree(usbsw);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
+{
+	return 0;
+}
+
+static int fsa9480_resume(struct i2c_client *client)
+{
+	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
+	int dev1, dev2;
+
+	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH);
+
+	return 0;
+}
+
+#else
+
+#define fsa9480_suspend NULL
+#define fsa9480_resume NULL
+
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id fsa9480_id[] = {
+	{"fsa9480", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, fsa9480_id);
+
+static struct i2c_driver fsa9480_i2c_driver = {
+	.driver = {
+		.name = "fsa9480",
+	},
+	.probe = fsa9480_probe,
+	.remove = __devexit_p(fsa9480_remove),
+	.resume = fsa9480_resume,
+	.suspend = fsa9480_suspend,
+	.id_table = fsa9480_id,
+};
+
+static int __init fsa9480_init(void)
+{
+	return i2c_add_driver(&fsa9480_i2c_driver);
+}
+module_init(fsa9480_init);
+
+static void __exit fsa9480_exit(void)
+{
+	i2c_del_driver(&fsa9480_i2c_driver);
+}
+module_exit(fsa9480_exit);
+
+MODULE_AUTHOR("Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_DESCRIPTION("FSA9480 USB Switch driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fsa9480.h b/include/linux/fsa9480.h
new file mode 100644
index 0000000..5a2c00f
--- /dev/null
+++ b/include/linux/fsa9480.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ * Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ * Wonguk Jeong <wonguk.jeong-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef _FSA9480_H_
+#define _FSA9480_H_
+
+#define FSA9480_ATTACHED	1
+#define FSA9480_DETACHED	0
+
+struct fsa9480_platform_data {
+	void (*cfg_gpio) (void);
+	void (*usb_cb) (u8 attached);
+	void (*uart_cb) (u8 attached);
+	void (*charger_cb) (u8 attached);
+	void (*jig_cb) (u8 attached);
+	void (*reset_cb) (void);
+};
+
+void fsa9480_set_switch(const char *buf);
+ssize_t fsa9480_get_switch(char *buf);
+
+#endif /* _FSA9480_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] misc: adds support the FSA9480 USB Switch
       [not found] ` <4C7CD95A.5040309-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
@ 2010-09-17 22:07   ` Andrew Morton
  2010-09-17 22:44     ` Greg KH
                       ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Andrew Morton @ 2010-09-17 22:07 UTC (permalink / raw)
  To: Minkyu Kang
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Greg KH

(catching up!)

On Tue, 31 Aug 2010 19:28:42 +0900
Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:

> The FSA9480 is a USB port accessory detector and switch.
> This patch adds support the FSA9480 USB Switch.
> 

What a strange device.

Is there a data sheet available?

> +config USB_SWITCH_FSA9480
> +	tristate "FSA9480 USB Switch"
> +	depends on I2C
> +	help
> +	  The FSA9480 is a USB port accessory detector and switch.
> +	  The FSA9480 is fully controlled using I2C and enables USB data,
> +	  stereo and mono audio, video, microphone and UART data to use
> +	  a common connector port.

So if I'm understanding it correctly, it's an i2c-controlled device
which turns USB devices on and off, multiplexing them into a single USB
port?  So if I switch from "USB data" over to "microphone", the USB
subsystem will see the "USB data" device get unplugged and will see a
"microphone" get plugged in?

Or something else.  Am I even vaguely understanding this thing?

It would help if the changelog were to contain a paragraph
describing the overall behaviour of this device.

>
> ...
>
> +void fsa9480_set_switch(const char *buf)
> +{
> +	struct fsa9480_usbsw *usbsw = chip;
> +	struct i2c_client *client = usbsw->client;
> +	unsigned int value;
> +	unsigned int path = 0;
> +
> +	value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
> +
> +	if (!strncmp(buf, "VAUDIO", 6)) {
> +		path = SW_VAUDIO;
> +		value &= ~CON_MANUAL_SW;
> +	} else if (!strncmp(buf, "UART", 4)) {
> +		path = SW_UART;
> +		value &= ~CON_MANUAL_SW;
> +	} else if (!strncmp(buf, "AUDIO", 5)) {
> +		path = SW_AUDIO;
> +		value &= ~CON_MANUAL_SW;
> +	} else if (!strncmp(buf, "DHOST", 5)) {
> +		path = SW_DHOST;
> +		value &= ~CON_MANUAL_SW;
> +	} else if (!strncmp(buf, "AUTO", 4)) {
> +		path = SW_AUTO;
> +		value |= CON_MANUAL_SW;
> +	} else {
> +		printk(KERN_ERR "Wrong command\n");
> +		return;
> +	}
> +
> +	usbsw->mansw = path;
> +	fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
> +	fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
> +}
> +EXPORT_SYMBOL_GPL(fsa9480_set_switch);

Why was this exported?

> +ssize_t fsa9480_get_switch(char *buf)
> +{
> +	struct fsa9480_usbsw *usbsw = chip;
> +	struct i2c_client *client = usbsw->client;
> +	unsigned int value;
> +
> +	value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
> +
> +	if (value == SW_VAUDIO)
> +		return sprintf(buf, "VAUDIO\n");
> +	else if (value == SW_UART)
> +		return sprintf(buf, "UART\n");
> +	else if (value == SW_AUDIO)
> +		return sprintf(buf, "AUDIO\n");
> +	else if (value == SW_DHOST)
> +		return sprintf(buf, "DHOST\n");
> +	else if (value == SW_AUTO)
> +		return sprintf(buf, "AUTO\n");
> +	else
> +		return sprintf(buf, "%x", value);
> +}
> +EXPORT_SYMBOL_GPL(fsa9480_get_switch);

This export also has no callers?

These functions implement a userspace API.  Userspace APIs are
important.  But the patch provided no documentation for that API. 
Please always fully, exhaustively document userspace APIs!  For they
are the one part of the driver which we can never change.

Documenting them in a documentation file is OK.  Also there's
Documentation/ABI/.  And they can be nicely described in the changelog
too.

But providing us with no description at all makes review harder and
less effective than we'd like it to be, and results in a driver which
is harder for our users to use.

OK?

> +static ssize_t fsa9480_show_status(struct device *dev,
> +				   struct device_attribute *attr,
> +				   char *buf)
> +{
> +	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
> +	struct i2c_client *client = usbsw->client;
> +	int devid, ctrl, adc, dev1, dev2, intr,
> +	    intmask1, intmask2, time1, time2, mansw1;
> +
> +	devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
> +	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
> +	adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
> +	intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
> +	intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
> +	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
> +	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
> +	time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
> +	time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
> +	mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
> +
> +	fsa9480_read_irq(client, &intr);
> +
> +	return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
> +			"ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
> +			"INT(%04x), INTMASK(%02x, %02x)\n"
> +			"TIMING(%02x, %02x), MANSW1(%02x)\n",
> +			devid, ctrl, adc, dev1, dev2, intr,
> +			intmask1, intmask2, time1, time2, mansw1);
> +}

That's will produce odd-looking output I suspect.  More conventional
would be

	Device ID:%02x CTRL:%02x

or something like that.

But that result is basically unparseable by software and a better output
would be

Device_ID: %02x
CTRL: %02x
ADC: %02x

etc.

But even that violates the sysfs one-value-per-file guideline.

So this interface is problematic.  It should have been discussed
up-front in the changelog so we can all take a look at the proposal and
have a think about it.

>
> ...
>
> +static irqreturn_t fsa9480_irq_handler(int irq, void *data)
> +{
> +	struct fsa9480_usbsw *usbsw = data;
> +
> +	if (!work_pending(&usbsw->work)) {
> +		disable_irq_nosync(irq);
> +		schedule_work(&usbsw->work);
> +	}
> +
> +	return IRQ_HANDLED;
> +}

I expect that this driver can be converted to the new threaded IRQ code
(request_threaded_irq) and it will all become simpler.

>
> ...
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] misc: adds support the FSA9480 USB Switch
  2010-09-17 22:07   ` Andrew Morton
@ 2010-09-17 22:44     ` Greg KH
  2010-09-18  2:47     ` Kyungmin Park
       [not found]     ` <20100917150731.f1f44f3c.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2010-09-17 22:44 UTC (permalink / raw)
  To: Andrew Morton, Minkyu Kang, linux-kernel, linux-i2c,
	kyungmin.park

On Fri, Sep 17, 2010 at 03:07:31PM -0700, Andrew Morton wrote:
> > +static ssize_t fsa9480_show_status(struct device *dev,
> > +				   struct device_attribute *attr,
> > +				   char *buf)
> > +{
> > +	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
> > +	struct i2c_client *client = usbsw->client;
> > +	int devid, ctrl, adc, dev1, dev2, intr,
> > +	    intmask1, intmask2, time1, time2, mansw1;
> > +
> > +	devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
> > +	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
> > +	adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
> > +	intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
> > +	intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
> > +	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
> > +	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
> > +	time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
> > +	time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
> > +	mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
> > +
> > +	fsa9480_read_irq(client, &intr);
> > +
> > +	return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
> > +			"ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
> > +			"INT(%04x), INTMASK(%02x, %02x)\n"
> > +			"TIMING(%02x, %02x), MANSW1(%02x)\n",
> > +			devid, ctrl, adc, dev1, dev2, intr,
> > +			intmask1, intmask2, time1, time2, mansw1);
> > +}
> 
> That's will produce odd-looking output I suspect.  More conventional
> would be
> 
> 	Device ID:%02x CTRL:%02x
> 
> or something like that.
> 
> But that result is basically unparseable by software and a better output
> would be
> 
> Device_ID: %02x
> CTRL: %02x
> ADC: %02x
> 
> etc.
> 
> But even that violates the sysfs one-value-per-file guideline.
> 
> So this interface is problematic.  It should have been discussed
> up-front in the changelog so we can all take a look at the proposal and
> have a think about it.

Yes, such a sysfs file is not allowed, please just have individual sysfs
files for these attribute types (device id, control, adc, etc.)

And are you sure they are even needed?  Some of those are already known
through the i2c interface, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] misc: adds support the FSA9480 USB Switch
       [not found]     ` <20100917150731.f1f44f3c.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
@ 2010-09-18  1:37       ` Ben Dooks
  2010-09-28  5:58       ` Minkyu Kang
  1 sibling, 0 replies; 11+ messages in thread
From: Ben Dooks @ 2010-09-18  1:37 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Minkyu Kang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Greg KH

On Fri, Sep 17, 2010 at 03:07:31PM -0700, Andrew Morton wrote:
> (catching up!)
> 
> On Tue, 31 Aug 2010 19:28:42 +0900
> Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
> 
> > The FSA9480 is a USB port accessory detector and switch.
> > This patch adds support the FSA9480 USB Switch.
> > 
> 
> What a strange device.
> 
> Is there a data sheet available?
> 
> > +config USB_SWITCH_FSA9480
> > +	tristate "FSA9480 USB Switch"
> > +	depends on I2C
> > +	help
> > +	  The FSA9480 is a USB port accessory detector and switch.
> > +	  The FSA9480 is fully controlled using I2C and enables USB data,
> > +	  stereo and mono audio, video, microphone and UART data to use
> > +	  a common connector port.
> 
> So if I'm understanding it correctly, it's an i2c-controlled device
> which turns USB devices on and off, multiplexing them into a single USB
> port?  So if I switch from "USB data" over to "microphone", the USB
> subsystem will see the "USB data" device get unplugged and will see a
> "microphone" get plugged in?

It is generally for 'smart phones' where one connector has to do many
jobs. Basically it's a electrical switch which allows one set of lines
on a connector to be electrically connected to either the USB, or one
of a number of analogue functions.

Often this is helped by the connector having some form of detect line
which tells you what is plugged in, such as a headset, usb cable, etc.
 
> Or something else.  Am I even vaguely understanding this thing?
> 
> It would help if the changelog were to contain a paragraph
> describing the overall behaviour of this device.
> 
> >
> > ...
> >
> > +void fsa9480_set_switch(const char *buf)
> > +{
> > +	struct fsa9480_usbsw *usbsw = chip;
> > +	struct i2c_client *client = usbsw->client;
> > +	unsigned int value;
> > +	unsigned int path = 0;
> > +
> > +	value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
> > +
> > +	if (!strncmp(buf, "VAUDIO", 6)) {
> > +		path = SW_VAUDIO;
> > +		value &= ~CON_MANUAL_SW;
> > +	} else if (!strncmp(buf, "UART", 4)) {
> > +		path = SW_UART;
> > +		value &= ~CON_MANUAL_SW;
> > +	} else if (!strncmp(buf, "AUDIO", 5)) {
> > +		path = SW_AUDIO;
> > +		value &= ~CON_MANUAL_SW;
> > +	} else if (!strncmp(buf, "DHOST", 5)) {
> > +		path = SW_DHOST;
> > +		value &= ~CON_MANUAL_SW;
> > +	} else if (!strncmp(buf, "AUTO", 4)) {
> > +		path = SW_AUTO;
> > +		value |= CON_MANUAL_SW;
> > +	} else {
> > +		printk(KERN_ERR "Wrong command\n");
> > +		return;
> > +	}
> > +
> > +	usbsw->mansw = path;
> > +	fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
> > +	fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
> > +}
> > +EXPORT_SYMBOL_GPL(fsa9480_set_switch);
> 
> Why was this exported?
> 
> > +ssize_t fsa9480_get_switch(char *buf)
> > +{
> > +	struct fsa9480_usbsw *usbsw = chip;
> > +	struct i2c_client *client = usbsw->client;
> > +	unsigned int value;
> > +
> > +	value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
> > +
> > +	if (value == SW_VAUDIO)
> > +		return sprintf(buf, "VAUDIO\n");
> > +	else if (value == SW_UART)
> > +		return sprintf(buf, "UART\n");
> > +	else if (value == SW_AUDIO)
> > +		return sprintf(buf, "AUDIO\n");
> > +	else if (value == SW_DHOST)
> > +		return sprintf(buf, "DHOST\n");
> > +	else if (value == SW_AUTO)
> > +		return sprintf(buf, "AUTO\n");
> > +	else
> > +		return sprintf(buf, "%x", value);
> > +}
> > +EXPORT_SYMBOL_GPL(fsa9480_get_switch);
> 
> This export also has no callers?
> 
> These functions implement a userspace API.  Userspace APIs are
> important.  But the patch provided no documentation for that API. 
> Please always fully, exhaustively document userspace APIs!  For they
> are the one part of the driver which we can never change.
> 
> Documenting them in a documentation file is OK.  Also there's
> Documentation/ABI/.  And they can be nicely described in the changelog
> too.
> 
> But providing us with no description at all makes review harder and
> less effective than we'd like it to be, and results in a driver which
> is harder for our users to use.
> 
> OK?
> 
> > +static ssize_t fsa9480_show_status(struct device *dev,
> > +				   struct device_attribute *attr,
> > +				   char *buf)
> > +{
> > +	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
> > +	struct i2c_client *client = usbsw->client;
> > +	int devid, ctrl, adc, dev1, dev2, intr,
> > +	    intmask1, intmask2, time1, time2, mansw1;
> > +
> > +	devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
> > +	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
> > +	adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
> > +	intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
> > +	intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
> > +	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
> > +	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
> > +	time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
> > +	time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
> > +	mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
> > +
> > +	fsa9480_read_irq(client, &intr);
> > +
> > +	return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
> > +			"ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
> > +			"INT(%04x), INTMASK(%02x, %02x)\n"
> > +			"TIMING(%02x, %02x), MANSW1(%02x)\n",
> > +			devid, ctrl, adc, dev1, dev2, intr,
> > +			intmask1, intmask2, time1, time2, mansw1);
> > +}
> 
> That's will produce odd-looking output I suspect.  More conventional
> would be
> 
> 	Device ID:%02x CTRL:%02x
> 
> or something like that.
> 
> But that result is basically unparseable by software and a better output
> would be
> 
> Device_ID: %02x
> CTRL: %02x
> ADC: %02x
> 
> etc.
> 
> But even that violates the sysfs one-value-per-file guideline.
> 
> So this interface is problematic.  It should have been discussed
> up-front in the changelog so we can all take a look at the proposal and
> have a think about it.
> 
> >
> > ...
> >
> > +static irqreturn_t fsa9480_irq_handler(int irq, void *data)
> > +{
> > +	struct fsa9480_usbsw *usbsw = data;
> > +
> > +	if (!work_pending(&usbsw->work)) {
> > +		disable_irq_nosync(irq);
> > +		schedule_work(&usbsw->work);
> > +	}
> > +
> > +	return IRQ_HANDLED;
> > +}
> 
> I expect that this driver can be converted to the new threaded IRQ code
> (request_threaded_irq) and it will all become simpler.
> 
> >
> > ...
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
-- 
Ben

Q:      What's a light-year?
A:      One-third less calories than a regular year.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] misc: adds support the FSA9480 USB Switch
  2010-09-17 22:07   ` Andrew Morton
  2010-09-17 22:44     ` Greg KH
@ 2010-09-18  2:47     ` Kyungmin Park
       [not found]     ` <20100917150731.f1f44f3c.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2 siblings, 0 replies; 11+ messages in thread
From: Kyungmin Park @ 2010-09-18  2:47 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Minkyu Kang, linux-kernel, linux-i2c, Greg KH

On Sat, Sep 18, 2010 at 7:07 AM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> (catching up!)
>
> On Tue, 31 Aug 2010 19:28:42 +0900
> Minkyu Kang <mk7.kang@samsung.com> wrote:
>
>> The FSA9480 is a USB port accessory detector and switch.
>> This patch adds support the FSA9480 USB Switch.
>>
>
> What a strange device.
>
As Minkyu Kang is on holiday until 9/27. I reply it instead. he will
give more information when returned.
I just explain the how to work and what's the purpose to export functions.

> Is there a data sheet available?

It's difficult to find it at web, I'll check it but maybe difficult.

>
>> +config USB_SWITCH_FSA9480
>> +     tristate "FSA9480 USB Switch"
>> +     depends on I2C
>> +     help
>> +       The FSA9480 is a USB port accessory detector and switch.
>> +       The FSA9480 is fully controlled using I2C and enables USB data,
>> +       stereo and mono audio, video, microphone and UART data to use
>> +       a common connector port.
>
> So if I'm understanding it correctly, it's an i2c-controlled device
> which turns USB devices on and off, multiplexing them into a single USB
> port?  So if I switch from "USB data" over to "microphone", the USB
> subsystem will see the "USB data" device get unplugged and will see a
> "microphone" get plugged in?

When connect the usb cable, then read USB ID(?) or something and
switch the mux automatically.
e.g, when you connect the car kit then it switch the path to car kit.
Can't turn off the USB devices. only switch the USB path.

>
> Or something else.  Am I even vaguely understanding this thing?
>
> It would help if the changelog were to contain a paragraph
> describing the overall behaviour of this device.
>
>>
>> ...
>>
>> +void fsa9480_set_switch(const char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = chip;
>> +     struct i2c_client *client = usbsw->client;
>> +     unsigned int value;
>> +     unsigned int path = 0;
>> +
>> +     value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
>> +
>> +     if (!strncmp(buf, "VAUDIO", 6)) {
>> +             path = SW_VAUDIO;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "UART", 4)) {
>> +             path = SW_UART;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "AUDIO", 5)) {
>> +             path = SW_AUDIO;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "DHOST", 5)) {
>> +             path = SW_DHOST;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "AUTO", 4)) {
>> +             path = SW_AUTO;
>> +             value |= CON_MANUAL_SW;
>> +     } else {
>> +             printk(KERN_ERR "Wrong command\n");
>> +             return;
>> +     }
>> +
>> +     usbsw->mansw = path;
>> +     fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
>> +     fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
>> +}
>> +EXPORT_SYMBOL_GPL(fsa9480_set_switch);
To Minkyu, It's should be EXPORT_SYMBOL???
>
> Why was this exported?

Even though it switch the USB path automatically, we don't use the
full path for each purpose.
e.g., we don't use the V(ideo)Audio or Audio. it's connected it for
other purpose.
In this case we switch it by manually by MAN(ual) Switch register.

>
>> +ssize_t fsa9480_get_switch(char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = chip;
>> +     struct i2c_client *client = usbsw->client;
>> +     unsigned int value;
>> +
>> +     value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
>> +
>> +     if (value == SW_VAUDIO)
>> +             return sprintf(buf, "VAUDIO\n");
>> +     else if (value == SW_UART)
>> +             return sprintf(buf, "UART\n");
>> +     else if (value == SW_AUDIO)
>> +             return sprintf(buf, "AUDIO\n");
>> +     else if (value == SW_DHOST)
>> +             return sprintf(buf, "DHOST\n");
>> +     else if (value == SW_AUTO)
>> +             return sprintf(buf, "AUTO\n");
>> +     else
>> +             return sprintf(buf, "%x", value);
>> +}
>> +EXPORT_SYMBOL_GPL(fsa9480_get_switch);
>
> This export also has no callers?
It's used check what's the current switch status at other drivers.

Thank you,
Kyungmin Park
>
> These functions implement a userspace API.  Userspace APIs are
> important.  But the patch provided no documentation for that API.
> Please always fully, exhaustively document userspace APIs!  For they
> are the one part of the driver which we can never change.
>
> Documenting them in a documentation file is OK.  Also there's
> Documentation/ABI/.  And they can be nicely described in the changelog
> too.
>
> But providing us with no description at all makes review harder and
> less effective than we'd like it to be, and results in a driver which
> is harder for our users to use.
>
> OK?
>
>> +static ssize_t fsa9480_show_status(struct device *dev,
>> +                                struct device_attribute *attr,
>> +                                char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
>> +     struct i2c_client *client = usbsw->client;
>> +     int devid, ctrl, adc, dev1, dev2, intr,
>> +         intmask1, intmask2, time1, time2, mansw1;
>> +
>> +     devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
>> +     ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
>> +     adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
>> +     intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
>> +     intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
>> +     dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
>> +     dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
>> +     time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
>> +     time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
>> +     mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
>> +
>> +     fsa9480_read_irq(client, &intr);
>> +
>> +     return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
>> +                     "ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
>> +                     "INT(%04x), INTMASK(%02x, %02x)\n"
>> +                     "TIMING(%02x, %02x), MANSW1(%02x)\n",
>> +                     devid, ctrl, adc, dev1, dev2, intr,
>> +                     intmask1, intmask2, time1, time2, mansw1);
>> +}
>
> That's will produce odd-looking output I suspect.  More conventional
> would be
>
>        Device ID:%02x CTRL:%02x
>
> or something like that.
>
> But that result is basically unparseable by software and a better output
> would be
>
> Device_ID: %02x
> CTRL: %02x
> ADC: %02x
>
> etc.
>
> But even that violates the sysfs one-value-per-file guideline.
>
> So this interface is problematic.  It should have been discussed
> up-front in the changelog so we can all take a look at the proposal and
> have a think about it.
>
>>
>> ...
>>
>> +static irqreturn_t fsa9480_irq_handler(int irq, void *data)
>> +{
>> +     struct fsa9480_usbsw *usbsw = data;
>> +
>> +     if (!work_pending(&usbsw->work)) {
>> +             disable_irq_nosync(irq);
>> +             schedule_work(&usbsw->work);
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>
> I expect that this driver can be converted to the new threaded IRQ code
> (request_threaded_irq) and it will all become simpler.
>
>>
>> ...
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] misc: adds support the FSA9480 USB Switch
       [not found]     ` <20100917150731.f1f44f3c.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2010-09-18  1:37       ` Ben Dooks
@ 2010-09-28  5:58       ` Minkyu Kang
       [not found]         ` <AANLkTim2UhJAhOw1qHvZ9bbctR0tNSMvE61T=sxffHxO-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  1 sibling, 1 reply; 11+ messages in thread
From: Minkyu Kang @ 2010-09-28  5:58 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Minkyu Kang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Greg KH, Ben Dooks

Dear Andrew Morton,

On 18 September 2010 07:07, Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org> wrote:
> (catching up!)
>
> On Tue, 31 Aug 2010 19:28:42 +0900
> Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> wrote:
>
>> The FSA9480 is a USB port accessory detector and switch.
>> This patch adds support the FSA9480 USB Switch.
>>
>
> What a strange device.
>
> Is there a data sheet available?

Hello :)
I couldn't find the fsa9480 data sheet on the web.
But I found the fsa9280 data sheet instead.
It looks very similar.
http://www.fairchildsemi.com/ds/FS/FSA9280A.pdf

>
>> +config USB_SWITCH_FSA9480
>> +     tristate "FSA9480 USB Switch"
>> +     depends on I2C
>> +     help
>> +       The FSA9480 is a USB port accessory detector and switch.
>> +       The FSA9480 is fully controlled using I2C and enables USB data,
>> +       stereo and mono audio, video, microphone and UART data to use
>> +       a common connector port.
>
> So if I'm understanding it correctly, it's an i2c-controlled device
> which turns USB devices on and off, multiplexing them into a single USB
> port?  So if I switch from "USB data" over to "microphone", the USB
> subsystem will see the "USB data" device get unplugged and will see a
> "microphone" get plugged in?
>
> Or something else.  Am I even vaguely understanding this thing?
>
> It would help if the changelog were to contain a paragraph
> describing the overall behaviour of this device.
>
>>
>> ...
>>
>> +void fsa9480_set_switch(const char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = chip;
>> +     struct i2c_client *client = usbsw->client;
>> +     unsigned int value;
>> +     unsigned int path = 0;
>> +
>> +     value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
>> +
>> +     if (!strncmp(buf, "VAUDIO", 6)) {
>> +             path = SW_VAUDIO;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "UART", 4)) {
>> +             path = SW_UART;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "AUDIO", 5)) {
>> +             path = SW_AUDIO;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "DHOST", 5)) {
>> +             path = SW_DHOST;
>> +             value &= ~CON_MANUAL_SW;
>> +     } else if (!strncmp(buf, "AUTO", 4)) {
>> +             path = SW_AUTO;
>> +             value |= CON_MANUAL_SW;
>> +     } else {
>> +             printk(KERN_ERR "Wrong command\n");
>> +             return;
>> +     }
>> +
>> +     usbsw->mansw = path;
>> +     fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
>> +     fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
>> +}
>> +EXPORT_SYMBOL_GPL(fsa9480_set_switch);
>
> Why was this exported?

Kyungmin already explained about it.

>
>> +ssize_t fsa9480_get_switch(char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = chip;
>> +     struct i2c_client *client = usbsw->client;
>> +     unsigned int value;
>> +
>> +     value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
>> +
>> +     if (value == SW_VAUDIO)
>> +             return sprintf(buf, "VAUDIO\n");
>> +     else if (value == SW_UART)
>> +             return sprintf(buf, "UART\n");
>> +     else if (value == SW_AUDIO)
>> +             return sprintf(buf, "AUDIO\n");
>> +     else if (value == SW_DHOST)
>> +             return sprintf(buf, "DHOST\n");
>> +     else if (value == SW_AUTO)
>> +             return sprintf(buf, "AUTO\n");
>> +     else
>> +             return sprintf(buf, "%x", value);
>> +}
>> +EXPORT_SYMBOL_GPL(fsa9480_get_switch);
>
> This export also has no callers?

It's for other drivers.
For example.. When USB cable is connected, PMIC driver enable the
power for each device.
But if use the manual switch, PMIC driver can't know what device is enabled.
So, this function was exported.

>
> These functions implement a userspace API.  Userspace APIs are
> important.  But the patch provided no documentation for that API.
> Please always fully, exhaustively document userspace APIs!  For they
> are the one part of the driver which we can never change.
>
> Documenting them in a documentation file is OK.  Also there's
> Documentation/ABI/.  And they can be nicely described in the changelog
> too.
>
> But providing us with no description at all makes review harder and
> less effective than we'd like it to be, and results in a driver which
> is harder for our users to use.
>
> OK?
>
>> +static ssize_t fsa9480_show_status(struct device *dev,
>> +                                struct device_attribute *attr,
>> +                                char *buf)
>> +{
>> +     struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
>> +     struct i2c_client *client = usbsw->client;
>> +     int devid, ctrl, adc, dev1, dev2, intr,
>> +         intmask1, intmask2, time1, time2, mansw1;
>> +
>> +     devid = fsa9480_read_reg(client, FSA9480_REG_DEVID);
>> +     ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
>> +     adc = fsa9480_read_reg(client, FSA9480_REG_ADC);
>> +     intmask1 = fsa9480_read_reg(client, FSA9480_REG_INT1_MASK);
>> +     intmask2 = fsa9480_read_reg(client, FSA9480_REG_INT2_MASK);
>> +     dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
>> +     dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
>> +     time1 = fsa9480_read_reg(client, FSA9480_REG_TIMING1);
>> +     time2 = fsa9480_read_reg(client, FSA9480_REG_TIMING2);
>> +     mansw1 = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
>> +
>> +     fsa9480_read_irq(client, &intr);
>> +
>> +     return sprintf(buf, "Device ID(%02x), CTRL(%02x)\n"
>> +                     "ADC(%02x), DEV_T1(%02x), DEV_T2(%02x)\n"
>> +                     "INT(%04x), INTMASK(%02x, %02x)\n"
>> +                     "TIMING(%02x, %02x), MANSW1(%02x)\n",
>> +                     devid, ctrl, adc, dev1, dev2, intr,
>> +                     intmask1, intmask2, time1, time2, mansw1);
>> +}
>
> That's will produce odd-looking output I suspect.  More conventional
> would be
>
>        Device ID:%02x CTRL:%02x
>
> or something like that.
>
> But that result is basically unparseable by software and a better output
> would be
>
> Device_ID: %02x
> CTRL: %02x
> ADC: %02x
>
> etc.
>
> But even that violates the sysfs one-value-per-file guideline.
>
> So this interface is problematic.  It should have been discussed
> up-front in the changelog so we can all take a look at the proposal and
> have a think about it.

Yes. It's for debugging.
I'll remove some features and separate this sysfs file.

>
>>
>> ...
>>
>> +static irqreturn_t fsa9480_irq_handler(int irq, void *data)
>> +{
>> +     struct fsa9480_usbsw *usbsw = data;
>> +
>> +     if (!work_pending(&usbsw->work)) {
>> +             disable_irq_nosync(irq);
>> +             schedule_work(&usbsw->work);
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>
> I expect that this driver can be converted to the new threaded IRQ code
> (request_threaded_irq) and it will all become simpler.

Ok, I'll convert to new IRQ code.

>
>>
>> ...
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

Thanks
Minkyu Kang.
-- 
from. prom.
www.promsoft.net

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2] misc: adds support the FSA9480 USB Switch
       [not found]         ` <AANLkTim2UhJAhOw1qHvZ9bbctR0tNSMvE61T=sxffHxO-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-10-11  1:32           ` Minkyu Kang
  2010-10-11 17:36             ` Greg KH
  0 siblings, 1 reply; 11+ messages in thread
From: Minkyu Kang @ 2010-10-11  1:32 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA
  Cc: Andrew Morton, kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Greg KH,
	Ben Dooks

The FSA9480 is a USB port accessory detector and switch.
This patch adds support the FSA9480 USB Switch.

Signed-off-by: Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
v2:
 use the threaded irq
 fix the sysfs

 drivers/misc/Kconfig    |    9 +
 drivers/misc/Makefile   |    1 +
 drivers/misc/fsa9480.c  |  544 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fsa9480.h |   40 ++++
 4 files changed, 594 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/fsa9480.c
 create mode 100644 include/linux/fsa9480.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b743312..bfd7ef7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -390,6 +390,15 @@ config BMP085
 	  To compile this driver as a module, choose M here: the
 	  module will be called bmp085.
 
+config USB_SWITCH_FSA9480
+	tristate "FSA9480 USB Switch"
+	depends on I2C
+	help
+	  The FSA9480 is a USB port accessory detector and switch.
+	  The FSA9480 is fully controlled using I2C and enables USB data,
+	  stereo and mono audio, video, microphone and UART data to use
+	  a common connector port.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 42eab95..f1e9bf8 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -35,3 +35,4 @@ obj-y				+= eeprom/
 obj-y				+= cb710/
 obj-$(CONFIG_VMWARE_BALLOON)	+= vmw_balloon.o
 obj-$(CONFIG_ARM_CHARLCD)	+= arm-charlcd.o
+obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
new file mode 100644
index 0000000..1abf6de
--- /dev/null
+++ b/drivers/misc/fsa9480.c
@@ -0,0 +1,544 @@
+/*
+ * fsa9480.c - FSA9480 micro USB switch device driver
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ * Wonguk Jeong <wonguk.jeong-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/fsa9480.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* FSA9480 I2C registers */
+#define FSA9480_REG_DEVID		0x01
+#define FSA9480_REG_CTRL		0x02
+#define FSA9480_REG_INT1		0x03
+#define FSA9480_REG_INT2		0x04
+#define FSA9480_REG_INT1_MASK		0x05
+#define FSA9480_REG_INT2_MASK		0x06
+#define FSA9480_REG_ADC			0x07
+#define FSA9480_REG_TIMING1		0x08
+#define FSA9480_REG_TIMING2		0x09
+#define FSA9480_REG_DEV_T1		0x0a
+#define FSA9480_REG_DEV_T2		0x0b
+#define FSA9480_REG_BTN1		0x0c
+#define FSA9480_REG_BTN2		0x0d
+#define FSA9480_REG_CK			0x0e
+#define FSA9480_REG_CK_INT1		0x0f
+#define FSA9480_REG_CK_INT2		0x10
+#define FSA9480_REG_CK_INTMASK1		0x11
+#define FSA9480_REG_CK_INTMASK2		0x12
+#define FSA9480_REG_MANSW1		0x13
+#define FSA9480_REG_MANSW2		0x14
+
+/* Control */
+#define CON_SWITCH_OPEN		(1 << 4)
+#define CON_RAW_DATA		(1 << 3)
+#define CON_MANUAL_SW		(1 << 2)
+#define CON_WAIT		(1 << 1)
+#define CON_INT_MASK		(1 << 0)
+#define CON_MASK		(CON_SWITCH_OPEN | CON_RAW_DATA | \
+				CON_MANUAL_SW | CON_WAIT)
+
+/* Device Type 1 */
+#define DEV_USB_OTG		(1 << 7)
+#define DEV_DEDICATED_CHG	(1 << 6)
+#define DEV_USB_CHG		(1 << 5)
+#define DEV_CAR_KIT		(1 << 4)
+#define DEV_UART		(1 << 3)
+#define DEV_USB			(1 << 2)
+#define DEV_AUDIO_2		(1 << 1)
+#define DEV_AUDIO_1		(1 << 0)
+
+#define DEV_T1_USB_MASK		(DEV_USB_OTG | DEV_USB)
+#define DEV_T1_UART_MASK	(DEV_UART)
+#define DEV_T1_CHARGER_MASK	(DEV_DEDICATED_CHG | DEV_USB_CHG)
+
+/* Device Type 2 */
+#define DEV_AV			(1 << 6)
+#define DEV_TTY			(1 << 5)
+#define DEV_PPD			(1 << 4)
+#define DEV_JIG_UART_OFF	(1 << 3)
+#define DEV_JIG_UART_ON		(1 << 2)
+#define DEV_JIG_USB_OFF		(1 << 1)
+#define DEV_JIG_USB_ON		(1 << 0)
+
+#define DEV_T2_USB_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON)
+#define DEV_T2_UART_MASK	(DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+#define DEV_T2_JIG_MASK		(DEV_JIG_USB_OFF | DEV_JIG_USB_ON | \
+				DEV_JIG_UART_OFF | DEV_JIG_UART_ON)
+
+/*
+ * Manual Switch
+ * D- [7:5] / D+ [4:2]
+ * 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100: V_AUDIO
+ */
+#define SW_VAUDIO		((4 << 5) | (4 << 2))
+#define SW_UART			((3 << 5) | (3 << 2))
+#define SW_AUDIO		((2 << 5) | (2 << 2))
+#define SW_DHOST		((1 << 5) | (1 << 2))
+#define SW_AUTO			((0 << 5) | (0 << 2))
+
+/* Interrupt 1 */
+#define INT_DETACH		(1 << 1)
+#define INT_ATTACH		(1 << 0)
+
+struct fsa9480_usbsw {
+	struct i2c_client		*client;
+	struct fsa9480_platform_data	*pdata;
+	int				dev1;
+	int				dev2;
+	int				mansw;
+};
+
+static struct fsa9480_usbsw *chip;
+
+static int fsa9480_write_reg(struct i2c_client *client,
+		int reg, int value)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int fsa9480_read_reg(struct i2c_client *client, int reg)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int fsa9480_read_irq(struct i2c_client *client, int *value)
+{
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(client,
+			FSA9480_REG_INT1, 2, (u8 *)value);
+	*value &= 0xffff;
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+void fsa9480_set_switch(const char *buf)
+{
+	struct fsa9480_usbsw *usbsw = chip;
+	struct i2c_client *client = usbsw->client;
+	unsigned int value;
+	unsigned int path = 0;
+
+	value = fsa9480_read_reg(client, FSA9480_REG_CTRL);
+
+	if (!strncmp(buf, "VAUDIO", 6)) {
+		path = SW_VAUDIO;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "UART", 4)) {
+		path = SW_UART;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "AUDIO", 5)) {
+		path = SW_AUDIO;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "DHOST", 5)) {
+		path = SW_DHOST;
+		value &= ~CON_MANUAL_SW;
+	} else if (!strncmp(buf, "AUTO", 4)) {
+		path = SW_AUTO;
+		value |= CON_MANUAL_SW;
+	} else {
+		printk(KERN_ERR "Wrong command\n");
+		return;
+	}
+
+	usbsw->mansw = path;
+	fsa9480_write_reg(client, FSA9480_REG_MANSW1, path);
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, value);
+}
+EXPORT_SYMBOL(fsa9480_set_switch);
+
+ssize_t fsa9480_get_switch(char *buf)
+{
+	struct fsa9480_usbsw *usbsw = chip;
+	struct i2c_client *client = usbsw->client;
+	unsigned int value;
+
+	value = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
+
+	if (value == SW_VAUDIO)
+		return sprintf(buf, "VAUDIO\n");
+	else if (value == SW_UART)
+		return sprintf(buf, "UART\n");
+	else if (value == SW_AUDIO)
+		return sprintf(buf, "AUDIO\n");
+	else if (value == SW_DHOST)
+		return sprintf(buf, "DHOST\n");
+	else if (value == SW_AUTO)
+		return sprintf(buf, "AUTO\n");
+	else
+		return sprintf(buf, "%x", value);
+}
+EXPORT_SYMBOL(fsa9480_get_switch);
+
+static ssize_t fsa9480_show_device(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+	struct fsa9480_usbsw *usbsw = dev_get_drvdata(dev);
+	struct i2c_client *client = usbsw->client;
+	int dev1, dev2;
+
+	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+
+	if (!dev1 && !dev2)
+		return sprintf(buf, "NONE\n");
+
+	/* USB */
+	if (dev1 & DEV_T1_USB_MASK || dev2 & DEV_T2_USB_MASK)
+		return sprintf(buf, "USB\n");
+
+	/* UART */
+	if (dev1 & DEV_T1_UART_MASK || dev2 & DEV_T2_UART_MASK)
+		return sprintf(buf, "UART\n");
+
+	/* CHARGER */
+	if (dev1 & DEV_T1_CHARGER_MASK)
+		return sprintf(buf, "CHARGER\n");
+
+	/* JIG */
+	if (dev2 & DEV_T2_JIG_MASK)
+		return sprintf(buf, "JIG\n");
+
+	return sprintf(buf, "UNKNOWN\n");
+}
+
+static ssize_t fsa9480_show_manualsw(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return fsa9480_get_switch(buf);
+
+}
+
+static ssize_t fsa9480_set_manualsw(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	fsa9480_set_switch(buf);
+
+	return count;
+}
+
+static DEVICE_ATTR(device, S_IRUGO, fsa9480_show_device, NULL);
+static DEVICE_ATTR(switch, S_IRUGO | S_IWUGO,
+		fsa9480_show_manualsw, fsa9480_set_manualsw);
+
+static struct attribute *fsa9480_attributes[] = {
+	&dev_attr_device.attr,
+	&dev_attr_switch.attr,
+	NULL
+};
+
+static const struct attribute_group fsa9480_group = {
+	.attrs = fsa9480_attributes,
+};
+
+static void fsa9480_detect_dev(struct fsa9480_usbsw *usbsw, int intr)
+{
+	int val1, val2, ctrl;
+	struct fsa9480_platform_data *pdata = usbsw->pdata;
+	struct i2c_client *client = usbsw->client;
+
+	val1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	val2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+	ctrl = fsa9480_read_reg(client, FSA9480_REG_CTRL);
+
+	dev_info(&client->dev, "intr: 0x%x, dev1: 0x%x, dev2: 0x%x\n",
+			intr, val1, val2);
+
+	if (!intr)
+		goto out;
+
+	if (intr & INT_ATTACH) {	/* Attached */
+		/* USB */
+		if (val1 & DEV_T1_USB_MASK || val2 & DEV_T2_USB_MASK) {
+			if (pdata->usb_cb)
+				pdata->usb_cb(FSA9480_ATTACHED);
+
+			if (usbsw->mansw) {
+				fsa9480_write_reg(client,
+					FSA9480_REG_MANSW1, usbsw->mansw);
+			}
+		}
+
+		/* UART */
+		if (val1 & DEV_T1_UART_MASK || val2 & DEV_T2_UART_MASK) {
+			if (pdata->uart_cb)
+				pdata->uart_cb(FSA9480_ATTACHED);
+
+			if (!(ctrl & CON_MANUAL_SW)) {
+				fsa9480_write_reg(client,
+					FSA9480_REG_MANSW1, SW_UART);
+			}
+		}
+
+		/* CHARGER */
+		if (val1 & DEV_T1_CHARGER_MASK) {
+			if (pdata->charger_cb)
+				pdata->charger_cb(FSA9480_ATTACHED);
+		}
+
+		/* JIG */
+		if (val2 & DEV_T2_JIG_MASK) {
+			if (pdata->jig_cb)
+				pdata->jig_cb(FSA9480_ATTACHED);
+		}
+	} else if (intr & INT_DETACH) {	/* Detached */
+		/* USB */
+		if (usbsw->dev1 & DEV_T1_USB_MASK ||
+			usbsw->dev2 & DEV_T2_USB_MASK) {
+			if (pdata->usb_cb)
+				pdata->usb_cb(FSA9480_DETACHED);
+		}
+
+		/* UART */
+		if (usbsw->dev1 & DEV_T1_UART_MASK ||
+			usbsw->dev2 & DEV_T2_UART_MASK) {
+			if (pdata->uart_cb)
+				pdata->uart_cb(FSA9480_DETACHED);
+		}
+
+		/* CHARGER */
+		if (usbsw->dev1 & DEV_T1_CHARGER_MASK) {
+			if (pdata->charger_cb)
+				pdata->charger_cb(FSA9480_DETACHED);
+		}
+
+		/* JIG */
+		if (usbsw->dev2 & DEV_T2_JIG_MASK) {
+			if (pdata->jig_cb)
+				pdata->jig_cb(FSA9480_DETACHED);
+		}
+	}
+
+	usbsw->dev1 = val1;
+	usbsw->dev2 = val2;
+
+out:
+	ctrl &= ~CON_INT_MASK;
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
+}
+
+static irqreturn_t fsa9480_irq_handler(int irq, void *data)
+{
+	struct fsa9480_usbsw *usbsw = data;
+	struct i2c_client *client = usbsw->client;
+	int intr;
+
+	/* clear interrupt */
+	fsa9480_read_irq(client, &intr);
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, intr);
+
+	return IRQ_HANDLED;
+}
+
+static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw)
+{
+	struct fsa9480_platform_data *pdata = usbsw->pdata;
+	struct i2c_client *client = usbsw->client;
+	int ret;
+	int intr;
+	unsigned int ctrl = CON_MASK;
+
+	/* clear interrupt */
+	fsa9480_read_irq(client, &intr);
+
+	/* unmask interrupt (attach/detach only) */
+	fsa9480_write_reg(client, FSA9480_REG_INT1_MASK, 0xfc);
+	fsa9480_write_reg(client, FSA9480_REG_INT2_MASK, 0x1f);
+
+	usbsw->mansw = fsa9480_read_reg(client, FSA9480_REG_MANSW1);
+
+	if (usbsw->mansw)
+		ctrl &= ~CON_MANUAL_SW;	/* Manual Switching Mode */
+
+	fsa9480_write_reg(client, FSA9480_REG_CTRL, ctrl);
+
+	if (pdata && pdata->cfg_gpio)
+		pdata->cfg_gpio();
+
+	if (client->irq) {
+		ret = request_threaded_irq(client->irq, NULL,
+				fsa9480_irq_handler,
+				IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				"fsa9480 micro USB", usbsw);
+		if (ret) {
+			dev_err(&client->dev, "failed to reqeust IRQ\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int __devinit fsa9480_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct fsa9480_usbsw *usbsw;
+	int ret = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	usbsw = kzalloc(sizeof(struct fsa9480_usbsw), GFP_KERNEL);
+	if (!usbsw) {
+		dev_err(&client->dev, "failed to allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	usbsw->client = client;
+	usbsw->pdata = client->dev.platform_data;
+
+	chip = usbsw;
+
+	i2c_set_clientdata(client, usbsw);
+
+	ret = fsa9480_irq_init(usbsw);
+	if (ret)
+		goto fail1;
+
+	ret = sysfs_create_group(&client->dev.kobj, &fsa9480_group);
+	if (ret) {
+		dev_err(&client->dev,
+				"failed to create fsa9480 attribute group\n");
+		goto fail2;
+	}
+
+	/* ADC Detect Time: 500ms */
+	fsa9480_write_reg(client, FSA9480_REG_TIMING1, 0x6);
+
+	if (chip->pdata->reset_cb)
+		chip->pdata->reset_cb();
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, INT_ATTACH);
+
+	return 0;
+
+fail2:
+	if (client->irq)
+		free_irq(client->irq, NULL);
+fail1:
+	i2c_set_clientdata(client, NULL);
+	kfree(usbsw);
+	return ret;
+}
+
+static int __devexit fsa9480_remove(struct i2c_client *client)
+{
+	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
+	if (client->irq)
+		free_irq(client->irq, NULL);
+	i2c_set_clientdata(client, NULL);
+
+	sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
+	kfree(usbsw);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
+{
+	return 0;
+}
+
+static int fsa9480_resume(struct i2c_client *client)
+{
+	struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
+	int dev1, dev2;
+
+	dev1 = fsa9480_read_reg(client, FSA9480_REG_DEV_T1);
+	dev2 = fsa9480_read_reg(client, FSA9480_REG_DEV_T2);
+
+	/* device detection */
+	fsa9480_detect_dev(usbsw, (dev1 || dev2) ? INT_ATTACH : INT_DETACH);
+
+	return 0;
+}
+
+#else
+
+#define fsa9480_suspend NULL
+#define fsa9480_resume NULL
+
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id fsa9480_id[] = {
+	{"fsa9480", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, fsa9480_id);
+
+static struct i2c_driver fsa9480_i2c_driver = {
+	.driver = {
+		.name = "fsa9480",
+	},
+	.probe = fsa9480_probe,
+	.remove = __devexit_p(fsa9480_remove),
+	.resume = fsa9480_resume,
+	.suspend = fsa9480_suspend,
+	.id_table = fsa9480_id,
+};
+
+static int __init fsa9480_init(void)
+{
+	return i2c_add_driver(&fsa9480_i2c_driver);
+}
+module_init(fsa9480_init);
+
+static void __exit fsa9480_exit(void)
+{
+	i2c_del_driver(&fsa9480_i2c_driver);
+}
+module_exit(fsa9480_exit);
+
+MODULE_AUTHOR("Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_DESCRIPTION("FSA9480 USB Switch driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fsa9480.h b/include/linux/fsa9480.h
new file mode 100644
index 0000000..5a2c00f
--- /dev/null
+++ b/include/linux/fsa9480.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ * Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ * Wonguk Jeong <wonguk.jeong-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef _FSA9480_H_
+#define _FSA9480_H_
+
+#define FSA9480_ATTACHED	1
+#define FSA9480_DETACHED	0
+
+struct fsa9480_platform_data {
+	void (*cfg_gpio) (void);
+	void (*usb_cb) (u8 attached);
+	void (*uart_cb) (u8 attached);
+	void (*charger_cb) (u8 attached);
+	void (*jig_cb) (u8 attached);
+	void (*reset_cb) (void);
+};
+
+void fsa9480_set_switch(const char *buf);
+ssize_t fsa9480_get_switch(char *buf);
+
+#endif /* _FSA9480_H_ */
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] misc: adds support the FSA9480 USB Switch
  2010-10-11  1:32           ` [PATCH v2] " Minkyu Kang
@ 2010-10-11 17:36             ` Greg KH
       [not found]               ` <20101011173649.GC7116-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Greg KH @ 2010-10-11 17:36 UTC (permalink / raw)
  To: Minkyu Kang
  Cc: linux-kernel, linux-i2c, Andrew Morton, kyungmin.park, Ben Dooks

On Mon, Oct 11, 2010 at 10:32:33AM +0900, Minkyu Kang wrote:
> The FSA9480 is a USB port accessory detector and switch.
> This patch adds support the FSA9480 USB Switch.
> 
> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> v2:
>  use the threaded irq
>  fix the sysfs
> 
>  drivers/misc/Kconfig    |    9 +
>  drivers/misc/Makefile   |    1 +
>  drivers/misc/fsa9480.c  |  544 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fsa9480.h |   40 ++++

Why do you need a .h file here for a single driver?

You are creating new sysfs files, so you are required to add a new
Documentation/ABI file as well, please add that to this patch.

And why are you exporting symbols from this driver, that should not be
needed at all.


> +/*
> + * fsa9480.c - FSA9480 micro USB switch device driver
> + *
> + * Copyright (C) 2010 Samsung Electronics
> + * Minkyu Kang <mk7.kang@samsung.com>
> + * Wonguk Jeong <wonguk.jeong@samsung.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.

Are you positive about that "any later version" portion of this?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] misc: adds support the FSA9480 USB Switch
       [not found]               ` <20101011173649.GC7116-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
@ 2010-11-10  0:55                 ` Minkyu Kang
       [not found]                   ` <AANLkTi=vTkHJJ2dq5RZHHCwWYEBtY=Y7dPPh=Wzzx95f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Minkyu Kang @ 2010-11-10  0:55 UTC (permalink / raw)
  To: Greg KH
  Cc: Minkyu Kang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Ben Dooks

Dear Greg KH,

On 12 October 2010 02:36, Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Oct 11, 2010 at 10:32:33AM +0900, Minkyu Kang wrote:
>> The FSA9480 is a USB port accessory detector and switch.
>> This patch adds support the FSA9480 USB Switch.
>>
>> Signed-off-by: Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>> v2:
>>  use the threaded irq
>>  fix the sysfs
>>
>>  drivers/misc/Kconfig    |    9 +
>>  drivers/misc/Makefile   |    1 +
>>  drivers/misc/fsa9480.c  |  544 +++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/fsa9480.h |   40 ++++
>
> Why do you need a .h file here for a single driver?

Because of platform data.

>
> You are creating new sysfs files, so you are required to add a new
> Documentation/ABI file as well, please add that to this patch.

ok.

>
> And why are you exporting symbols from this driver, that should not be
> needed at all.

It's for other drivers.
For example.. When USB cable is connected, PMIC driver enable the
power for each device. (USB, uart, audio and so on..)
But if use the manual switch, PMIC driver can't know what device is enabled.
So, this function was exported.

>
>
>> +/*
>> + * fsa9480.c - FSA9480 micro USB switch device driver
>> + *
>> + * Copyright (C) 2010 Samsung Electronics
>> + * Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> + * Wonguk Jeong <wonguk.jeong-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> + *
>> + * 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.
>
> Are you positive about that "any later version" portion of this?

I will update the licence.

>
> thanks,
>
> greg k-h
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

Thanks
Minkyu Kang
-- 
from. prom.
www.promsoft.net

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] misc: adds support the FSA9480 USB Switch
       [not found]                   ` <AANLkTi=vTkHJJ2dq5RZHHCwWYEBtY=Y7dPPh=Wzzx95f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2010-11-10 14:31                     ` Mark Brown
  2010-11-10 17:49                     ` Greg KH
  1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2010-11-10 14:31 UTC (permalink / raw)
  To: Minkyu Kang
  Cc: Greg KH, Minkyu Kang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Ben Dooks

On Wed, Nov 10, 2010 at 09:55:34AM +0900, Minkyu Kang wrote:
> Dear Greg KH,

> > And why are you exporting symbols from this driver, that should not be
> > needed at all.

> It's for other drivers.
> For example.. When USB cable is connected, PMIC driver enable the
> power for each device. (USB, uart, audio and so on..)
> But if use the manual switch, PMIC driver can't know what device is enabled.
> So, this function was exported.

This seems like it would require the PMIC driver to have knowledge of
the USB switch driver which would be likely to give a system which is
rather board specific.  For PMIC supply management integration the
regulator API would be more normal.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] misc: adds support the FSA9480 USB Switch
       [not found]                   ` <AANLkTi=vTkHJJ2dq5RZHHCwWYEBtY=Y7dPPh=Wzzx95f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2010-11-10 14:31                     ` Mark Brown
@ 2010-11-10 17:49                     ` Greg KH
  1 sibling, 0 replies; 11+ messages in thread
From: Greg KH @ 2010-11-10 17:49 UTC (permalink / raw)
  To: Minkyu Kang
  Cc: Minkyu Kang, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Ben Dooks

On Wed, Nov 10, 2010 at 09:55:34AM +0900, Minkyu Kang wrote:
> Dear Greg KH,
> 
> On 12 October 2010 02:36, Greg KH <greg-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org> wrote:
> > On Mon, Oct 11, 2010 at 10:32:33AM +0900, Minkyu Kang wrote:
> >> The FSA9480 is a USB port accessory detector and switch.
> >> This patch adds support the FSA9480 USB Switch.
> >>
> >> Signed-off-by: Minkyu Kang <mk7.kang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> ---
> >> v2:
> >> ?use the threaded irq
> >> ?fix the sysfs
> >>
> >> ?drivers/misc/Kconfig ? ?| ? ?9 +
> >> ?drivers/misc/Makefile ? | ? ?1 +
> >> ?drivers/misc/fsa9480.c ?| ?544 +++++++++++++++++++++++++++++++++++++++++++++++
> >> ?include/linux/fsa9480.h | ? 40 ++++
> >
> > Why do you need a .h file here for a single driver?
> 
> Because of platform data.

Then put it in include/linux/platform_data/ instead please.

> > You are creating new sysfs files, so you are required to add a new
> > Documentation/ABI file as well, please add that to this patch.
> 
> ok.
> 
> >
> > And why are you exporting symbols from this driver, that should not be
> > needed at all.
> 
> It's for other drivers.
> For example.. When USB cable is connected, PMIC driver enable the
> power for each device. (USB, uart, audio and so on..)
> But if use the manual switch, PMIC driver can't know what device is enabled.
> So, this function was exported.

What drivers are using these functions?  Where is the code for them?
When will they be submitted for inclusion?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-11-10 17:49 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-31 10:28 [PATCH] misc: adds support the FSA9480 USB Switch Minkyu Kang
     [not found] ` <4C7CD95A.5040309-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2010-09-17 22:07   ` Andrew Morton
2010-09-17 22:44     ` Greg KH
2010-09-18  2:47     ` Kyungmin Park
     [not found]     ` <20100917150731.f1f44f3c.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
2010-09-18  1:37       ` Ben Dooks
2010-09-28  5:58       ` Minkyu Kang
     [not found]         ` <AANLkTim2UhJAhOw1qHvZ9bbctR0tNSMvE61T=sxffHxO-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-10-11  1:32           ` [PATCH v2] " Minkyu Kang
2010-10-11 17:36             ` Greg KH
     [not found]               ` <20101011173649.GC7116-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2010-11-10  0:55                 ` Minkyu Kang
     [not found]                   ` <AANLkTi=vTkHJJ2dq5RZHHCwWYEBtY=Y7dPPh=Wzzx95f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-11-10 14:31                     ` Mark Brown
2010-11-10 17:49                     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).