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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEsSpuqBtbWtRe4rLGnM3fLN7rz1MFAmF44TsWHGN3MDAuY2hv
 aUBzYW1zdW5nLmNvbQAKCRCczd8s3uvPU2wLD/48IvHZQUFatPwBgbGiKqCzCfdT
 7cK8pewTGUdEFLe1kMZssy35k39KQzj8uU+leUBasZ9HCSMGv6MTj7j0RWkHyygR
 dkcT7jX0i1lK324pMGv/qH3BLJUJC+ayJiYf1xcOWX743ykqLl9nQSTjgRKv9nUP
 QErkeEn4sTWi5wn4h0ZiLvPiZKjNLeXymUoU0XDsX5ngIccMGo/J2G4fPTJRUtb6
 kUN/Ep1niftu6MJVhGSjAFoyeNUWMEjNwk9E6RGLR2TW8EiNvOyiqAkx/EP+ad6p
 p5VrVoo1DwG/J1+VpQt+ugtOTib2GdiZ6Q5AfHxoQru93S/Yth91D83/CAPBpLOf
 AFLIv2uW/vrz6zvl3UDQ9JGZPQrlxhYhvkj10vi+FdxrQbW88pNTkiPBXrRsZ4jv
 7zg0gX0Q8LW6nEusWuzi0UzKPA8pQAl9RnGIV9TgxpCTaWtpDT7ynyaNnGJ9fsen
 URZYvUs2H/UvZVgNrbJLPMY8LDQxF1fZArTT3/qBE8lgAkxg0e+zMmNP5UOamUUJ
 9htr9tvOlFzI9IdOhmuMyk+yxYwsCHAkp6h+9tE7y8r+5gMdp/MmFN5RbsD9GGND
 uXmVUE5bqsYuQlEfquYnUX8aYWY5QLxmodlpQM2mPtVYDycg9ZR7y8Ubbb7iETYe
 nugbNhiJUMG+3stS6g==
 =qEVD
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Greg Kroah-Hartman 2021-10-27 16:49:55 +02:00
commit db788e6bf6
6 changed files with 192 additions and 12 deletions

View File

@ -11,7 +11,9 @@ maintainers:
properties:
compatible:
const: ti,tusb320
enum:
- ti,tusb320
- ti,tusb320l
reg:
maxItems: 1

View File

@ -23,7 +23,7 @@ config EXTCON_ADC_JACK
config EXTCON_AXP288
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
help
Say Y here to enable support for USB peripheral detection

View File

@ -24,6 +24,7 @@
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/iosf_mbi.h>
/* Power source status register */
#define PS_STAT_VBUS_TRIGGER BIT(0)
@ -215,6 +216,10 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
unsigned int cable = info->previous_cable;
bool vbus_attach = false;
ret = iosf_mbi_block_punit_i2c_access();
if (ret < 0)
return ret;
vbus_attach = axp288_get_vbus_attach(info);
if (!vbus_attach)
goto no_vbus;
@ -253,6 +258,8 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
}
no_vbus:
iosf_mbi_unblock_punit_i2c_access();
extcon_set_state_sync(info->edev, info->previous_cable, false);
if (info->previous_cable == EXTCON_CHG_USB_SDP)
extcon_set_state_sync(info->edev, EXTCON_USB, false);
@ -275,6 +282,8 @@ no_vbus:
return 0;
dev_det_ret:
iosf_mbi_unblock_punit_i2c_access();
if (ret < 0)
dev_err(info->dev, "failed to detect BC Mod\n");
@ -305,13 +314,23 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data)
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,
BC_GLOBAL_RUN, 0);
/* Enable the charger detection logic */
regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
BC_GLOBAL_RUN, BC_GLOBAL_RUN);
iosf_mbi_unblock_punit_i2c_access();
return ret;
}
static void axp288_put_role_sw(void *data)
@ -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);
axp288_extcon_log_rsi(info);
iosf_mbi_unblock_punit_i2c_access();
/* Initialize extcon device */
info->edev = devm_extcon_dev_allocate(&pdev->dev,
axp288_extcon_cables);
@ -441,7 +466,9 @@ static int axp288_extcon_probe(struct platform_device *pdev)
}
/* Start charger cable type detection */
axp288_extcon_enable(info);
ret = axp288_extcon_enable(info);
if (ret < 0)
return ret;
device_init_wakeup(dev, true);
platform_set_drvdata(pdev, info);

View File

@ -7,7 +7,6 @@
*/
#include <linux/extcon-provider.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/module.h>

View File

@ -7,18 +7,17 @@
*/
#include <linux/extcon-provider.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mod_devicetable.h>
#define USB_GPIO_DEBOUNCE_MS 20 /* ms */

View File

@ -19,15 +19,42 @@
#define TUSB320_REG9_ATTACHED_STATE_MASK 0x3
#define TUSB320_REG9_CABLE_DIRECTION BIT(5)
#define TUSB320_REG9_INTERRUPT_STATUS BIT(4)
#define TUSB320_ATTACHED_STATE_NONE 0x0
#define TUSB320_ATTACHED_STATE_DFP 0x1
#define TUSB320_ATTACHED_STATE_UFP 0x2
#define TUSB320_ATTACHED_STATE_ACC 0x3
#define TUSB320_REGA 0xa
#define TUSB320L_REGA_DISABLE_TERM BIT(0)
#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 device *dev;
struct regmap *regmap;
struct extcon_dev *edev;
struct tusb320_ops *ops;
enum tusb320_attached_state state;
};
static const char * const tusb_attached_states[] = {
@ -62,6 +89,101 @@ static int tusb320_check_signature(struct tusb320_priv *priv)
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)
{
struct tusb320_priv *priv = 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_HOST);
priv->state = state;
regmap_write(priv->regmap, TUSB320_REG9, reg);
return IRQ_HANDLED;
@ -110,6 +234,8 @@ static int tusb320_extcon_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tusb320_priv *priv;
const void *match_data;
unsigned int revision;
int ret;
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
@ -125,12 +251,27 @@ static int tusb320_extcon_probe(struct i2c_client *client,
if (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);
if (IS_ERR(priv->edev)) {
dev_err(priv->dev, "failed to allocate extcon device\n");
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);
if (ret < 0) {
dev_err(priv->dev, "failed to register extcon device\n");
@ -145,6 +286,17 @@ static int tusb320_extcon_probe(struct i2c_client *client,
/* update initial state */
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,
tusb320_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
@ -154,7 +306,8 @@ static int tusb320_extcon_probe(struct i2c_client *client,
}
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);