File Index
Files and directories
Sign in
FILE

extcon-max14526.c

File preview with syntax highlighting.

linux-6.19.14/drivers/extcon/extcon-max14526.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2
  3#include <linux/device.h>
  4#include <linux/devm-helpers.h>
  5#include <linux/delay.h>
  6#include <linux/err.h>
  7#include <linux/extcon-provider.h>
  8#include <linux/i2c.h>
  9#include <linux/mod_devicetable.h>
 10#include <linux/interrupt.h>
 11#include <linux/module.h>
 12#include <linux/pm.h>
 13#include <linux/regmap.h>
 14
 15/* I2C addresses of MUIC internal registers */
 16#define MAX14526_DEVICE_ID	0x00
 17#define MAX14526_ID		0x02
 18
 19/* CONTROL_1 register masks */
 20#define MAX14526_CONTROL_1	0x01
 21#define   ID_2P2		BIT(6)
 22#define   ID_620		BIT(5)
 23#define   ID_200		BIT(4)
 24#define   VLDO			BIT(3)
 25#define   SEMREN		BIT(2)
 26#define   ADC_EN		BIT(1)
 27#define   CP_EN			BIT(0)
 28
 29/* CONTROL_2 register masks */
 30#define MAX14526_CONTROL_2	0x02
 31#define   INTPOL		BIT(7)
 32#define   INT_EN		BIT(6)
 33#define   MIC_LP		BIT(5)
 34#define   CP_AUD		BIT(4)
 35#define   CHG_TYPE		BIT(1)
 36#define   USB_DET_DIS		BIT(0)
 37
 38/* SW_CONTROL register masks */
 39#define MAX14526_SW_CONTROL	0x03
 40#define   SW_DATA		0x00
 41#define   SW_UART		0x01
 42#define   SW_AUDIO		0x02
 43#define   SW_OPEN		0x07
 44
 45/* INT_STATUS register masks */
 46#define MAX14526_INT_STAT	0x04
 47#define   CHGDET		BIT(7)
 48#define   MR_COMP		BIT(6)
 49#define   SENDEND		BIT(5)
 50#define   V_VBUS		BIT(4)
 51
 52/* STATUS register masks */
 53#define MAX14526_STATUS		0x05
 54#define   CPORT			BIT(7)
 55#define   CHPORT		BIT(6)
 56#define   C1COMP		BIT(0)
 57
 58enum max14526_idno_resistance {
 59	MAX14526_GND,
 60	MAX14526_24KOHM,
 61	MAX14526_56KOHM,
 62	MAX14526_100KOHM,
 63	MAX14526_130KOHM,
 64	MAX14526_180KOHM,
 65	MAX14526_240KOHM,
 66	MAX14526_330KOHM,
 67	MAX14526_430KOHM,
 68	MAX14526_620KOHM,
 69	MAX14526_910KOHM,
 70	MAX14526_OPEN
 71};
 72
 73enum max14526_field_idx {
 74	VENDOR_ID, CHIP_REV,		/* DEVID */
 75	DM, DP,				/* SW_CONTROL */
 76	MAX14526_N_REGMAP_FIELDS
 77};
 78
 79static const struct reg_field max14526_reg_field[MAX14526_N_REGMAP_FIELDS] = {
 80	[VENDOR_ID] = REG_FIELD(MAX14526_DEVICE_ID,  4, 7),
 81	[CHIP_REV]  = REG_FIELD(MAX14526_DEVICE_ID,  0, 3),
 82	[DM]        = REG_FIELD(MAX14526_SW_CONTROL, 0, 2),
 83	[DP]        = REG_FIELD(MAX14526_SW_CONTROL, 3, 5),
 84};
 85
 86struct max14526_data {
 87	struct i2c_client *client;
 88	struct extcon_dev *edev;
 89
 90	struct regmap *regmap;
 91	struct regmap_field *rfield[MAX14526_N_REGMAP_FIELDS];
 92
 93	int last_state;
 94	int cable;
 95};
 96
 97enum max14526_muic_modes {
 98	MAX14526_OTG     = MAX14526_GND, /* no power */
 99	MAX14526_MHL     = MAX14526_56KOHM, /* no power */
100	MAX14526_OTG_Y   = MAX14526_GND | V_VBUS,
101	MAX14526_MHL_CHG = MAX14526_GND | V_VBUS | CHGDET,
102	MAX14526_NONE    = MAX14526_OPEN,
103	MAX14526_USB     = MAX14526_OPEN | V_VBUS,
104	MAX14526_CHG     = MAX14526_OPEN | V_VBUS | CHGDET,
105};
106
107static const unsigned int max14526_extcon_cable[] = {
108	EXTCON_USB,
109	EXTCON_USB_HOST,
110	EXTCON_CHG_USB_FAST,
111	EXTCON_DISP_MHL,
112	EXTCON_NONE,
113};
114
115static int max14526_ap_usb_mode(struct max14526_data *priv)
116{
117	struct device *dev = &priv->client->dev;
118	int ret;
119
120	/* Enable USB Path */
121	ret = regmap_field_write(priv->rfield[DM], SW_DATA);
122	if (ret)
123		return ret;
124
125	ret = regmap_field_write(priv->rfield[DP], SW_DATA);
126	if (ret)
127		return ret;
128
129	/* Enable 200K, Charger Pump and ADC */
130	ret = regmap_write(priv->regmap, MAX14526_CONTROL_1,
131			   ID_200 | ADC_EN | CP_EN);
132	if (ret)
133		return ret;
134
135	dev_dbg(dev, "AP USB mode set\n");
136
137	return 0;
138}
139
140static irqreturn_t max14526_interrupt(int irq, void *dev_id)
141{
142	struct max14526_data *priv = dev_id;
143	struct device *dev = &priv->client->dev;
144	int state, ret;
145
146	/*
147	 * Upon an MUIC IRQ (MUIC_INT_N falls), wait at least 70ms
148	 * before reading INT_STAT and STATUS. After the reads,
149	 * MUIC_INT_N returns to high (but the INT_STAT and STATUS
150	 * contents will be held).
151	 */
152	msleep(100);
153
154	ret = regmap_read(priv->regmap, MAX14526_INT_STAT, &state);
155	if (ret)
156		dev_err(dev, "failed to read MUIC state %d\n", ret);
157
158	if (state == priv->last_state)
159		return IRQ_HANDLED;
160
161	/* Detach previous device */
162	extcon_set_state_sync(priv->edev, priv->cable, false);
163
164	switch (state) {
165	case MAX14526_USB:
166		priv->cable = EXTCON_USB;
167		break;
168
169	case MAX14526_CHG:
170		priv->cable = EXTCON_CHG_USB_FAST;
171		break;
172
173	case MAX14526_OTG:
174	case MAX14526_OTG_Y:
175		priv->cable = EXTCON_USB_HOST;
176		break;
177
178	case MAX14526_MHL:
179	case MAX14526_MHL_CHG:
180		priv->cable = EXTCON_DISP_MHL;
181		break;
182
183	case MAX14526_NONE:
184	default:
185		priv->cable = EXTCON_NONE;
186		break;
187	}
188
189	extcon_set_state_sync(priv->edev, priv->cable, true);
190
191	priv->last_state = state;
192
193	return IRQ_HANDLED;
194}
195
196static const struct regmap_config max14526_regmap_config = {
197	.reg_bits = 8,
198	.val_bits = 8,
199	.max_register = MAX14526_STATUS,
200};
201
202static int max14526_probe(struct i2c_client *client)
203{
204	struct device *dev = &client->dev;
205	struct max14526_data *priv;
206	int ret, dev_id, rev, i;
207
208	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
209	if (!priv)
210		return -ENOMEM;
211
212	priv->client = client;
213	i2c_set_clientdata(client, priv);
214
215	priv->regmap = devm_regmap_init_i2c(client, &max14526_regmap_config);
216	if (IS_ERR(priv->regmap))
217		return dev_err_probe(dev, PTR_ERR(priv->regmap), "cannot allocate regmap\n");
218
219	for (i = 0; i < MAX14526_N_REGMAP_FIELDS; i++) {
220		priv->rfield[i] = devm_regmap_field_alloc(dev, priv->regmap,
221							  max14526_reg_field[i]);
222		if (IS_ERR(priv->rfield[i]))
223			return dev_err_probe(dev, PTR_ERR(priv->rfield[i]),
224					     "cannot allocate regmap field\n");
225	}
226
227	/* Detect if MUIC version is supported */
228	ret = regmap_field_read(priv->rfield[VENDOR_ID], &dev_id);
229	if (ret)
230		return dev_err_probe(dev, ret, "failed to read MUIC ID\n");
231
232	regmap_field_read(priv->rfield[CHIP_REV], &rev);
233
234	if (dev_id == MAX14526_ID)
235		dev_info(dev, "detected MAX14526 MUIC with id 0x%x, rev 0x%x\n", dev_id, rev);
236	else
237		dev_err_probe(dev, -EINVAL, "MUIC vendor id 0x%X is not recognized\n", dev_id);
238
239	priv->edev = devm_extcon_dev_allocate(dev, max14526_extcon_cable);
240	if (IS_ERR(priv->edev))
241		return dev_err_probe(dev, (IS_ERR(priv->edev)),
242				     "failed to allocate extcon device\n");
243
244	ret = devm_extcon_dev_register(dev, priv->edev);
245	if (ret < 0)
246		return dev_err_probe(dev, ret, "failed to register extcon device\n");
247
248	ret = max14526_ap_usb_mode(priv);
249	if (ret < 0)
250		return dev_err_probe(dev, ret, "failed to set AP USB mode\n");
251
252	regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, INT_EN, INT_EN);
253	regmap_write_bits(priv->regmap, MAX14526_CONTROL_2, USB_DET_DIS, (u32)~USB_DET_DIS);
254
255	ret = devm_request_threaded_irq(dev, client->irq, NULL, &max14526_interrupt,
256					IRQF_ONESHOT | IRQF_SHARED, client->name, priv);
257	if (ret)
258		return dev_err_probe(dev, ret, "failed to register IRQ\n");
259
260	irq_wake_thread(client->irq, priv);
261
262	return 0;
263}
264
265static int max14526_resume(struct device *dev)
266{
267	struct i2c_client *client = to_i2c_client(dev);
268	struct max14526_data *priv = i2c_get_clientdata(client);
269
270	irq_wake_thread(client->irq, priv);
271
272	return 0;
273}
274
275static DEFINE_SIMPLE_DEV_PM_OPS(max14526_pm_ops, NULL, max14526_resume);
276
277static const struct of_device_id max14526_match[] = {
278	{ .compatible = "maxim,max14526" },
279	{ /* sentinel */ }
280};
281MODULE_DEVICE_TABLE(of, max14526_match);
282
283static const struct i2c_device_id max14526_id[] = {
284	{ "max14526" },
285	{ }
286};
287MODULE_DEVICE_TABLE(i2c, max14526_id);
288
289static struct i2c_driver max14526_driver = {
290	.driver = {
291		.name = "max14526",
292		.of_match_table = max14526_match,
293		.pm = &max14526_pm_ops,
294	},
295	.probe = max14526_probe,
296	.id_table = max14526_id,
297};
298module_i2c_driver(max14526_driver);
299
300MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
301MODULE_DESCRIPTION("MAX14526 extcon driver to support MUIC");
302MODULE_LICENSE("GPL");
~/ Read-only file preview.