// SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include #include #include #include #include /* I2C addresses of MUIC internal registers */ #define MAX14526_DEVICE_ID 0x00 #define MAX14526_ID 0x02 /* CONTROL_1 register masks */ #define MAX14526_CONTROL_1 0x01 #define ID_2P2 BIT(6) #define ID_620 BIT(5) #define ID_200 BIT(4) #define VLDO BIT(3) #define SEMREN BIT(2) #define ADC_EN BIT(1) #define CP_EN BIT(0) /* CONTROL_2 register masks */ #define MAX14526_CONTROL_2 0x02 #define INTPOL BIT(7) #define INT_EN BIT(6) #define MIC_LP BIT(5) #define CP_AUD BIT(4) #define CHG_TYPE BIT(1) #define USB_DET_DIS BIT(0) /* SW_CONTROL register masks */ #define MAX14526_SW_CONTROL 0x03 #define SW_DATA 0x00 #define SW_UART 0x01 #define SW_AUDIO 0x02 #define SW_OPEN 0x07 /* INT_STATUS register masks */ #define MAX14526_INT_STAT 0x04 #define CHGDET BIT(7) #define MR_COMP BIT(6) #define SENDEND BIT(5) #define V_VBUS BIT(4) /* STATUS register masks */ #define MAX14526_STATUS 0x05 #define CPORT BIT(7) #define CHPORT BIT(6) #define C1COMP BIT(0) enum max14526_idno_resistance { MAX14526_GND, MAX14526_24KOHM, MAX14526_56KOHM, MAX14526_100KOHM, MAX14526_130KOHM, MAX14526_180KOHM, MAX14526_240KOHM, MAX14526_330KOHM, MAX14526_430KOHM, MAX14526_620KOHM, MAX14526_910KOHM, MAX14526_OPEN }; enum max14526_field_idx { VENDOR_ID, CHIP_REV, /* DEVID */ DM, DP, /* SW_CONTROL */ MAX14526_N_REGMAP_FIELDS }; static const struct reg_field max14526_reg_field[MAX14526_N_REGMAP_FIELDS] = { [VENDOR_ID] = REG_FIELD(MAX14526_DEVICE_ID, 4, 7), [CHIP_REV] = REG_FIELD(MAX14526_DEVICE_ID, 0, 3), [DM] = REG_FIELD(MAX14526_SW_CONTROL, 0, 2), [DP] = REG_FIELD(MAX14526_SW_CONTROL, 3, 5), }; struct max14526_data { struct i2c_client *client; struct extcon_dev *edev; struct regmap *regmap; struct regmap_field *rfield[MAX14526_N_REGMAP_FIELDS]; int last_state; int cable; }; enum max14526_muic_modes { MAX14526_OTG = MAX14526_GND, /* no power */ MAX14526_MHL = MAX14526_56KOHM, /* no power */ MAX14526_OTG_Y = MAX14526_GND | V_VBUS, MAX14526_MHL_CHG = MAX14526_GND | V_VBUS | CHGDET, MAX14526_NONE = MAX14526_OPEN, MAX14526_USB = MAX14526_OPEN | V_VBUS, MAX14526_CHG = MAX14526_OPEN | V_VBUS | CHGDET, }; static const unsigned int max14526_extcon_cable[] = { EXTCON_USB, EXTCON_USB_HOST, EXTCON_CHG_USB_FAST, EXTCON_DISP_MHL, EXTCON_NONE, }; static int max14526_ap_usb_mode(struct max14526_data *priv) { struct device *dev = &priv->client->dev; int ret; /* Enable USB Path */ ret = regmap_field_write(priv->rfield[DM], SW_DATA); if (ret) return ret; ret = regmap_field_write(priv->rfield[DP], SW_DATA); if (ret) return ret; /* Enable 200K, Charger Pump and ADC */ ret = regmap_write(priv->regmap, MAX14526_CONTROL_1, ID_200 | ADC_EN | CP_EN); if (ret) return ret; dev_dbg(dev, "AP USB mode set\n"); return 0; } static irqreturn_t max14526_interrupt(int irq, void *dev_id) { struct max14526_data *priv = dev_id; struct device *dev = &priv->client->dev; int state, ret; /* * Upon an MUIC IRQ (MUIC_INT_N falls), wait at least 70ms * before reading INT_STAT and STATUS. After the reads, * MUIC_INT_N returns to high (but the INT_STAT and STATUS * contents will be held). */ msleep(100); ret = regmap_read(priv->regmap, MAX14526_INT_STAT, &state); if (ret) dev_err(dev, "failed to read MUIC state %d\n", ret); if (state == priv->last_state) return IRQ_HANDLED; /* Detach previous device */ extcon_set_state_sync(priv->edev, priv->cable, false); switch (state) { case MAX14526_USB: priv->cable = EXTCON_USB; break; case MAX14526_CHG: priv->cable = EXTCON_CHG_USB_FAST; break; case MAX14526_OTG: case MAX14526_OTG_Y: priv->cable = EXTCON_USB_HOST; break; case MAX14526_MHL: case MAX14526_MHL_CHG: priv->cable = EXTCON_DISP_MHL; break; case MAX14526_NONE: default: priv->cable = EXTCON_NONE; break; } extcon_set_state_sync(priv->edev, priv->cable, true); priv->last_state = state; return IRQ_HANDLED; } static const struct regmap_config max14526_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = MAX14526_STATUS, }; static int max14526_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct max14526_data *priv; int ret, dev_id, rev, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->client = client; i2c_set_clientdata(client, priv); priv->regmap = devm_regmap_init_i2c(client, &max14526_regmap_config); if (IS_ERR(priv->regmap)) return dev_err_probe(dev, PTR_ERR(priv->regmap), "cannot allocate regmap\n"); for (i = 0; i < MAX14526_N_REGMAP_FIELDS; i++) { priv->rfield[i] = devm_regmap_field_alloc(dev, priv->regmap, max14526_reg_field[i]); if (IS_ERR(priv->rfield[i])) return dev_err_probe(dev, PTR_ERR(priv->rfield[i]), "cannot allocate regmap field\n"); } /* Detect if MUIC version is supported */ ret = regmap_field_read(priv->rfield[VENDOR_ID], &dev_id); if (ret) return dev_err_probe(dev, ret, "failed to read MUIC ID\n"); regmap_field_read(priv->rfield[CHIP_REV], &rev); if (dev_id == MAX14526_ID) dev_info(dev, "detected MAX14526 MUIC with id 0x%x, rev 0x%x\n", dev_id, rev); else dev_err_probe(dev, -EINVAL, "MUIC vendor id 0x%X is not recognized\n", dev_id); priv->edev = devm_extcon_dev_allocate(dev, max14526_extcon_cable); if (IS_ERR(priv->edev)) return dev_err_probe(dev, (IS_ERR(priv->edev)), "failed to allocate extcon device\n"); ret = devm_extcon_dev_register(dev, priv->edev); if (ret < 0) return dev_err_probe(dev, ret, "failed to register extcon device\n"); ret = max14526_ap_usb_mode(priv); if (ret < 0) return dev_err_probe(dev, ret, "failed to set AP USB mode\n"); regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, INT_EN, INT_EN); regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, USB_DET_DIS, (u32)~USB_DET_DIS); ret = devm_request_threaded_irq(dev, client->irq, NULL, &max14526_interrupt, IRQF_ONESHOT | IRQF_SHARED, client->name, priv); if (ret) return dev_err_probe(dev, ret, "failed to register IRQ\n"); irq_wake_thread(client->irq, priv); return 0; } static int max14526_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct max14526_data *priv = i2c_get_clientdata(client); irq_wake_thread(client->irq, priv); return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(max14526_pm_ops, NULL, max14526_resume); static const struct of_device_id max14526_match[] = { { .compatible = "maxim,max14526" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, max14526_match); static const struct i2c_device_id max14526_id[] = { { "max14526" }, { } }; MODULE_DEVICE_TABLE(i2c, max14526_id); static struct i2c_driver max14526_driver = { .driver = { .name = "max14526", .of_match_table = max14526_match, .pm = &max14526_pm_ops, }, .probe = max14526_probe, .id_table = max14526_id, }; module_i2c_driver(max14526_driver); MODULE_AUTHOR("Svyatoslav Ryhel "); MODULE_DESCRIPTION("MAX14526 extcon driver to support MUIC"); MODULE_LICENSE("GPL");