2018-08-07 19:21:22 +03:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
//
|
|
|
|
// extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
|
|
|
|
//
|
|
|
|
// Copyright (C) 2012 Samsung Electronics
|
|
|
|
// Donggeun Kim <dg77.kim@samsung.com>
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/i2c.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/kobject.h>
|
|
|
|
#include <linux/mfd/max8997.h>
|
|
|
|
#include <linux/mfd/max8997-private.h>
|
2017-09-21 06:11:24 +03:00
|
|
|
#include <linux/extcon-provider.h>
|
2012-07-02 04:03:00 +04:00
|
|
|
#include <linux/irqdomain.h>
|
2012-05-09 07:31:58 +04:00
|
|
|
|
|
|
|
#define DEV_NAME "max8997-muic"
|
2013-02-13 10:10:00 +04:00
|
|
|
#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 03:50:00 +04:00
|
|
|
enum max8997_muic_adc_debounce_time {
|
|
|
|
ADC_DEBOUNCE_TIME_0_5MS = 0, /* 0.5ms */
|
|
|
|
ADC_DEBOUNCE_TIME_10MS, /* 10ms */
|
|
|
|
ADC_DEBOUNCE_TIME_25MS, /* 25ms */
|
|
|
|
ADC_DEBOUNCE_TIME_38_62MS, /* 38.62ms */
|
|
|
|
};
|
|
|
|
|
2011-11-24 13:12:18 +04:00
|
|
|
struct max8997_muic_irq {
|
|
|
|
unsigned int irq;
|
|
|
|
const char *name;
|
2012-07-02 04:03:00 +04:00
|
|
|
unsigned int virq;
|
2011-11-24 13:12:18 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct max8997_muic_irq muic_irqs[] = {
|
2013-02-13 07:05:42 +04:00
|
|
|
{ MAX8997_MUICIRQ_ADCError, "muic-ADCERROR" },
|
|
|
|
{ MAX8997_MUICIRQ_ADCLow, "muic-ADCLOW" },
|
|
|
|
{ MAX8997_MUICIRQ_ADC, "muic-ADC" },
|
|
|
|
{ MAX8997_MUICIRQ_VBVolt, "muic-VBVOLT" },
|
|
|
|
{ MAX8997_MUICIRQ_DBChg, "muic-DBCHG" },
|
|
|
|
{ MAX8997_MUICIRQ_DCDTmr, "muic-DCDTMR" },
|
|
|
|
{ MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" },
|
|
|
|
{ MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" },
|
|
|
|
{ MAX8997_MUICIRQ_OVP, "muic-OVP" },
|
2020-12-30 23:51:53 +03:00
|
|
|
{ MAX8997_PMICIRQ_CHGINS, "pmic-CHGINS" },
|
|
|
|
{ MAX8997_PMICIRQ_CHGRM, "pmic-CHGRM" },
|
2013-02-13 07:05:42 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Define supported cable type */
|
|
|
|
enum max8997_muic_acc_type {
|
|
|
|
MAX8997_MUIC_ADC_GROUND = 0x0,
|
|
|
|
MAX8997_MUIC_ADC_MHL, /* MHL*/
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S1_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S2_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S3_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S4_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S5_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S6_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S7_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S8_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S9_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S10_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S11_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_REMOTE_S12_BUTTON,
|
|
|
|
MAX8997_MUIC_ADC_RESERVED_ACC_1,
|
|
|
|
MAX8997_MUIC_ADC_RESERVED_ACC_2,
|
|
|
|
MAX8997_MUIC_ADC_RESERVED_ACC_3,
|
|
|
|
MAX8997_MUIC_ADC_RESERVED_ACC_4,
|
|
|
|
MAX8997_MUIC_ADC_RESERVED_ACC_5,
|
|
|
|
MAX8997_MUIC_ADC_CEA936_AUDIO,
|
|
|
|
MAX8997_MUIC_ADC_PHONE_POWERED_DEV,
|
|
|
|
MAX8997_MUIC_ADC_TTY_CONVERTER,
|
|
|
|
MAX8997_MUIC_ADC_UART_CABLE,
|
|
|
|
MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG,
|
|
|
|
MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF, /* JIG-USB-OFF */
|
|
|
|
MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON, /* JIG-USB-ON */
|
|
|
|
MAX8997_MUIC_ADC_AV_CABLE_NOLOAD, /* DESKDOCK */
|
|
|
|
MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG,
|
|
|
|
MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF, /* JIG-UART */
|
|
|
|
MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON, /* CARDOCK */
|
|
|
|
MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE,
|
|
|
|
MAX8997_MUIC_ADC_OPEN, /* OPEN */
|
|
|
|
};
|
|
|
|
|
|
|
|
enum max8997_muic_cable_group {
|
|
|
|
MAX8997_CABLE_GROUP_ADC = 0,
|
|
|
|
MAX8997_CABLE_GROUP_ADC_GND,
|
|
|
|
MAX8997_CABLE_GROUP_CHG,
|
|
|
|
MAX8997_CABLE_GROUP_VBVOLT,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum max8997_muic_usb_type {
|
|
|
|
MAX8997_USB_HOST,
|
|
|
|
MAX8997_USB_DEVICE,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum max8997_muic_charger_type {
|
|
|
|
MAX8997_CHARGER_TYPE_NONE = 0,
|
|
|
|
MAX8997_CHARGER_TYPE_USB,
|
|
|
|
MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT,
|
|
|
|
MAX8997_CHARGER_TYPE_DEDICATED_CHG,
|
|
|
|
MAX8997_CHARGER_TYPE_500MA,
|
|
|
|
MAX8997_CHARGER_TYPE_1A,
|
|
|
|
MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7,
|
2011-11-24 13:12:18 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct max8997_muic_info {
|
|
|
|
struct device *dev;
|
|
|
|
struct i2c_client *muic;
|
2013-02-13 07:05:42 +04:00
|
|
|
struct extcon_dev *edev;
|
|
|
|
int prev_cable_type;
|
|
|
|
int prev_chg_type;
|
|
|
|
u8 status[2];
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
int irq;
|
|
|
|
struct work_struct irq_work;
|
|
|
|
struct mutex mutex;
|
2012-05-09 07:31:58 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
struct max8997_muic_platform_data *muic_pdata;
|
|
|
|
enum max8997_muic_charger_type pre_charger_type;
|
2013-02-13 10:04:15 +04:00
|
|
|
|
2013-02-13 10:10:00 +04:00
|
|
|
/*
|
|
|
|
* Use delayed workqueue to detect cable state and then
|
|
|
|
* notify cable state to notifiee/platform through uevent.
|
|
|
|
* After completing the booting of platform, the extcon provider
|
|
|
|
* driver should notify cable state to upper layer.
|
|
|
|
*/
|
|
|
|
struct delayed_work wq_detcable;
|
|
|
|
|
2013-02-13 10:04:15 +04:00
|
|
|
/*
|
|
|
|
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
|
|
|
|
* h/w path of COMP2/COMN1 on CONTROL1 register.
|
|
|
|
*/
|
|
|
|
int path_usb;
|
|
|
|
int path_uart;
|
2012-05-09 07:31:58 +04:00
|
|
|
};
|
|
|
|
|
2015-06-12 05:10:06 +03:00
|
|
|
static const unsigned int max8997_extcon_cable[] = {
|
extcon: Use the unique id for external connector instead of string
This patch uses the unique id to identify the type of external connector instead
of string name. The string name have the many potential issues. So, this patch
defines the 'extcon' enumeration which includes all supported external connector
on EXTCON subsystem. If new external connector is necessary, the unique id of
new connector have to be added in 'extcon' enumeration. There are current
supported external connector in 'enum extcon' as following:
enum extcon {
EXTCON_NONE = 0x0,
/* USB external connector */
EXTCON_USB = 0x1,
EXTCON_USB_HOST = 0x2,
/* Charger external connector */
EXTCON_TA = 0x10,
EXTCON_FAST_CHARGER = 0x11,
EXTCON_SLOW_CHARGER = 0x12,
EXTCON_CHARGE_DOWNSTREAM = 0x13,
/* Audio and video external connector */
EXTCON_LINE_IN = 0x20,
EXTCON_LINE_OUT = 0x21,
EXTCON_MICROPHONE = 0x22,
EXTCON_HEADPHONE = 0x23,
EXTCON_HDMI = 0x30,
EXTCON_MHL = 0x31,
EXTCON_DVI = 0x32,
EXTCON_VGA = 0x33,
EXTCON_SPDIF_IN = 0x34,
EXTCON_SPDIF_OUT = 0x35,
EXTCON_VIDEO_IN = 0x36,
EXTCON_VIDEO_OUT = 0x37,
/* Miscellaneous external connector */
EXTCON_DOCK = 0x50,
EXTCON_JIG = 0x51,
EXTCON_MECHANICAL = 0x52,
EXTCON_END,
};
For example in extcon-arizona.c:
To use unique id removes the potential issue about handling
the inconsistent name of external connector with string.
- Previously, use the string to register the type of arizona jack connector
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
};
- Newly, use the unique id to register the type of arizona jack connector
static const enum extcon arizona_cable[] = {
EXTCON_MECHANICAL,
EXTCON_MICROPHONE,
EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
EXTCON_NONE,
};
And this patch modify the prototype of extcon_{get|set}_cable_state_() which
uses the 'enum extcon id' instead of 'cable_index'. Because although one more
extcon drivers support USB cable, each extcon driver might has the differnt
'cable_index' for USB cable. All extcon drivers can use the unique id number
for same external connector with modified extcon_{get|set}_cable_state_().
- Previously, use 'cable_index' on these functions:
extcon_get_cable_state_(struct extcon_dev*, int cable_index)
extcon_set_cable_state_(struct extcon_dev*, int cable_index, bool state)
-Newly, use 'enum extcon id' on these functions:
extcon_get_cable_state_(struct extcon_dev*, enum extcon id)
extcon_set_cable_state_(struct extcon_dev*, enum extcon id, bool state)
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Roger Quadros <rogerq@ti.com>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
[arnd: Report the build break about drivers/usb/phy/phy-tahvo.c after using the
unique id for external connector insteadf of string]
Reported-by: Arnd Bergmann <arnd@arndb.de>
[dan.carpenter: Report the build warning of extcon_{set|get}_cable_state_()]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
2015-04-24 13:16:05 +03:00
|
|
|
EXTCON_USB,
|
|
|
|
EXTCON_USB_HOST,
|
2015-11-09 04:10:15 +03:00
|
|
|
EXTCON_CHG_USB_SDP,
|
2015-10-03 08:15:13 +03:00
|
|
|
EXTCON_CHG_USB_DCP,
|
|
|
|
EXTCON_CHG_USB_FAST,
|
|
|
|
EXTCON_CHG_USB_SLOW,
|
|
|
|
EXTCON_CHG_USB_CDP,
|
|
|
|
EXTCON_DISP_MHL,
|
extcon: Use the unique id for external connector instead of string
This patch uses the unique id to identify the type of external connector instead
of string name. The string name have the many potential issues. So, this patch
defines the 'extcon' enumeration which includes all supported external connector
on EXTCON subsystem. If new external connector is necessary, the unique id of
new connector have to be added in 'extcon' enumeration. There are current
supported external connector in 'enum extcon' as following:
enum extcon {
EXTCON_NONE = 0x0,
/* USB external connector */
EXTCON_USB = 0x1,
EXTCON_USB_HOST = 0x2,
/* Charger external connector */
EXTCON_TA = 0x10,
EXTCON_FAST_CHARGER = 0x11,
EXTCON_SLOW_CHARGER = 0x12,
EXTCON_CHARGE_DOWNSTREAM = 0x13,
/* Audio and video external connector */
EXTCON_LINE_IN = 0x20,
EXTCON_LINE_OUT = 0x21,
EXTCON_MICROPHONE = 0x22,
EXTCON_HEADPHONE = 0x23,
EXTCON_HDMI = 0x30,
EXTCON_MHL = 0x31,
EXTCON_DVI = 0x32,
EXTCON_VGA = 0x33,
EXTCON_SPDIF_IN = 0x34,
EXTCON_SPDIF_OUT = 0x35,
EXTCON_VIDEO_IN = 0x36,
EXTCON_VIDEO_OUT = 0x37,
/* Miscellaneous external connector */
EXTCON_DOCK = 0x50,
EXTCON_JIG = 0x51,
EXTCON_MECHANICAL = 0x52,
EXTCON_END,
};
For example in extcon-arizona.c:
To use unique id removes the potential issue about handling
the inconsistent name of external connector with string.
- Previously, use the string to register the type of arizona jack connector
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
};
- Newly, use the unique id to register the type of arizona jack connector
static const enum extcon arizona_cable[] = {
EXTCON_MECHANICAL,
EXTCON_MICROPHONE,
EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
EXTCON_NONE,
};
And this patch modify the prototype of extcon_{get|set}_cable_state_() which
uses the 'enum extcon id' instead of 'cable_index'. Because although one more
extcon drivers support USB cable, each extcon driver might has the differnt
'cable_index' for USB cable. All extcon drivers can use the unique id number
for same external connector with modified extcon_{get|set}_cable_state_().
- Previously, use 'cable_index' on these functions:
extcon_get_cable_state_(struct extcon_dev*, int cable_index)
extcon_set_cable_state_(struct extcon_dev*, int cable_index, bool state)
-Newly, use 'enum extcon id' on these functions:
extcon_get_cable_state_(struct extcon_dev*, enum extcon id)
extcon_set_cable_state_(struct extcon_dev*, enum extcon id, bool state)
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Roger Quadros <rogerq@ti.com>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
[arnd: Report the build break about drivers/usb/phy/phy-tahvo.c after using the
unique id for external connector insteadf of string]
Reported-by: Arnd Bergmann <arnd@arndb.de>
[dan.carpenter: Report the build warning of extcon_{set|get}_cable_state_()]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
2015-04-24 13:16:05 +03:00
|
|
|
EXTCON_DOCK,
|
|
|
|
EXTCON_JIG,
|
|
|
|
EXTCON_NONE,
|
2011-11-24 13:12:18 +04:00
|
|
|
};
|
|
|
|
|
2013-02-13 03:50:00 +04:00
|
|
|
/*
|
|
|
|
* max8997_muic_set_debounce_time - Set the debounce time of ADC
|
|
|
|
* @info: the instance including private data of max8997 MUIC
|
|
|
|
* @time: the debounce time of ADC
|
|
|
|
*/
|
|
|
|
static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,
|
|
|
|
enum max8997_muic_adc_debounce_time time)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
switch (time) {
|
|
|
|
case ADC_DEBOUNCE_TIME_0_5MS:
|
|
|
|
case ADC_DEBOUNCE_TIME_10MS:
|
|
|
|
case ADC_DEBOUNCE_TIME_25MS:
|
|
|
|
case ADC_DEBOUNCE_TIME_38_62MS:
|
|
|
|
ret = max8997_update_reg(info->muic,
|
|
|
|
MAX8997_MUIC_REG_CONTROL3,
|
|
|
|
time << CONTROL3_ADCDBSET_SHIFT,
|
|
|
|
CONTROL3_ADCDBSET_MASK);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(info->dev, "failed to set ADC debounce time\n");
|
2013-04-08 04:13:18 +04:00
|
|
|
return ret;
|
2013-02-13 03:50:00 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dev_err(info->dev, "invalid ADC debounce time\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
2013-02-13 03:42:37 +04:00
|
|
|
/*
|
|
|
|
* max8997_muic_set_path - Set hardware line according to attached cable
|
|
|
|
* @info: the instance including private data of max8997 MUIC
|
|
|
|
* @value: the path according to attached cable
|
|
|
|
* @attached: the state of cable (true:attached, false:detached)
|
|
|
|
*
|
|
|
|
* The max8997 MUIC device share outside H/W line among a varity of cables,
|
|
|
|
* so this function set internal path of H/W line according to the type of
|
|
|
|
* attached cable.
|
|
|
|
*/
|
|
|
|
static int max8997_muic_set_path(struct max8997_muic_info *info,
|
|
|
|
u8 val, bool attached)
|
|
|
|
{
|
2017-11-09 12:00:08 +03:00
|
|
|
int ret;
|
2013-02-13 03:42:37 +04:00
|
|
|
u8 ctrl1, ctrl2 = 0;
|
|
|
|
|
|
|
|
if (attached)
|
|
|
|
ctrl1 = val;
|
|
|
|
else
|
|
|
|
ctrl1 = CONTROL1_SW_OPEN;
|
|
|
|
|
|
|
|
ret = max8997_update_reg(info->muic,
|
|
|
|
MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(info->dev, "failed to update MUIC register\n");
|
2013-04-08 04:13:18 +04:00
|
|
|
return ret;
|
2013-02-13 03:42:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (attached)
|
|
|
|
ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */
|
|
|
|
else
|
|
|
|
ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
|
|
|
|
|
|
|
|
ret = max8997_update_reg(info->muic,
|
|
|
|
MAX8997_MUIC_REG_CONTROL2, ctrl2,
|
|
|
|
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(info->dev, "failed to update MUIC register\n");
|
2013-04-08 04:13:18 +04:00
|
|
|
return ret;
|
2013-02-13 03:42:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
dev_info(info->dev,
|
|
|
|
"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
|
|
|
|
ctrl1, ctrl2, attached ? "attached" : "detached");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
/*
|
|
|
|
* max8997_muic_get_cable_type - Return cable type and check cable state
|
|
|
|
* @info: the instance including private data of max8997 MUIC
|
|
|
|
* @group: the path according to attached cable
|
|
|
|
* @attached: store cable state and return
|
|
|
|
*
|
|
|
|
* This function check the cable state either attached or detached,
|
|
|
|
* and then divide precise type of cable according to cable group.
|
|
|
|
* - MAX8997_CABLE_GROUP_ADC
|
|
|
|
* - MAX8997_CABLE_GROUP_CHG
|
|
|
|
*/
|
|
|
|
static int max8997_muic_get_cable_type(struct max8997_muic_info *info,
|
|
|
|
enum max8997_muic_cable_group group, bool *attached)
|
|
|
|
{
|
|
|
|
int cable_type = 0;
|
|
|
|
int adc;
|
|
|
|
int chg_type;
|
|
|
|
|
|
|
|
switch (group) {
|
|
|
|
case MAX8997_CABLE_GROUP_ADC:
|
|
|
|
/*
|
|
|
|
* Read ADC value to check cable type and decide cable state
|
|
|
|
* according to cable type
|
|
|
|
*/
|
|
|
|
adc = info->status[0] & STATUS1_ADC_MASK;
|
|
|
|
adc >>= STATUS1_ADC_SHIFT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check current cable state/cable type and store cable type
|
|
|
|
* (info->prev_cable_type) for handling cable when cable is
|
|
|
|
* detached.
|
|
|
|
*/
|
|
|
|
if (adc == MAX8997_MUIC_ADC_OPEN) {
|
|
|
|
*attached = false;
|
|
|
|
|
|
|
|
cable_type = info->prev_cable_type;
|
|
|
|
info->prev_cable_type = MAX8997_MUIC_ADC_OPEN;
|
|
|
|
} else {
|
|
|
|
*attached = true;
|
|
|
|
|
|
|
|
cable_type = info->prev_cable_type = adc;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MAX8997_CABLE_GROUP_CHG:
|
|
|
|
/*
|
|
|
|
* Read charger type to check cable type and decide cable state
|
|
|
|
* according to type of charger cable.
|
|
|
|
*/
|
|
|
|
chg_type = info->status[1] & STATUS2_CHGTYP_MASK;
|
|
|
|
chg_type >>= STATUS2_CHGTYP_SHIFT;
|
|
|
|
|
|
|
|
if (chg_type == MAX8997_CHARGER_TYPE_NONE) {
|
|
|
|
*attached = false;
|
|
|
|
|
|
|
|
cable_type = info->prev_chg_type;
|
|
|
|
info->prev_chg_type = MAX8997_CHARGER_TYPE_NONE;
|
|
|
|
} else {
|
|
|
|
*attached = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check current cable state/cable type and store cable
|
|
|
|
* type(info->prev_chg_type) for handling cable when
|
|
|
|
* charger cable is detached.
|
|
|
|
*/
|
|
|
|
cable_type = info->prev_chg_type = chg_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dev_err(info->dev, "Unknown cable group (%d)\n", group);
|
|
|
|
cable_type = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cable_type;
|
|
|
|
}
|
|
|
|
|
2011-11-24 13:12:18 +04:00
|
|
|
static int max8997_muic_handle_usb(struct max8997_muic_info *info,
|
|
|
|
enum max8997_muic_usb_type usb_type, bool attached)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2018-11-13 18:38:47 +03:00
|
|
|
ret = max8997_muic_set_path(info, info->path_usb, attached);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(info->dev, "failed to update muic register\n");
|
|
|
|
return ret;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2012-05-09 07:31:58 +04:00
|
|
|
switch (usb_type) {
|
|
|
|
case MAX8997_USB_HOST:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached);
|
2012-05-09 07:31:58 +04:00
|
|
|
break;
|
|
|
|
case MAX8997_USB_DEVICE:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_USB, attached);
|
|
|
|
extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP,
|
2015-11-09 04:10:15 +03:00
|
|
|
attached);
|
2012-05-09 07:31:58 +04:00
|
|
|
break;
|
|
|
|
default:
|
2013-02-13 07:05:42 +04:00
|
|
|
dev_err(info->dev, "failed to detect %s usb cable\n",
|
|
|
|
attached ? "attached" : "detached");
|
|
|
|
return -EINVAL;
|
2012-05-09 07:31:58 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int max8997_muic_handle_dock(struct max8997_muic_info *info,
|
2013-02-13 07:05:42 +04:00
|
|
|
int cable_type, bool attached)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2013-02-13 03:42:37 +04:00
|
|
|
ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
if (ret) {
|
|
|
|
dev_err(info->dev, "failed to update muic register\n");
|
2013-02-13 07:05:42 +04:00
|
|
|
return ret;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
switch (cable_type) {
|
|
|
|
case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
|
|
|
|
case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_DOCK, attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
break;
|
|
|
|
default:
|
2013-02-13 07:05:42 +04:00
|
|
|
dev_err(info->dev, "failed to detect %s dock device\n",
|
|
|
|
attached ? "attached" : "detached");
|
|
|
|
return -EINVAL;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
2013-02-13 07:05:42 +04:00
|
|
|
|
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
|
|
|
|
bool attached)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* switch to UART */
|
2013-02-13 10:04:15 +04:00
|
|
|
ret = max8997_muic_set_path(info, info->path_uart, attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
if (ret) {
|
|
|
|
dev_err(info->dev, "failed to update muic register\n");
|
2013-04-08 04:13:18 +04:00
|
|
|
return ret;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_JIG, attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
static int max8997_muic_adc_handler(struct max8997_muic_info *info)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
2013-02-13 07:05:42 +04:00
|
|
|
int cable_type;
|
|
|
|
bool attached;
|
2011-11-24 13:12:18 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
/* Check cable state which is either detached or attached */
|
|
|
|
cable_type = max8997_muic_get_cable_type(info,
|
|
|
|
MAX8997_CABLE_GROUP_ADC, &attached);
|
|
|
|
|
|
|
|
switch (cable_type) {
|
|
|
|
case MAX8997_MUIC_ADC_GROUND:
|
|
|
|
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
break;
|
|
|
|
case MAX8997_MUIC_ADC_MHL:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
|
2013-02-13 07:05:42 +04:00
|
|
|
break;
|
|
|
|
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF:
|
|
|
|
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON:
|
2013-08-23 05:21:37 +04:00
|
|
|
ret = max8997_muic_handle_usb(info,
|
|
|
|
MAX8997_USB_DEVICE, attached);
|
2013-02-13 07:05:42 +04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
break;
|
|
|
|
case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
|
|
|
|
case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
|
|
|
|
ret = max8997_muic_handle_dock(info, cable_type, attached);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
break;
|
|
|
|
case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF:
|
|
|
|
ret = max8997_muic_handle_jig_uart(info, attached);
|
|
|
|
break;
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON:
|
|
|
|
case MAX8997_MUIC_ADC_RESERVED_ACC_1:
|
|
|
|
case MAX8997_MUIC_ADC_RESERVED_ACC_2:
|
|
|
|
case MAX8997_MUIC_ADC_RESERVED_ACC_3:
|
|
|
|
case MAX8997_MUIC_ADC_RESERVED_ACC_4:
|
|
|
|
case MAX8997_MUIC_ADC_RESERVED_ACC_5:
|
|
|
|
case MAX8997_MUIC_ADC_CEA936_AUDIO:
|
|
|
|
case MAX8997_MUIC_ADC_PHONE_POWERED_DEV:
|
|
|
|
case MAX8997_MUIC_ADC_TTY_CONVERTER:
|
|
|
|
case MAX8997_MUIC_ADC_UART_CABLE:
|
|
|
|
case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG:
|
|
|
|
case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG:
|
|
|
|
case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE:
|
|
|
|
/*
|
|
|
|
* This cable isn't used in general case if it is specially
|
|
|
|
* needed to detect additional cable, should implement
|
|
|
|
* proper operation when this cable is attached/detached.
|
|
|
|
*/
|
|
|
|
dev_info(info->dev,
|
|
|
|
"cable is %s but it isn't used (type:0x%x)\n",
|
|
|
|
attached ? "attached" : "detached", cable_type);
|
|
|
|
return -EAGAIN;
|
2012-05-09 07:31:58 +04:00
|
|
|
default:
|
2013-02-13 07:05:42 +04:00
|
|
|
dev_err(info->dev,
|
|
|
|
"failed to detect %s unknown cable (type:0x%x)\n",
|
|
|
|
attached ? "attached" : "detached", cable_type);
|
2012-08-31 12:30:19 +04:00
|
|
|
return -EINVAL;
|
2012-05-09 07:31:58 +04:00
|
|
|
}
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2012-08-31 12:30:19 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
static int max8997_muic_chg_handler(struct max8997_muic_info *info)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
2013-02-13 07:05:42 +04:00
|
|
|
int chg_type;
|
|
|
|
bool attached;
|
|
|
|
int adc;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
chg_type = max8997_muic_get_cable_type(info,
|
|
|
|
MAX8997_CABLE_GROUP_CHG, &attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
switch (chg_type) {
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_CHARGER_TYPE_NONE:
|
|
|
|
break;
|
|
|
|
case MAX8997_CHARGER_TYPE_USB:
|
2013-02-13 07:05:42 +04:00
|
|
|
adc = info->status[0] & STATUS1_ADC_MASK;
|
|
|
|
adc >>= STATUS1_ADC_SHIFT;
|
|
|
|
|
|
|
|
if ((adc & STATUS1_ADC_MASK) == MAX8997_MUIC_ADC_OPEN) {
|
2011-11-24 13:12:18 +04:00
|
|
|
max8997_muic_handle_usb(info,
|
2013-02-13 07:05:42 +04:00
|
|
|
MAX8997_USB_DEVICE, attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP,
|
extcon: Use the unique id for external connector instead of string
This patch uses the unique id to identify the type of external connector instead
of string name. The string name have the many potential issues. So, this patch
defines the 'extcon' enumeration which includes all supported external connector
on EXTCON subsystem. If new external connector is necessary, the unique id of
new connector have to be added in 'extcon' enumeration. There are current
supported external connector in 'enum extcon' as following:
enum extcon {
EXTCON_NONE = 0x0,
/* USB external connector */
EXTCON_USB = 0x1,
EXTCON_USB_HOST = 0x2,
/* Charger external connector */
EXTCON_TA = 0x10,
EXTCON_FAST_CHARGER = 0x11,
EXTCON_SLOW_CHARGER = 0x12,
EXTCON_CHARGE_DOWNSTREAM = 0x13,
/* Audio and video external connector */
EXTCON_LINE_IN = 0x20,
EXTCON_LINE_OUT = 0x21,
EXTCON_MICROPHONE = 0x22,
EXTCON_HEADPHONE = 0x23,
EXTCON_HDMI = 0x30,
EXTCON_MHL = 0x31,
EXTCON_DVI = 0x32,
EXTCON_VGA = 0x33,
EXTCON_SPDIF_IN = 0x34,
EXTCON_SPDIF_OUT = 0x35,
EXTCON_VIDEO_IN = 0x36,
EXTCON_VIDEO_OUT = 0x37,
/* Miscellaneous external connector */
EXTCON_DOCK = 0x50,
EXTCON_JIG = 0x51,
EXTCON_MECHANICAL = 0x52,
EXTCON_END,
};
For example in extcon-arizona.c:
To use unique id removes the potential issue about handling
the inconsistent name of external connector with string.
- Previously, use the string to register the type of arizona jack connector
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
};
- Newly, use the unique id to register the type of arizona jack connector
static const enum extcon arizona_cable[] = {
EXTCON_MECHANICAL,
EXTCON_MICROPHONE,
EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
EXTCON_NONE,
};
And this patch modify the prototype of extcon_{get|set}_cable_state_() which
uses the 'enum extcon id' instead of 'cable_index'. Because although one more
extcon drivers support USB cable, each extcon driver might has the differnt
'cable_index' for USB cable. All extcon drivers can use the unique id number
for same external connector with modified extcon_{get|set}_cable_state_().
- Previously, use 'cable_index' on these functions:
extcon_get_cable_state_(struct extcon_dev*, int cable_index)
extcon_set_cable_state_(struct extcon_dev*, int cable_index, bool state)
-Newly, use 'enum extcon id' on these functions:
extcon_get_cable_state_(struct extcon_dev*, enum extcon id)
extcon_set_cable_state_(struct extcon_dev*, enum extcon id, bool state)
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Roger Quadros <rogerq@ti.com>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
[arnd: Report the build break about drivers/usb/phy/phy-tahvo.c after using the
unique id for external connector insteadf of string]
Reported-by: Arnd Bergmann <arnd@arndb.de>
[dan.carpenter: Report the build warning of extcon_{set|get}_cable_state_()]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
2015-04-24 13:16:05 +03:00
|
|
|
attached);
|
2012-05-09 07:31:58 +04:00
|
|
|
break;
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP,
|
2015-10-03 08:15:13 +03:00
|
|
|
attached);
|
2012-05-09 07:31:58 +04:00
|
|
|
break;
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_CHARGER_TYPE_500MA:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW,
|
extcon: Use the unique id for external connector instead of string
This patch uses the unique id to identify the type of external connector instead
of string name. The string name have the many potential issues. So, this patch
defines the 'extcon' enumeration which includes all supported external connector
on EXTCON subsystem. If new external connector is necessary, the unique id of
new connector have to be added in 'extcon' enumeration. There are current
supported external connector in 'enum extcon' as following:
enum extcon {
EXTCON_NONE = 0x0,
/* USB external connector */
EXTCON_USB = 0x1,
EXTCON_USB_HOST = 0x2,
/* Charger external connector */
EXTCON_TA = 0x10,
EXTCON_FAST_CHARGER = 0x11,
EXTCON_SLOW_CHARGER = 0x12,
EXTCON_CHARGE_DOWNSTREAM = 0x13,
/* Audio and video external connector */
EXTCON_LINE_IN = 0x20,
EXTCON_LINE_OUT = 0x21,
EXTCON_MICROPHONE = 0x22,
EXTCON_HEADPHONE = 0x23,
EXTCON_HDMI = 0x30,
EXTCON_MHL = 0x31,
EXTCON_DVI = 0x32,
EXTCON_VGA = 0x33,
EXTCON_SPDIF_IN = 0x34,
EXTCON_SPDIF_OUT = 0x35,
EXTCON_VIDEO_IN = 0x36,
EXTCON_VIDEO_OUT = 0x37,
/* Miscellaneous external connector */
EXTCON_DOCK = 0x50,
EXTCON_JIG = 0x51,
EXTCON_MECHANICAL = 0x52,
EXTCON_END,
};
For example in extcon-arizona.c:
To use unique id removes the potential issue about handling
the inconsistent name of external connector with string.
- Previously, use the string to register the type of arizona jack connector
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
};
- Newly, use the unique id to register the type of arizona jack connector
static const enum extcon arizona_cable[] = {
EXTCON_MECHANICAL,
EXTCON_MICROPHONE,
EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
EXTCON_NONE,
};
And this patch modify the prototype of extcon_{get|set}_cable_state_() which
uses the 'enum extcon id' instead of 'cable_index'. Because although one more
extcon drivers support USB cable, each extcon driver might has the differnt
'cable_index' for USB cable. All extcon drivers can use the unique id number
for same external connector with modified extcon_{get|set}_cable_state_().
- Previously, use 'cable_index' on these functions:
extcon_get_cable_state_(struct extcon_dev*, int cable_index)
extcon_set_cable_state_(struct extcon_dev*, int cable_index, bool state)
-Newly, use 'enum extcon id' on these functions:
extcon_get_cable_state_(struct extcon_dev*, enum extcon id)
extcon_set_cable_state_(struct extcon_dev*, enum extcon id, bool state)
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Roger Quadros <rogerq@ti.com>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
[arnd: Report the build break about drivers/usb/phy/phy-tahvo.c after using the
unique id for external connector insteadf of string]
Reported-by: Arnd Bergmann <arnd@arndb.de>
[dan.carpenter: Report the build warning of extcon_{set|get}_cable_state_()]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
2015-04-24 13:16:05 +03:00
|
|
|
attached);
|
2012-05-09 07:31:58 +04:00
|
|
|
break;
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_CHARGER_TYPE_1A:
|
2016-08-16 09:55:34 +03:00
|
|
|
extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST,
|
extcon: Use the unique id for external connector instead of string
This patch uses the unique id to identify the type of external connector instead
of string name. The string name have the many potential issues. So, this patch
defines the 'extcon' enumeration which includes all supported external connector
on EXTCON subsystem. If new external connector is necessary, the unique id of
new connector have to be added in 'extcon' enumeration. There are current
supported external connector in 'enum extcon' as following:
enum extcon {
EXTCON_NONE = 0x0,
/* USB external connector */
EXTCON_USB = 0x1,
EXTCON_USB_HOST = 0x2,
/* Charger external connector */
EXTCON_TA = 0x10,
EXTCON_FAST_CHARGER = 0x11,
EXTCON_SLOW_CHARGER = 0x12,
EXTCON_CHARGE_DOWNSTREAM = 0x13,
/* Audio and video external connector */
EXTCON_LINE_IN = 0x20,
EXTCON_LINE_OUT = 0x21,
EXTCON_MICROPHONE = 0x22,
EXTCON_HEADPHONE = 0x23,
EXTCON_HDMI = 0x30,
EXTCON_MHL = 0x31,
EXTCON_DVI = 0x32,
EXTCON_VGA = 0x33,
EXTCON_SPDIF_IN = 0x34,
EXTCON_SPDIF_OUT = 0x35,
EXTCON_VIDEO_IN = 0x36,
EXTCON_VIDEO_OUT = 0x37,
/* Miscellaneous external connector */
EXTCON_DOCK = 0x50,
EXTCON_JIG = 0x51,
EXTCON_MECHANICAL = 0x52,
EXTCON_END,
};
For example in extcon-arizona.c:
To use unique id removes the potential issue about handling
the inconsistent name of external connector with string.
- Previously, use the string to register the type of arizona jack connector
static const char *arizona_cable[] = {
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
};
- Newly, use the unique id to register the type of arizona jack connector
static const enum extcon arizona_cable[] = {
EXTCON_MECHANICAL,
EXTCON_MICROPHONE,
EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
EXTCON_NONE,
};
And this patch modify the prototype of extcon_{get|set}_cable_state_() which
uses the 'enum extcon id' instead of 'cable_index'. Because although one more
extcon drivers support USB cable, each extcon driver might has the differnt
'cable_index' for USB cable. All extcon drivers can use the unique id number
for same external connector with modified extcon_{get|set}_cable_state_().
- Previously, use 'cable_index' on these functions:
extcon_get_cable_state_(struct extcon_dev*, int cable_index)
extcon_set_cable_state_(struct extcon_dev*, int cable_index, bool state)
-Newly, use 'enum extcon id' on these functions:
extcon_get_cable_state_(struct extcon_dev*, enum extcon id)
extcon_set_cable_state_(struct extcon_dev*, enum extcon id, bool state)
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Roger Quadros <rogerq@ti.com>
Acked-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Acked-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
[arnd: Report the build break about drivers/usb/phy/phy-tahvo.c after using the
unique id for external connector insteadf of string]
Reported-by: Arnd Bergmann <arnd@arndb.de>
[dan.carpenter: Report the build warning of extcon_{set|get}_cable_state_()]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
2015-04-24 13:16:05 +03:00
|
|
|
attached);
|
2011-11-24 13:12:18 +04:00
|
|
|
break;
|
|
|
|
default:
|
2013-02-13 07:05:42 +04:00
|
|
|
dev_err(info->dev,
|
|
|
|
"failed to detect %s unknown chg cable (type:0x%x)\n",
|
|
|
|
attached ? "attached" : "detached", chg_type);
|
|
|
|
return -EINVAL;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void max8997_muic_irq_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct max8997_muic_info *info = container_of(work,
|
|
|
|
struct max8997_muic_info, irq_work);
|
2012-07-02 04:03:00 +04:00
|
|
|
int irq_type = 0;
|
|
|
|
int i, ret;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
if (!info->edev)
|
|
|
|
return;
|
|
|
|
|
2011-11-24 13:12:18 +04:00
|
|
|
mutex_lock(&info->mutex);
|
|
|
|
|
2013-08-05 13:02:03 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
|
2013-02-13 07:05:42 +04:00
|
|
|
if (info->irq == muic_irqs[i].virq)
|
|
|
|
irq_type = muic_irqs[i].irq;
|
|
|
|
|
2011-11-24 13:12:18 +04:00
|
|
|
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
|
2013-02-13 07:05:42 +04:00
|
|
|
2, info->status);
|
2011-11-24 13:12:18 +04:00
|
|
|
if (ret) {
|
|
|
|
dev_err(info->dev, "failed to read muic register\n");
|
|
|
|
mutex_unlock(&info->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (irq_type) {
|
2013-02-13 07:05:42 +04:00
|
|
|
case MAX8997_MUICIRQ_ADCError:
|
|
|
|
case MAX8997_MUICIRQ_ADCLow:
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_MUICIRQ_ADC:
|
2013-02-13 07:05:42 +04:00
|
|
|
/* Handle all of cable except for charger cable */
|
|
|
|
ret = max8997_muic_adc_handler(info);
|
2011-11-24 13:12:18 +04:00
|
|
|
break;
|
2013-02-13 07:05:42 +04:00
|
|
|
case MAX8997_MUICIRQ_VBVolt:
|
|
|
|
case MAX8997_MUICIRQ_DBChg:
|
|
|
|
case MAX8997_MUICIRQ_DCDTmr:
|
|
|
|
case MAX8997_MUICIRQ_ChgDetRun:
|
2011-11-24 13:12:18 +04:00
|
|
|
case MAX8997_MUICIRQ_ChgTyp:
|
2020-12-30 23:51:53 +03:00
|
|
|
case MAX8997_PMICIRQ_CHGINS:
|
|
|
|
case MAX8997_PMICIRQ_CHGRM:
|
2013-02-13 07:05:42 +04:00
|
|
|
/* Handle charger cable */
|
|
|
|
ret = max8997_muic_chg_handler(info);
|
|
|
|
break;
|
|
|
|
case MAX8997_MUICIRQ_OVP:
|
2011-11-24 13:12:18 +04:00
|
|
|
break;
|
|
|
|
default:
|
2012-05-09 07:31:58 +04:00
|
|
|
dev_info(info->dev, "misc interrupt: irq %d occurred\n",
|
|
|
|
irq_type);
|
2013-02-13 07:05:42 +04:00
|
|
|
mutex_unlock(&info->mutex);
|
|
|
|
return;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
if (ret < 0)
|
|
|
|
dev_err(info->dev, "failed to handle MUIC interrupt\n");
|
|
|
|
|
2011-11-24 13:12:18 +04:00
|
|
|
mutex_unlock(&info->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
|
|
|
|
{
|
|
|
|
struct max8997_muic_info *info = data;
|
|
|
|
|
|
|
|
dev_dbg(info->dev, "irq:%d\n", irq);
|
|
|
|
info->irq = irq;
|
|
|
|
|
|
|
|
schedule_work(&info->irq_work);
|
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
static int max8997_muic_detect_dev(struct max8997_muic_info *info)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
2013-02-13 07:05:42 +04:00
|
|
|
int ret = 0;
|
|
|
|
int adc;
|
|
|
|
int chg_type;
|
|
|
|
bool attached;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
mutex_lock(&info->mutex);
|
|
|
|
|
|
|
|
/* Read STATUSx register to detect accessory */
|
|
|
|
ret = max8997_bulk_read(info->muic,
|
|
|
|
MAX8997_MUIC_REG_STATUS1, 2, info->status);
|
2011-11-24 13:12:18 +04:00
|
|
|
if (ret) {
|
2013-02-13 07:05:42 +04:00
|
|
|
dev_err(info->dev, "failed to read MUIC register\n");
|
|
|
|
mutex_unlock(&info->mutex);
|
2013-04-08 04:13:18 +04:00
|
|
|
return ret;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
|
|
|
|
&attached);
|
|
|
|
if (attached && adc != MAX8997_MUIC_ADC_OPEN) {
|
|
|
|
ret = max8997_muic_adc_handler(info);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(info->dev, "Cannot detect ADC cable\n");
|
|
|
|
mutex_unlock(&info->mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG,
|
|
|
|
&attached);
|
|
|
|
if (attached && chg_type != MAX8997_CHARGER_TYPE_NONE) {
|
|
|
|
ret = max8997_muic_chg_handler(info);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(info->dev, "Cannot detect charger cable\n");
|
|
|
|
mutex_unlock(&info->mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
mutex_unlock(&info->mutex);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 07:05:42 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 10:10:00 +04:00
|
|
|
static void max8997_muic_detect_cable_wq(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct max8997_muic_info *info = container_of(to_delayed_work(work),
|
|
|
|
struct max8997_muic_info, wq_detcable);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = max8997_muic_detect_dev(info);
|
|
|
|
if (ret < 0)
|
2013-04-08 04:11:06 +04:00
|
|
|
dev_err(info->dev, "failed to detect cable type\n");
|
2013-02-13 10:10:00 +04:00
|
|
|
}
|
|
|
|
|
2012-11-19 22:23:21 +04:00
|
|
|
static int max8997_muic_probe(struct platform_device *pdev)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
2012-05-09 07:31:58 +04:00
|
|
|
struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
|
|
|
|
struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
|
2011-11-24 13:12:18 +04:00
|
|
|
struct max8997_muic_info *info;
|
2013-02-13 10:10:00 +04:00
|
|
|
int delay_jiffies;
|
2018-11-08 16:45:48 +03:00
|
|
|
int cable_type;
|
|
|
|
bool attached;
|
2011-11-24 13:12:18 +04:00
|
|
|
int ret, i;
|
|
|
|
|
2012-11-20 10:46:47 +04:00
|
|
|
info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info),
|
|
|
|
GFP_KERNEL);
|
2014-07-23 05:07:09 +04:00
|
|
|
if (!info)
|
2012-11-20 10:46:47 +04:00
|
|
|
return -ENOMEM;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
info->dev = &pdev->dev;
|
2012-05-09 07:31:58 +04:00
|
|
|
info->muic = max8997->muic;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
platform_set_drvdata(pdev, info);
|
|
|
|
mutex_init(&info->mutex);
|
|
|
|
|
|
|
|
INIT_WORK(&info->irq_work, max8997_muic_irq_work);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
|
|
|
|
struct max8997_muic_irq *muic_irq = &muic_irqs[i];
|
2012-11-20 10:46:41 +04:00
|
|
|
unsigned int virq = 0;
|
2012-07-02 04:03:00 +04:00
|
|
|
|
|
|
|
virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq);
|
2012-11-20 10:46:41 +04:00
|
|
|
if (!virq) {
|
|
|
|
ret = -EINVAL;
|
2012-07-02 04:03:00 +04:00
|
|
|
goto err_irq;
|
2012-11-20 10:46:41 +04:00
|
|
|
}
|
2012-07-02 04:03:00 +04:00
|
|
|
muic_irq->virq = virq;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2012-11-28 07:39:01 +04:00
|
|
|
ret = request_threaded_irq(virq, NULL,
|
|
|
|
max8997_muic_irq_handler,
|
|
|
|
IRQF_NO_SUSPEND,
|
|
|
|
muic_irq->name, info);
|
2011-11-24 13:12:18 +04:00
|
|
|
if (ret) {
|
|
|
|
dev_err(&pdev->dev,
|
2015-03-06 19:41:36 +03:00
|
|
|
"failed: irq request (IRQ: %d, error :%d)\n",
|
2011-11-24 13:12:18 +04:00
|
|
|
muic_irq->irq, ret);
|
|
|
|
goto err_irq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-09 07:31:58 +04:00
|
|
|
/* External connector */
|
2014-04-21 15:37:51 +04:00
|
|
|
info->edev = devm_extcon_dev_allocate(&pdev->dev, max8997_extcon_cable);
|
|
|
|
if (IS_ERR(info->edev)) {
|
2012-05-09 07:31:58 +04:00
|
|
|
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
2020-08-29 15:43:56 +03:00
|
|
|
ret = PTR_ERR(info->edev);
|
2012-05-09 07:31:58 +04:00
|
|
|
goto err_irq;
|
|
|
|
}
|
2014-04-21 15:37:51 +04:00
|
|
|
|
2014-04-21 14:10:13 +04:00
|
|
|
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
2012-05-09 07:31:58 +04:00
|
|
|
if (ret) {
|
|
|
|
dev_err(&pdev->dev, "failed to register extcon device\n");
|
2012-11-20 10:46:47 +04:00
|
|
|
goto err_irq;
|
2012-05-09 07:31:58 +04:00
|
|
|
}
|
|
|
|
|
2014-04-09 17:20:14 +04:00
|
|
|
if (pdata && pdata->muic_pdata) {
|
2013-02-18 05:15:03 +04:00
|
|
|
struct max8997_muic_platform_data *muic_pdata
|
|
|
|
= pdata->muic_pdata;
|
|
|
|
|
|
|
|
/* Initialize registers according to platform data */
|
|
|
|
for (i = 0; i < muic_pdata->num_init_data; i++) {
|
|
|
|
max8997_write_reg(info->muic,
|
|
|
|
muic_pdata->init_data[i].addr,
|
|
|
|
muic_pdata->init_data[i].data);
|
2012-05-09 07:31:58 +04:00
|
|
|
}
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-18 05:15:03 +04:00
|
|
|
/*
|
|
|
|
* Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
|
|
|
|
* h/w path of COMP2/COMN1 on CONTROL1 register.
|
|
|
|
*/
|
|
|
|
if (muic_pdata->path_uart)
|
|
|
|
info->path_uart = muic_pdata->path_uart;
|
|
|
|
else
|
|
|
|
info->path_uart = CONTROL1_SW_UART;
|
2013-02-13 10:04:15 +04:00
|
|
|
|
2013-02-18 05:15:03 +04:00
|
|
|
if (muic_pdata->path_usb)
|
|
|
|
info->path_usb = muic_pdata->path_usb;
|
|
|
|
else
|
|
|
|
info->path_usb = CONTROL1_SW_USB;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default delay time for detecting cable state
|
|
|
|
* after certain time.
|
|
|
|
*/
|
|
|
|
if (muic_pdata->detcable_delay_ms)
|
|
|
|
delay_jiffies =
|
|
|
|
msecs_to_jiffies(muic_pdata->detcable_delay_ms);
|
|
|
|
else
|
|
|
|
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
|
|
|
|
} else {
|
|
|
|
info->path_uart = CONTROL1_SW_UART;
|
2013-02-13 10:04:15 +04:00
|
|
|
info->path_usb = CONTROL1_SW_USB;
|
2013-02-18 05:15:03 +04:00
|
|
|
delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
|
|
|
|
}
|
2013-02-13 10:04:15 +04:00
|
|
|
|
2018-11-08 16:45:48 +03:00
|
|
|
/* Set initial path for UART when JIG is connected to get serial logs */
|
|
|
|
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
|
|
|
|
2, info->status);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(info->dev, "failed to read MUIC register\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
cable_type = max8997_muic_get_cable_type(info,
|
|
|
|
MAX8997_CABLE_GROUP_ADC, &attached);
|
|
|
|
if (attached && cable_type == MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF)
|
|
|
|
max8997_muic_set_path(info, info->path_uart, true);
|
2013-02-13 10:04:15 +04:00
|
|
|
|
2013-02-13 03:50:00 +04:00
|
|
|
/* Set ADC debounce time */
|
|
|
|
max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);
|
|
|
|
|
2013-02-13 10:10:00 +04:00
|
|
|
/*
|
|
|
|
* Detect accessory after completing the initialization of platform
|
|
|
|
*
|
|
|
|
* - Use delayed workqueue to detect cable state and then
|
|
|
|
* notify cable state to notifiee/platform through uevent.
|
|
|
|
* After completing the booting of platform, the extcon provider
|
|
|
|
* driver should notify cable state to upper layer.
|
|
|
|
*/
|
|
|
|
INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
|
2014-04-09 17:20:15 +04:00
|
|
|
queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
|
|
|
|
delay_jiffies);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2013-02-13 10:10:00 +04:00
|
|
|
return 0;
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
err_irq:
|
2012-03-26 05:57:08 +04:00
|
|
|
while (--i >= 0)
|
2012-07-02 04:03:00 +04:00
|
|
|
free_irq(muic_irqs[i].virq, info);
|
2011-11-24 13:12:18 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-11-19 22:25:49 +04:00
|
|
|
static int max8997_muic_remove(struct platform_device *pdev)
|
2011-11-24 13:12:18 +04:00
|
|
|
{
|
|
|
|
struct max8997_muic_info *info = platform_get_drvdata(pdev);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
|
2012-07-02 04:03:00 +04:00
|
|
|
free_irq(muic_irqs[i].virq, info);
|
2011-12-15 13:20:47 +04:00
|
|
|
cancel_work_sync(&info->irq_work);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct platform_driver max8997_muic_driver = {
|
|
|
|
.driver = {
|
2012-05-09 07:31:58 +04:00
|
|
|
.name = DEV_NAME,
|
2011-11-24 13:12:18 +04:00
|
|
|
},
|
|
|
|
.probe = max8997_muic_probe,
|
2012-11-19 22:20:06 +04:00
|
|
|
.remove = max8997_muic_remove,
|
2011-11-24 13:12:18 +04:00
|
|
|
};
|
|
|
|
|
2012-01-22 11:33:49 +04:00
|
|
|
module_platform_driver(max8997_muic_driver);
|
2011-11-24 13:12:18 +04:00
|
|
|
|
2012-05-09 07:31:58 +04:00
|
|
|
MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
|
2011-11-24 13:12:18 +04:00
|
|
|
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
|
|
|
|
MODULE_LICENSE("GPL");
|