extcon: max14577: Add support for MAX77836
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>
Mon, 14 Apr 2014 09:17:19 +0000 (11:17 +0200)
committerLee Jones <lee.jones@linaro.org>
Wed, 23 Apr 2014 13:09:25 +0000 (14:09 +0100)
Add support for MAX77836 chipset to the max14577 extcon driver. The
MAX77836 MUIC has additional interrupts (VIDRM, ADC1K) so IRQ handling
is split up into two functions: max14577_parse_irq() and
max77836_parse_irq().

Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/extcon/Kconfig
drivers/extcon/extcon-max14577.c
drivers/mfd/max14577.c
include/linux/mfd/max14577-private.h

index be56e8ac95e6e3d6240ec1039739f0efbaba74e1..aebde489c2914d07173558d0909203d9ffd04ee4 100644 (file)
@@ -28,13 +28,13 @@ config EXTCON_ADC_JACK
          Say Y here to enable extcon device driver based on ADC values.
 
 config EXTCON_MAX14577
-       tristate "MAX14577 EXTCON Support"
+       tristate "MAX14577/77836 EXTCON Support"
        depends on MFD_MAX14577
        select IRQ_DOMAIN
        select REGMAP_I2C
        help
          If you say yes here you get support for the MUIC device of
-         Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
+         Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
          detector and switch.
 
 config EXTCON_MAX77693
index 1513013a92f188471a5a26dc96e4f238ee47e572..c76734a70171756a351167b58601712b0258c4fd 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
+ * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
  *
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
  * Chanwoo Choi <cw00.choi@samsung.com>
+ * Krzysztof Kozlowski <k.kozlowski@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
@@ -62,6 +63,19 @@ static struct max14577_muic_irq max14577_muic_irqs[] = {
        { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
 };
 
+static struct max14577_muic_irq max77836_muic_irqs[] = {
+       { MAX14577_IRQ_INT1_ADC,        "muic-ADC" },
+       { MAX14577_IRQ_INT1_ADCLOW,     "muic-ADCLOW" },
+       { MAX14577_IRQ_INT1_ADCERR,     "muic-ADCError" },
+       { MAX77836_IRQ_INT1_ADC1K,      "muic-ADC1K" },
+       { MAX14577_IRQ_INT2_CHGTYP,     "muic-CHGTYP" },
+       { MAX14577_IRQ_INT2_CHGDETRUN,  "muic-CHGDETRUN" },
+       { MAX14577_IRQ_INT2_DCDTMR,     "muic-DCDTMR" },
+       { MAX14577_IRQ_INT2_DBCHG,      "muic-DBCHG" },
+       { MAX14577_IRQ_INT2_VBVOLT,     "muic-VBVOLT" },
+       { MAX77836_IRQ_INT2_VIDRM,      "muic-VIDRM" },
+};
+
 struct max14577_muic_info {
        struct device *dev;
        struct max14577 *max14577;
@@ -529,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
        return;
 }
 
-static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
 {
-       struct max14577_muic_info *info = data;
-       int i, irq_type = -1;
-
-       /*
-        * We may be called multiple times for different nested IRQ-s.
-        * Including changes in INT1_ADC and INT2_CGHTYP at once.
-        * However we only need to know whether it was ADC, charger
-        * or both interrupts so decode IRQ and turn on proper flags.
-        */
-       for (i = 0; i < info->muic_irqs_num; i++)
-               if (irq == info->muic_irqs[i].virq)
-                       irq_type = info->muic_irqs[i].irq;
-
        switch (irq_type) {
        case MAX14577_IRQ_INT1_ADC:
        case MAX14577_IRQ_INT1_ADCLOW:
@@ -551,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
                /* Handle all of accessory except for
                   type of charger accessory */
                info->irq_adc = true;
-               break;
+               return 1;
        case MAX14577_IRQ_INT2_CHGTYP:
        case MAX14577_IRQ_INT2_CHGDETRUN:
        case MAX14577_IRQ_INT2_DCDTMR:
@@ -559,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
        case MAX14577_IRQ_INT2_VBVOLT:
                /* Handle charger accessory */
                info->irq_chg = true;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
+{
+       /* First check common max14577 interrupts */
+       if (max14577_parse_irq(info, irq_type))
+               return 1;
+
+       switch (irq_type) {
+       case MAX77836_IRQ_INT1_ADC1K:
+               info->irq_adc = true;
+               return 1;
+       case MAX77836_IRQ_INT2_VIDRM:
+               /* Handle charger accessory */
+               info->irq_chg = true;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+{
+       struct max14577_muic_info *info = data;
+       int i, irq_type = -1;
+       bool irq_parsed;
+
+       /*
+        * We may be called multiple times for different nested IRQ-s.
+        * Including changes in INT1_ADC and INT2_CGHTYP at once.
+        * However we only need to know whether it was ADC, charger
+        * or both interrupts so decode IRQ and turn on proper flags.
+        */
+       for (i = 0; i < info->muic_irqs_num; i++)
+               if (irq == info->muic_irqs[i].virq)
+                       irq_type = info->muic_irqs[i].irq;
+
+       switch (info->max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               irq_parsed = max77836_parse_irq(info, irq_type);
                break;
+       case MAXIM_DEVICE_TYPE_MAX14577:
        default:
+               irq_parsed = max14577_parse_irq(info, irq_type);
+               break;
+       }
+
+       if (!irq_parsed) {
                dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
                                irq_type);
                return IRQ_HANDLED;
@@ -646,6 +705,10 @@ static int max14577_muic_probe(struct platform_device *pdev)
        INIT_WORK(&info->irq_work, max14577_muic_irq_work);
 
        switch (max14577->dev_type) {
+       case MAXIM_DEVICE_TYPE_MAX77836:
+               info->muic_irqs = max77836_muic_irqs;
+               info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
+               break;
        case MAXIM_DEVICE_TYPE_MAX14577:
        default:
                info->muic_irqs = max14577_muic_irqs;
@@ -744,6 +807,13 @@ static int max14577_muic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id max14577_muic_id[] = {
+       { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
+       { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_muic_id);
+
 static struct platform_driver max14577_muic_driver = {
        .driver         = {
                .name   = "max14577-muic",
@@ -751,11 +821,12 @@ static struct platform_driver max14577_muic_driver = {
        },
        .probe          = max14577_muic_probe,
        .remove         = max14577_muic_remove,
+       .id_table       = max14577_muic_id,
 };
 
 module_platform_driver(max14577_muic_driver);
 
-MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:extcon-max14577");
index 20e3b2d81bf0d2949117d4f89243b5b10adb6a0e..484d372a4892b642b0f064dd327ee7195e1ae0de 100644 (file)
@@ -147,6 +147,7 @@ static const struct regmap_irq max77836_muic_irqs[] = {
        { .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
        { .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
        { .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
+       { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
        /* INT2 interrupts */
        { .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
        { .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
index e301bd19b06766003cdd3a8de9324ef22a2e91be..a557ae27d8a812d2333dff3ae0150a9722121e2c 100644 (file)
@@ -87,6 +87,7 @@ enum max14577_muic_charger_type {
 #define MAX14577_INT1_ADC_MASK         BIT(0)
 #define MAX14577_INT1_ADCLOW_MASK      BIT(1)
 #define MAX14577_INT1_ADCERR_MASK      BIT(2)
+#define MAX77836_INT1_ADC1K_MASK       BIT(3)
 
 #define MAX14577_INT2_CHGTYP_MASK      BIT(0)
 #define MAX14577_INT2_CHGDETRUN_MASK   BIT(1)
@@ -332,6 +333,7 @@ enum max14577_irq {
        MAX14577_IRQ_INT1_ADC,
        MAX14577_IRQ_INT1_ADCLOW,
        MAX14577_IRQ_INT1_ADCERR,
+       MAX77836_IRQ_INT1_ADC1K,
 
        /* INT2 */
        MAX14577_IRQ_INT2_CHGTYP,
@@ -339,6 +341,7 @@ enum max14577_irq {
        MAX14577_IRQ_INT2_DCDTMR,
        MAX14577_IRQ_INT2_DBCHG,
        MAX14577_IRQ_INT2_VBVOLT,
+       MAX77836_IRQ_INT2_VIDRM,
 
        /* INT3 */
        MAX14577_IRQ_INT3_EOC,