summaryrefslogtreecommitdiff
path: root/drivers/extcon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig9
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-arizona.c71
-rw-r--r--drivers/extcon/extcon-max14577.c2
-rw-r--r--drivers/extcon/extcon-max3355.c146
-rw-r--r--drivers/extcon/extcon-max77693.c4
-rw-r--r--drivers/extcon/extcon-max77843.c2
-rw-r--r--drivers/extcon/extcon-rt8973a.c2
8 files changed, 229 insertions, 8 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 0cebbf668..3d89e60a3 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -52,6 +52,15 @@ config EXTCON_MAX14577
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
detector and switch.
+config EXTCON_MAX3355
+ tristate "Maxim MAX3355 USB OTG EXTCON Support"
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ If you say yes here you get support for the USB OTG role detection by
+ MAX3355. The MAX3355 chip integrates a charge pump and comparators to
+ enable a system with an integrated USB OTG dual-role transceiver to
+ function as an USB OTG dual-role device.
+
config EXTCON_MAX77693
tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index ba787d042..2a0e4f45d 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
+obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index e4890dd4f..c121d01a5 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level);
}
-static int arizona_extcon_device_get_pdata(struct arizona *arizona)
+static int arizona_extcon_get_micd_configs(struct device *dev,
+ struct arizona *arizona)
+{
+ const char * const prop = "wlf,micd-configs";
+ const int entries_per_config = 3;
+ struct arizona_micd_config *micd_configs;
+ int nconfs, ret;
+ int i, j;
+ u32 *vals;
+
+ nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0);
+ if (nconfs <= 0)
+ return 0;
+
+ vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
+ if (ret < 0)
+ goto out;
+
+ nconfs /= entries_per_config;
+
+ micd_configs = devm_kzalloc(dev,
+ nconfs * sizeof(struct arizona_micd_range),
+ GFP_KERNEL);
+ if (!micd_configs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, j = 0; i < nconfs; ++i) {
+ micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
+ micd_configs[i].bias = vals[j++];
+ micd_configs[i].gpio = vals[j++];
+ }
+
+ arizona->pdata.micd_configs = micd_configs;
+ arizona->pdata.num_micd_configs = nconfs;
+
+out:
+ kfree(vals);
+ return ret;
+}
+
+static int arizona_extcon_device_get_pdata(struct device *dev,
+ struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+ int ret;
device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
switch (val) {
@@ -1230,12 +1278,29 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona)
device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
&pdata->micd_dbtime);
- device_property_read_u32(arizona->dev, "wlf,micd-timeout",
+ device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
&pdata->micd_timeout);
pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
"wlf,micd-force-micbias");
+ pdata->micd_software_compare = device_property_read_bool(arizona->dev,
+ "wlf,micd-software-compare");
+
+ pdata->jd_invert = device_property_read_bool(arizona->dev,
+ "wlf,jd-invert");
+
+ device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
+
+ pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2");
+ pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
+ "wlf,use-jd2-nopull");
+
+ ret = arizona_extcon_get_micd_configs(dev, arizona);
+ if (ret < 0)
+ dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
+
return 0;
}
@@ -1257,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
return -ENOMEM;
if (!dev_get_platdata(arizona->dev))
- arizona_extcon_device_get_pdata(arizona);
+ arizona_extcon_device_get_pdata(&pdev->dev, arizona);
info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) {
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 601dbd996..b30ab97ce 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
/* Support irq domain for max14577 MUIC device */
for (i = 0; i < info->muic_irqs_num; i++) {
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
if (virq <= 0)
diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
new file mode 100644
index 000000000..c24abec5d
--- /dev/null
+++ b/drivers/extcon/extcon-max3355.c
@@ -0,0 +1,146 @@
+/*
+ * Maxim Integrated MAX3355 USB OTG chip extcon driver
+ *
+ * Copyright (C) 2014-2015 Cogent Embedded, Inc.
+ * Author: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+
+#include <linux/extcon.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct max3355_data {
+ struct extcon_dev *edev;
+ struct gpio_desc *id_gpiod;
+ struct gpio_desc *shdn_gpiod;
+};
+
+static const unsigned int max3355_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+static irqreturn_t max3355_id_irq(int irq, void *dev_id)
+{
+ struct max3355_data *data = dev_id;
+ int id = gpiod_get_value_cansleep(data->id_gpiod);
+
+ if (id) {
+ /*
+ * ID = 1 means USB HOST cable detached.
+ * As we don't have event for USB peripheral cable attached,
+ * we simulate USB peripheral attach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB, true);
+ } else {
+ /*
+ * ID = 0 means USB HOST cable attached.
+ * As we don't have event for USB peripheral cable detached,
+ * we simulate USB peripheral detach here.
+ */
+ extcon_set_cable_state_(data->edev, EXTCON_USB, false);
+ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int max3355_probe(struct platform_device *pdev)
+{
+ struct max3355_data *data;
+ struct gpio_desc *gpiod;
+ int irq, err;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->id_gpiod = gpiod;
+
+ gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod)) {
+ dev_err(&pdev->dev, "failed to get SHDN# GPIO\n");
+ return PTR_ERR(gpiod);
+ }
+ data->shdn_gpiod = gpiod;
+
+ data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable);
+ if (IS_ERR(data->edev)) {
+ dev_err(&pdev->dev, "failed to allocate extcon device\n");
+ return PTR_ERR(data->edev);
+ }
+
+ err = devm_extcon_dev_register(&pdev->dev, data->edev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return err;
+ }
+
+ irq = gpiod_to_irq(data->id_gpiod);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n");
+ return irq;
+ }
+
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND |
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ pdev->name, data);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ /* Perform initial detection */
+ max3355_id_irq(irq, data);
+
+ return 0;
+}
+
+static int max3355_remove(struct platform_device *pdev)
+{
+ struct max3355_data *data = platform_get_drvdata(pdev);
+
+ gpiod_set_value_cansleep(data->shdn_gpiod, 0);
+
+ return 0;
+}
+
+static const struct of_device_id max3355_match_table[] = {
+ { .compatible = "maxim,max3355", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max3355_match_table);
+
+static struct platform_driver max3355_driver = {
+ .probe = max3355_probe,
+ .remove = max3355_remove,
+ .driver = {
+ .name = "extcon-max3355",
+ .of_match_table = max3355_match_table,
+ },
+};
+
+module_platform_driver(max3355_driver);
+
+MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
+MODULE_DESCRIPTION("Maxim MAX3355 extcon driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 44c499e1b..fdf8f5d4d 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
/* Support irq domain for MAX77693 MUIC device */
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max77693_muic_irq *muic_irq = &muic_irqs[i];
- unsigned int virq = 0;
+ int virq;
virq = regmap_irq_get_virq(max77693->irq_data_muic,
muic_irq->irq);
- if (!virq)
+ if (virq <= 0)
return -EINVAL;
muic_irq->virq = virq;
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 9f9ea3343..74dfb7f4f 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i];
- unsigned int virq = 0;
+ int virq = 0;
virq = regmap_irq_get_virq(max77843->irq_data_muic,
muic_irq->irq);
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index 36bf1d637..e1bb82809 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
ret = devm_request_threaded_irq(info->dev, virq, NULL,
rt8973a_muic_irq_handler,
- IRQF_NO_SUSPEND,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
muic_irq->name, info);
if (ret) {
dev_err(info->dev,