Commit db788e6b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'extcon-next-for-5.16' of...

Merge tag 'extcon-next-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next

Chanwoo writes:

Update extcon next for v5.16

Detailed description for this pull request:
1. Add support for TUSB320L and update tusb320 extcon driver
- The existing extcon-usbc-tusb320 driver is updated
for supporting the mode setting and reset operation.
Also, this driver supports the simliar TUSB320L device
at the same extcon-usbc-tusb320 extcon provider driver.

2. Use p-unit semaphone lock for register access for extcon-axp288
driver

3. Update the minor clean-up for extcon-max3355 and extcon-usb-gpio
driver.

* tag 'extcon-next-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon:
  dt-bindings: extcon: usbc-tusb320: Add TUSB320L compatible string
  extcon: usbc-tusb320: Add support for TUSB320L
  extcon: usbc-tusb320: Add support for mode setting and reset
  extcon: extcon-axp288: Use P-Unit semaphore lock for register accesses
  extcon: max3355: Drop unused include
  extcon: usb-gpio: Use the right includes
parents 08e438e6 9e6ef3a2
...@@ -11,7 +11,9 @@ maintainers: ...@@ -11,7 +11,9 @@ maintainers:
properties: properties:
compatible: compatible:
const: ti,tusb320 enum:
- ti,tusb320
- ti,tusb320l
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -23,7 +23,7 @@ config EXTCON_ADC_JACK ...@@ -23,7 +23,7 @@ config EXTCON_ADC_JACK
config EXTCON_AXP288 config EXTCON_AXP288
tristate "X-Power AXP288 EXTCON support" tristate "X-Power AXP288 EXTCON support"
depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI && IOSF_MBI
select USB_ROLE_SWITCH select USB_ROLE_SWITCH
help help
Say Y here to enable support for USB peripheral detection Say Y here to enable support for USB peripheral detection
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#include <asm/intel-family.h> #include <asm/intel-family.h>
#include <asm/iosf_mbi.h>
/* Power source status register */ /* Power source status register */
#define PS_STAT_VBUS_TRIGGER BIT(0) #define PS_STAT_VBUS_TRIGGER BIT(0)
...@@ -215,6 +216,10 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) ...@@ -215,6 +216,10 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
unsigned int cable = info->previous_cable; unsigned int cable = info->previous_cable;
bool vbus_attach = false; bool vbus_attach = false;
ret = iosf_mbi_block_punit_i2c_access();
if (ret < 0)
return ret;
vbus_attach = axp288_get_vbus_attach(info); vbus_attach = axp288_get_vbus_attach(info);
if (!vbus_attach) if (!vbus_attach)
goto no_vbus; goto no_vbus;
...@@ -253,6 +258,8 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) ...@@ -253,6 +258,8 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
} }
no_vbus: no_vbus:
iosf_mbi_unblock_punit_i2c_access();
extcon_set_state_sync(info->edev, info->previous_cable, false); extcon_set_state_sync(info->edev, info->previous_cable, false);
if (info->previous_cable == EXTCON_CHG_USB_SDP) if (info->previous_cable == EXTCON_CHG_USB_SDP)
extcon_set_state_sync(info->edev, EXTCON_USB, false); extcon_set_state_sync(info->edev, EXTCON_USB, false);
...@@ -275,6 +282,8 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) ...@@ -275,6 +282,8 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
return 0; return 0;
dev_det_ret: dev_det_ret:
iosf_mbi_unblock_punit_i2c_access();
if (ret < 0) if (ret < 0)
dev_err(info->dev, "failed to detect BC Mod\n"); dev_err(info->dev, "failed to detect BC Mod\n");
...@@ -305,13 +314,23 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data) ...@@ -305,13 +314,23 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void axp288_extcon_enable(struct axp288_extcon_info *info) static int axp288_extcon_enable(struct axp288_extcon_info *info)
{ {
int ret = 0;
ret = iosf_mbi_block_punit_i2c_access();
if (ret < 0)
return ret;
regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
BC_GLOBAL_RUN, 0); BC_GLOBAL_RUN, 0);
/* Enable the charger detection logic */ /* Enable the charger detection logic */
regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
BC_GLOBAL_RUN, BC_GLOBAL_RUN); BC_GLOBAL_RUN, BC_GLOBAL_RUN);
iosf_mbi_unblock_punit_i2c_access();
return ret;
} }
static void axp288_put_role_sw(void *data) static void axp288_put_role_sw(void *data)
...@@ -384,10 +403,16 @@ static int axp288_extcon_probe(struct platform_device *pdev) ...@@ -384,10 +403,16 @@ static int axp288_extcon_probe(struct platform_device *pdev)
} }
} }
ret = iosf_mbi_block_punit_i2c_access();
if (ret < 0)
return ret;
info->vbus_attach = axp288_get_vbus_attach(info); info->vbus_attach = axp288_get_vbus_attach(info);
axp288_extcon_log_rsi(info); axp288_extcon_log_rsi(info);
iosf_mbi_unblock_punit_i2c_access();
/* Initialize extcon device */ /* Initialize extcon device */
info->edev = devm_extcon_dev_allocate(&pdev->dev, info->edev = devm_extcon_dev_allocate(&pdev->dev,
axp288_extcon_cables); axp288_extcon_cables);
...@@ -441,7 +466,9 @@ static int axp288_extcon_probe(struct platform_device *pdev) ...@@ -441,7 +466,9 @@ static int axp288_extcon_probe(struct platform_device *pdev)
} }
/* Start charger cable type detection */ /* Start charger cable type detection */
axp288_extcon_enable(info); ret = axp288_extcon_enable(info);
if (ret < 0)
return ret;
device_init_wakeup(dev, true); device_init_wakeup(dev, true);
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
*/ */
#include <linux/extcon-provider.h> #include <linux/extcon-provider.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -7,18 +7,17 @@ ...@@ -7,18 +7,17 @@
*/ */
#include <linux/extcon-provider.h> #include <linux/extcon-provider.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/mod_devicetable.h>
#define USB_GPIO_DEBOUNCE_MS 20 /* ms */ #define USB_GPIO_DEBOUNCE_MS 20 /* ms */
......
...@@ -19,15 +19,42 @@ ...@@ -19,15 +19,42 @@
#define TUSB320_REG9_ATTACHED_STATE_MASK 0x3 #define TUSB320_REG9_ATTACHED_STATE_MASK 0x3
#define TUSB320_REG9_CABLE_DIRECTION BIT(5) #define TUSB320_REG9_CABLE_DIRECTION BIT(5)
#define TUSB320_REG9_INTERRUPT_STATUS BIT(4) #define TUSB320_REG9_INTERRUPT_STATUS BIT(4)
#define TUSB320_ATTACHED_STATE_NONE 0x0
#define TUSB320_ATTACHED_STATE_DFP 0x1 #define TUSB320_REGA 0xa
#define TUSB320_ATTACHED_STATE_UFP 0x2 #define TUSB320L_REGA_DISABLE_TERM BIT(0)
#define TUSB320_ATTACHED_STATE_ACC 0x3 #define TUSB320_REGA_I2C_SOFT_RESET BIT(3)
#define TUSB320_REGA_MODE_SELECT_SHIFT 4
#define TUSB320_REGA_MODE_SELECT_MASK 0x3
#define TUSB320L_REGA0_REVISION 0xa0
enum tusb320_attached_state {
TUSB320_ATTACHED_STATE_NONE,
TUSB320_ATTACHED_STATE_DFP,
TUSB320_ATTACHED_STATE_UFP,
TUSB320_ATTACHED_STATE_ACC,
};
enum tusb320_mode {
TUSB320_MODE_PORT,
TUSB320_MODE_UFP,
TUSB320_MODE_DFP,
TUSB320_MODE_DRP,
};
struct tusb320_priv;
struct tusb320_ops {
int (*set_mode)(struct tusb320_priv *priv, enum tusb320_mode mode);
int (*get_revision)(struct tusb320_priv *priv, unsigned int *revision);
};
struct tusb320_priv { struct tusb320_priv {
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
struct extcon_dev *edev; struct extcon_dev *edev;
struct tusb320_ops *ops;
enum tusb320_attached_state state;
}; };
static const char * const tusb_attached_states[] = { static const char * const tusb_attached_states[] = {
...@@ -62,6 +89,101 @@ static int tusb320_check_signature(struct tusb320_priv *priv) ...@@ -62,6 +89,101 @@ static int tusb320_check_signature(struct tusb320_priv *priv)
return 0; return 0;
} }
static int tusb320_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
{
int ret;
/* Mode cannot be changed while cable is attached */
if (priv->state != TUSB320_ATTACHED_STATE_NONE)
return -EBUSY;
/* Write mode */
ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
mode << TUSB320_REGA_MODE_SELECT_SHIFT);
if (ret) {
dev_err(priv->dev, "failed to write mode: %d\n", ret);
return ret;
}
return 0;
}
static int tusb320l_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
{
int ret;
/* Disable CC state machine */
ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
TUSB320L_REGA_DISABLE_TERM, 1);
if (ret) {
dev_err(priv->dev,
"failed to disable CC state machine: %d\n", ret);
return ret;
}
/* Write mode */
ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
mode << TUSB320_REGA_MODE_SELECT_SHIFT);
if (ret) {
dev_err(priv->dev, "failed to write mode: %d\n", ret);
goto err;
}
msleep(5);
err:
/* Re-enable CC state machine */
ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
TUSB320L_REGA_DISABLE_TERM, 0);
if (ret)
dev_err(priv->dev,
"failed to re-enable CC state machine: %d\n", ret);
return ret;
}
static int tusb320_reset(struct tusb320_priv *priv)
{
int ret;
/* Set mode to default (follow PORT pin) */
ret = priv->ops->set_mode(priv, TUSB320_MODE_PORT);
if (ret && ret != -EBUSY) {
dev_err(priv->dev,
"failed to set mode to PORT: %d\n", ret);
return ret;
}
/* Perform soft reset */
ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
TUSB320_REGA_I2C_SOFT_RESET, 1);
if (ret) {
dev_err(priv->dev,
"failed to write soft reset bit: %d\n", ret);
return ret;
}
/* Wait for chip to go through reset */
msleep(95);
return 0;
}
static int tusb320l_get_revision(struct tusb320_priv *priv, unsigned int *revision)
{
return regmap_read(priv->regmap, TUSB320L_REGA0_REVISION, revision);
}
static struct tusb320_ops tusb320_ops = {
.set_mode = tusb320_set_mode,
};
static struct tusb320_ops tusb320l_ops = {
.set_mode = tusb320l_set_mode,
.get_revision = tusb320l_get_revision,
};
static irqreturn_t tusb320_irq_handler(int irq, void *dev_id) static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
{ {
struct tusb320_priv *priv = dev_id; struct tusb320_priv *priv = dev_id;
...@@ -96,6 +218,8 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id) ...@@ -96,6 +218,8 @@ static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
extcon_sync(priv->edev, EXTCON_USB); extcon_sync(priv->edev, EXTCON_USB);
extcon_sync(priv->edev, EXTCON_USB_HOST); extcon_sync(priv->edev, EXTCON_USB_HOST);
priv->state = state;
regmap_write(priv->regmap, TUSB320_REG9, reg); regmap_write(priv->regmap, TUSB320_REG9, reg);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -110,6 +234,8 @@ static int tusb320_extcon_probe(struct i2c_client *client, ...@@ -110,6 +234,8 @@ static int tusb320_extcon_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct tusb320_priv *priv; struct tusb320_priv *priv;
const void *match_data;
unsigned int revision;
int ret; int ret;
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
...@@ -125,12 +251,27 @@ static int tusb320_extcon_probe(struct i2c_client *client, ...@@ -125,12 +251,27 @@ static int tusb320_extcon_probe(struct i2c_client *client,
if (ret) if (ret)
return ret; return ret;
match_data = device_get_match_data(&client->dev);
if (!match_data)
return -EINVAL;
priv->ops = (struct tusb320_ops*)match_data;
priv->edev = devm_extcon_dev_allocate(priv->dev, tusb320_extcon_cable); priv->edev = devm_extcon_dev_allocate(priv->dev, tusb320_extcon_cable);
if (IS_ERR(priv->edev)) { if (IS_ERR(priv->edev)) {
dev_err(priv->dev, "failed to allocate extcon device\n"); dev_err(priv->dev, "failed to allocate extcon device\n");
return PTR_ERR(priv->edev); return PTR_ERR(priv->edev);
} }
if (priv->ops->get_revision) {
ret = priv->ops->get_revision(priv, &revision);
if (ret)
dev_warn(priv->dev,
"failed to read revision register: %d\n", ret);
else
dev_info(priv->dev, "chip revision %d\n", revision);
}
ret = devm_extcon_dev_register(priv->dev, priv->edev); ret = devm_extcon_dev_register(priv->dev, priv->edev);
if (ret < 0) { if (ret < 0) {
dev_err(priv->dev, "failed to register extcon device\n"); dev_err(priv->dev, "failed to register extcon device\n");
...@@ -145,6 +286,17 @@ static int tusb320_extcon_probe(struct i2c_client *client, ...@@ -145,6 +286,17 @@ static int tusb320_extcon_probe(struct i2c_client *client,
/* update initial state */ /* update initial state */
tusb320_irq_handler(client->irq, priv); tusb320_irq_handler(client->irq, priv);
/* Reset chip to its default state */
ret = tusb320_reset(priv);
if (ret)
dev_warn(priv->dev, "failed to reset chip: %d\n", ret);
else
/*
* State and polarity might change after a reset, so update
* them again and make sure the interrupt status bit is cleared.
*/
tusb320_irq_handler(client->irq, priv);
ret = devm_request_threaded_irq(priv->dev, client->irq, NULL, ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
tusb320_irq_handler, tusb320_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
...@@ -154,7 +306,8 @@ static int tusb320_extcon_probe(struct i2c_client *client, ...@@ -154,7 +306,8 @@ static int tusb320_extcon_probe(struct i2c_client *client,
} }
static const struct of_device_id tusb320_extcon_dt_match[] = { static const struct of_device_id tusb320_extcon_dt_match[] = {
{ .compatible = "ti,tusb320", }, { .compatible = "ti,tusb320", .data = &tusb320_ops, },
{ .compatible = "ti,tusb320l", .data = &tusb320l_ops, },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match); MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment