* [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).