xref: /linux/drivers/power/supply/max14656_charger_detector.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1f71e7375SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29d60595aSAlexander Kurz /*
39d60595aSAlexander Kurz  * Maxim MAX14656 / AL32 USB Charger Detector driver
49d60595aSAlexander Kurz  *
59d60595aSAlexander Kurz  * Copyright (C) 2014 LG Electronics, Inc
69d60595aSAlexander Kurz  * Copyright (C) 2016 Alexander Kurz <akurz@blala.de>
79d60595aSAlexander Kurz  *
89d60595aSAlexander Kurz  * Components from Maxim AL32 Charger detection Driver for MX50 Yoshi Board
99d60595aSAlexander Kurz  * Copyright (C) Amazon Technologies Inc. All rights reserved.
109d60595aSAlexander Kurz  * Manish Lachwani (lachwani@lab126.com)
119d60595aSAlexander Kurz  */
129d60595aSAlexander Kurz #include <linux/module.h>
139d60595aSAlexander Kurz #include <linux/init.h>
149d60595aSAlexander Kurz #include <linux/delay.h>
159d60595aSAlexander Kurz #include <linux/i2c.h>
169d60595aSAlexander Kurz #include <linux/interrupt.h>
172ce8284cSRob Herring #include <linux/mod_devicetable.h>
189d60595aSAlexander Kurz #include <linux/slab.h>
199d60595aSAlexander Kurz #include <linux/workqueue.h>
209d60595aSAlexander Kurz #include <linux/power_supply.h>
21d016fc7aSChristophe JAILLET #include <linux/devm-helpers.h>
229d60595aSAlexander Kurz 
239d60595aSAlexander Kurz #define MAX14656_MANUFACTURER	"Maxim Integrated"
249d60595aSAlexander Kurz #define MAX14656_NAME		"max14656"
259d60595aSAlexander Kurz 
269d60595aSAlexander Kurz #define MAX14656_DEVICE_ID	0x00
279d60595aSAlexander Kurz #define MAX14656_INTERRUPT_1	0x01
289d60595aSAlexander Kurz #define MAX14656_INTERRUPT_2	0x02
299d60595aSAlexander Kurz #define MAX14656_STATUS_1	0x03
309d60595aSAlexander Kurz #define MAX14656_STATUS_2	0x04
319d60595aSAlexander Kurz #define MAX14656_INTMASK_1	0x05
329d60595aSAlexander Kurz #define MAX14656_INTMASK_2	0x06
339d60595aSAlexander Kurz #define MAX14656_CONTROL_1	0x07
349d60595aSAlexander Kurz #define MAX14656_CONTROL_2	0x08
359d60595aSAlexander Kurz #define MAX14656_CONTROL_3	0x09
369d60595aSAlexander Kurz 
379d60595aSAlexander Kurz #define DEVICE_VENDOR_MASK	0xf0
389d60595aSAlexander Kurz #define DEVICE_REV_MASK		0x0f
399d60595aSAlexander Kurz #define INT_EN_REG_MASK		BIT(4)
409d60595aSAlexander Kurz #define CHG_TYPE_INT_MASK	BIT(0)
419d60595aSAlexander Kurz #define STATUS1_VB_VALID_MASK	BIT(4)
429d60595aSAlexander Kurz #define STATUS1_CHG_TYPE_MASK	0xf
439d60595aSAlexander Kurz #define INT1_DCD_TIMEOUT_MASK	BIT(7)
449d60595aSAlexander Kurz #define CONTROL1_DEFAULT	0x0d
459d60595aSAlexander Kurz #define CONTROL1_INT_EN		BIT(4)
469d60595aSAlexander Kurz #define CONTROL1_INT_ACTIVE_HIGH	BIT(5)
479d60595aSAlexander Kurz #define CONTROL1_EDGE		BIT(7)
489d60595aSAlexander Kurz #define CONTROL2_DEFAULT	0x8e
499d60595aSAlexander Kurz #define CONTROL2_ADC_EN		BIT(0)
509d60595aSAlexander Kurz #define CONTROL3_DEFAULT	0x8d
519d60595aSAlexander Kurz 
529d60595aSAlexander Kurz enum max14656_chg_type {
539d60595aSAlexander Kurz 	MAX14656_NO_CHARGER	= 0,
549d60595aSAlexander Kurz 	MAX14656_SDP_CHARGER,
559d60595aSAlexander Kurz 	MAX14656_CDP_CHARGER,
569d60595aSAlexander Kurz 	MAX14656_DCP_CHARGER,
579d60595aSAlexander Kurz 	MAX14656_APPLE_500MA_CHARGER,
589d60595aSAlexander Kurz 	MAX14656_APPLE_1A_CHARGER,
599d60595aSAlexander Kurz 	MAX14656_APPLE_2A_CHARGER,
609d60595aSAlexander Kurz 	MAX14656_SPECIAL_500MA_CHARGER,
619d60595aSAlexander Kurz 	MAX14656_APPLE_12W,
629d60595aSAlexander Kurz 	MAX14656_CHARGER_LAST
639d60595aSAlexander Kurz };
649d60595aSAlexander Kurz 
659d60595aSAlexander Kurz static const struct max14656_chg_type_props {
669d60595aSAlexander Kurz 	enum power_supply_type type;
679d60595aSAlexander Kurz } chg_type_props[] = {
689d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_UNKNOWN },
699d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB },
709d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_CDP },
719d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_DCP },
729d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_DCP },
739d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_DCP },
749d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_DCP },
759d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB_DCP },
769d60595aSAlexander Kurz 	{ POWER_SUPPLY_TYPE_USB },
779d60595aSAlexander Kurz };
789d60595aSAlexander Kurz 
799d60595aSAlexander Kurz struct max14656_chip {
809d60595aSAlexander Kurz 	struct i2c_client	*client;
819d60595aSAlexander Kurz 	struct power_supply	*detect_psy;
829d60595aSAlexander Kurz 	struct power_supply_desc psy_desc;
839d60595aSAlexander Kurz 	struct delayed_work	irq_work;
849d60595aSAlexander Kurz 
859d60595aSAlexander Kurz 	int irq;
869d60595aSAlexander Kurz 	int online;
879d60595aSAlexander Kurz };
889d60595aSAlexander Kurz 
max14656_read_reg(struct i2c_client * client,int reg,u8 * val)899d60595aSAlexander Kurz static int max14656_read_reg(struct i2c_client *client, int reg, u8 *val)
909d60595aSAlexander Kurz {
919d60595aSAlexander Kurz 	s32 ret;
929d60595aSAlexander Kurz 
939d60595aSAlexander Kurz 	ret = i2c_smbus_read_byte_data(client, reg);
949d60595aSAlexander Kurz 	if (ret < 0) {
959d60595aSAlexander Kurz 		dev_err(&client->dev,
969d60595aSAlexander Kurz 			"i2c read fail: can't read from %02x: %d\n",
979d60595aSAlexander Kurz 			reg, ret);
989d60595aSAlexander Kurz 		return ret;
999d60595aSAlexander Kurz 	}
1009d60595aSAlexander Kurz 	*val = ret;
1019d60595aSAlexander Kurz 	return 0;
1029d60595aSAlexander Kurz }
1039d60595aSAlexander Kurz 
max14656_write_reg(struct i2c_client * client,int reg,u8 val)1049d60595aSAlexander Kurz static int max14656_write_reg(struct i2c_client *client, int reg, u8 val)
1059d60595aSAlexander Kurz {
1069d60595aSAlexander Kurz 	s32 ret;
1079d60595aSAlexander Kurz 
1089d60595aSAlexander Kurz 	ret = i2c_smbus_write_byte_data(client, reg, val);
1099d60595aSAlexander Kurz 	if (ret < 0) {
1109d60595aSAlexander Kurz 		dev_err(&client->dev,
1119d60595aSAlexander Kurz 			"i2c write fail: can't write %02x to %02x: %d\n",
1129d60595aSAlexander Kurz 			val, reg, ret);
1139d60595aSAlexander Kurz 		return ret;
1149d60595aSAlexander Kurz 	}
1159d60595aSAlexander Kurz 	return 0;
1169d60595aSAlexander Kurz }
1179d60595aSAlexander Kurz 
max14656_read_block_reg(struct i2c_client * client,u8 reg,u8 length,u8 * val)1189d60595aSAlexander Kurz static int max14656_read_block_reg(struct i2c_client *client, u8 reg,
1199d60595aSAlexander Kurz 				  u8 length, u8 *val)
1209d60595aSAlexander Kurz {
1219d60595aSAlexander Kurz 	int ret;
1229d60595aSAlexander Kurz 
1239d60595aSAlexander Kurz 	ret = i2c_smbus_read_i2c_block_data(client, reg, length, val);
1249d60595aSAlexander Kurz 	if (ret < 0) {
1259d60595aSAlexander Kurz 		dev_err(&client->dev, "failed to block read reg 0x%x: %d\n",
1269d60595aSAlexander Kurz 				reg, ret);
1279d60595aSAlexander Kurz 		return ret;
1289d60595aSAlexander Kurz 	}
1299d60595aSAlexander Kurz 
1309d60595aSAlexander Kurz 	return 0;
1319d60595aSAlexander Kurz }
1329d60595aSAlexander Kurz 
1339d60595aSAlexander Kurz #define        REG_TOTAL_NUM   5
max14656_irq_worker(struct work_struct * work)1349d60595aSAlexander Kurz static void max14656_irq_worker(struct work_struct *work)
1359d60595aSAlexander Kurz {
1369d60595aSAlexander Kurz 	struct max14656_chip *chip =
1379d60595aSAlexander Kurz 		container_of(work, struct max14656_chip, irq_work.work);
1389d60595aSAlexander Kurz 
1399d60595aSAlexander Kurz 	u8 buf[REG_TOTAL_NUM];
1409d60595aSAlexander Kurz 	u8 chg_type;
1419d60595aSAlexander Kurz 
142f05ec507SJason Yan 	max14656_read_block_reg(chip->client, MAX14656_DEVICE_ID,
1439d60595aSAlexander Kurz 				REG_TOTAL_NUM, buf);
1449d60595aSAlexander Kurz 
1459d60595aSAlexander Kurz 	if ((buf[MAX14656_STATUS_1] & STATUS1_VB_VALID_MASK) &&
1469d60595aSAlexander Kurz 		(buf[MAX14656_STATUS_1] & STATUS1_CHG_TYPE_MASK)) {
1479d60595aSAlexander Kurz 		chg_type = buf[MAX14656_STATUS_1] & STATUS1_CHG_TYPE_MASK;
1489d60595aSAlexander Kurz 		if (chg_type < MAX14656_CHARGER_LAST)
1499d60595aSAlexander Kurz 			chip->psy_desc.type = chg_type_props[chg_type].type;
1509d60595aSAlexander Kurz 		else
1519d60595aSAlexander Kurz 			chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
1529d60595aSAlexander Kurz 		chip->online = 1;
1539d60595aSAlexander Kurz 	} else {
1549d60595aSAlexander Kurz 		chip->online = 0;
1559d60595aSAlexander Kurz 		chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
1569d60595aSAlexander Kurz 	}
1579d60595aSAlexander Kurz 
1589d60595aSAlexander Kurz 	power_supply_changed(chip->detect_psy);
1599d60595aSAlexander Kurz }
1609d60595aSAlexander Kurz 
max14656_irq(int irq,void * dev_id)1619d60595aSAlexander Kurz static irqreturn_t max14656_irq(int irq, void *dev_id)
1629d60595aSAlexander Kurz {
1639d60595aSAlexander Kurz 	struct max14656_chip *chip = dev_id;
1649d60595aSAlexander Kurz 
1659d60595aSAlexander Kurz 	schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(100));
1669d60595aSAlexander Kurz 
1679d60595aSAlexander Kurz 	return IRQ_HANDLED;
1689d60595aSAlexander Kurz }
1699d60595aSAlexander Kurz 
max14656_hw_init(struct max14656_chip * chip)1709d60595aSAlexander Kurz static int max14656_hw_init(struct max14656_chip *chip)
1719d60595aSAlexander Kurz {
1729d60595aSAlexander Kurz 	uint8_t val = 0;
1739d60595aSAlexander Kurz 	uint8_t rev;
1749d60595aSAlexander Kurz 	struct i2c_client *client = chip->client;
1759d60595aSAlexander Kurz 
1769d60595aSAlexander Kurz 	if (max14656_read_reg(client, MAX14656_DEVICE_ID, &val))
1779d60595aSAlexander Kurz 		return -ENODEV;
1789d60595aSAlexander Kurz 
1799d60595aSAlexander Kurz 	if ((val & DEVICE_VENDOR_MASK) != 0x20) {
1809d60595aSAlexander Kurz 		dev_err(&client->dev, "wrong vendor ID %d\n",
1819d60595aSAlexander Kurz 			((val & DEVICE_VENDOR_MASK) >> 4));
1829d60595aSAlexander Kurz 		return -ENODEV;
1839d60595aSAlexander Kurz 	}
1849d60595aSAlexander Kurz 	rev = val & DEVICE_REV_MASK;
1859d60595aSAlexander Kurz 
1869d60595aSAlexander Kurz 	/* Turn on ADC_EN */
1879d60595aSAlexander Kurz 	if (max14656_write_reg(client, MAX14656_CONTROL_2, CONTROL2_ADC_EN))
1889d60595aSAlexander Kurz 		return -EINVAL;
1899d60595aSAlexander Kurz 
1909d60595aSAlexander Kurz 	/* turn on interrupts and low power mode */
1919d60595aSAlexander Kurz 	if (max14656_write_reg(client, MAX14656_CONTROL_1,
1929d60595aSAlexander Kurz 		CONTROL1_DEFAULT |
1939d60595aSAlexander Kurz 		CONTROL1_INT_EN |
1949d60595aSAlexander Kurz 		CONTROL1_INT_ACTIVE_HIGH |
1959d60595aSAlexander Kurz 		CONTROL1_EDGE))
1969d60595aSAlexander Kurz 		return -EINVAL;
1979d60595aSAlexander Kurz 
1989d60595aSAlexander Kurz 	if (max14656_write_reg(client, MAX14656_INTMASK_1, 0x3))
1999d60595aSAlexander Kurz 		return -EINVAL;
2009d60595aSAlexander Kurz 
2019d60595aSAlexander Kurz 	if (max14656_write_reg(client, MAX14656_INTMASK_2, 0x1))
2029d60595aSAlexander Kurz 		return -EINVAL;
2039d60595aSAlexander Kurz 
2049d60595aSAlexander Kurz 	dev_info(&client->dev, "detected revision %d\n", rev);
2059d60595aSAlexander Kurz 	return 0;
2069d60595aSAlexander Kurz }
2079d60595aSAlexander Kurz 
max14656_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)2089d60595aSAlexander Kurz static int max14656_get_property(struct power_supply *psy,
2099d60595aSAlexander Kurz 			    enum power_supply_property psp,
2109d60595aSAlexander Kurz 			    union power_supply_propval *val)
2119d60595aSAlexander Kurz {
2129d60595aSAlexander Kurz 	struct max14656_chip *chip = power_supply_get_drvdata(psy);
2139d60595aSAlexander Kurz 
2149d60595aSAlexander Kurz 	switch (psp) {
2159d60595aSAlexander Kurz 	case POWER_SUPPLY_PROP_ONLINE:
2169d60595aSAlexander Kurz 		val->intval = chip->online;
2179d60595aSAlexander Kurz 		break;
2189d60595aSAlexander Kurz 	case POWER_SUPPLY_PROP_MODEL_NAME:
2199d60595aSAlexander Kurz 		val->strval = MAX14656_NAME;
2209d60595aSAlexander Kurz 		break;
2219d60595aSAlexander Kurz 	case POWER_SUPPLY_PROP_MANUFACTURER:
2229d60595aSAlexander Kurz 		val->strval = MAX14656_MANUFACTURER;
2239d60595aSAlexander Kurz 		break;
2249d60595aSAlexander Kurz 	default:
2259d60595aSAlexander Kurz 		return -EINVAL;
2269d60595aSAlexander Kurz 	}
2279d60595aSAlexander Kurz 
2289d60595aSAlexander Kurz 	return 0;
2299d60595aSAlexander Kurz }
2309d60595aSAlexander Kurz 
2319d60595aSAlexander Kurz static enum power_supply_property max14656_battery_props[] = {
2329d60595aSAlexander Kurz 	POWER_SUPPLY_PROP_ONLINE,
2339d60595aSAlexander Kurz 	POWER_SUPPLY_PROP_MODEL_NAME,
2349d60595aSAlexander Kurz 	POWER_SUPPLY_PROP_MANUFACTURER,
2359d60595aSAlexander Kurz };
2369d60595aSAlexander Kurz 
max14656_probe(struct i2c_client * client)237b17018deSUwe Kleine-König static int max14656_probe(struct i2c_client *client)
2389d60595aSAlexander Kurz {
23971d7ffb2SWolfram Sang 	struct i2c_adapter *adapter = client->adapter;
2409d60595aSAlexander Kurz 	struct device *dev = &client->dev;
2419d60595aSAlexander Kurz 	struct power_supply_config psy_cfg = {};
2429d60595aSAlexander Kurz 	struct max14656_chip *chip;
2439d60595aSAlexander Kurz 	int irq = client->irq;
2449d60595aSAlexander Kurz 	int ret = 0;
2459d60595aSAlexander Kurz 
2469d60595aSAlexander Kurz 	if (irq <= 0) {
2479d60595aSAlexander Kurz 		dev_err(dev, "invalid irq number: %d\n", irq);
2489d60595aSAlexander Kurz 		return -ENODEV;
2499d60595aSAlexander Kurz 	}
2509d60595aSAlexander Kurz 
2519d60595aSAlexander Kurz 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
2529d60595aSAlexander Kurz 		dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
2539d60595aSAlexander Kurz 		return -ENODEV;
2549d60595aSAlexander Kurz 	}
2559d60595aSAlexander Kurz 
2569d60595aSAlexander Kurz 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
2579d60595aSAlexander Kurz 	if (!chip)
2589d60595aSAlexander Kurz 		return -ENOMEM;
2599d60595aSAlexander Kurz 
2609d60595aSAlexander Kurz 	psy_cfg.drv_data = chip;
2619d60595aSAlexander Kurz 	chip->client = client;
2629d60595aSAlexander Kurz 	chip->online = 0;
2639d60595aSAlexander Kurz 	chip->psy_desc.name = MAX14656_NAME;
2649d60595aSAlexander Kurz 	chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN;
2659d60595aSAlexander Kurz 	chip->psy_desc.properties = max14656_battery_props;
2669d60595aSAlexander Kurz 	chip->psy_desc.num_properties = ARRAY_SIZE(max14656_battery_props);
2679d60595aSAlexander Kurz 	chip->psy_desc.get_property = max14656_get_property;
2689d60595aSAlexander Kurz 	chip->irq = irq;
2699d60595aSAlexander Kurz 
2709d60595aSAlexander Kurz 	ret = max14656_hw_init(chip);
2719d60595aSAlexander Kurz 	if (ret)
2729d60595aSAlexander Kurz 		return -ENODEV;
2739d60595aSAlexander Kurz 
2740cd0e497SSven Van Asbroeck 	chip->detect_psy = devm_power_supply_register(dev,
2750cd0e497SSven Van Asbroeck 		       &chip->psy_desc, &psy_cfg);
2760cd0e497SSven Van Asbroeck 	if (IS_ERR(chip->detect_psy)) {
2770cd0e497SSven Van Asbroeck 		dev_err(dev, "power_supply_register failed\n");
2780cd0e497SSven Van Asbroeck 		return -EINVAL;
2790cd0e497SSven Van Asbroeck 	}
2800cd0e497SSven Van Asbroeck 
281d016fc7aSChristophe JAILLET 	ret = devm_delayed_work_autocancel(dev, &chip->irq_work,
282d016fc7aSChristophe JAILLET 					   max14656_irq_worker);
283252fbeb8SSven Van Asbroeck 	if (ret) {
284d016fc7aSChristophe JAILLET 		dev_err(dev, "devm_delayed_work_autocancel %d failed\n", ret);
285252fbeb8SSven Van Asbroeck 		return ret;
286252fbeb8SSven Van Asbroeck 	}
287252fbeb8SSven Van Asbroeck 
2889d60595aSAlexander Kurz 	ret = devm_request_irq(dev, chip->irq, max14656_irq,
2899d60595aSAlexander Kurz 			       IRQF_TRIGGER_FALLING,
2909d60595aSAlexander Kurz 			       MAX14656_NAME, chip);
2919d60595aSAlexander Kurz 	if (ret) {
2929d60595aSAlexander Kurz 		dev_err(dev, "request_irq %d failed\n", chip->irq);
2939d60595aSAlexander Kurz 		return -EINVAL;
2949d60595aSAlexander Kurz 	}
2959d60595aSAlexander Kurz 	enable_irq_wake(chip->irq);
2969d60595aSAlexander Kurz 
2979d60595aSAlexander Kurz 	schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(2000));
2989d60595aSAlexander Kurz 
2999d60595aSAlexander Kurz 	return 0;
3009d60595aSAlexander Kurz }
3019d60595aSAlexander Kurz 
3029d60595aSAlexander Kurz static const struct i2c_device_id max14656_id[] = {
303*ebacfa1fSUwe Kleine-König 	{ "max14656" },
3049d60595aSAlexander Kurz 	{}
3059d60595aSAlexander Kurz };
306166e8dbdSJavier Martinez Canillas MODULE_DEVICE_TABLE(i2c, max14656_id);
3079d60595aSAlexander Kurz 
3089d60595aSAlexander Kurz static const struct of_device_id max14656_match_table[] = {
3099d60595aSAlexander Kurz 	{ .compatible = "maxim,max14656", },
3109d60595aSAlexander Kurz 	{}
3119d60595aSAlexander Kurz };
312166e8dbdSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, max14656_match_table);
3139d60595aSAlexander Kurz 
3149d60595aSAlexander Kurz static struct i2c_driver max14656_i2c_driver = {
3159d60595aSAlexander Kurz 	.driver = {
3169d60595aSAlexander Kurz 		.name	= "max14656",
3179d60595aSAlexander Kurz 		.of_match_table = max14656_match_table,
3189d60595aSAlexander Kurz 	},
319fe20b1dcSUwe Kleine-König 	.probe		= max14656_probe,
3209d60595aSAlexander Kurz 	.id_table	= max14656_id,
3219d60595aSAlexander Kurz };
3229d60595aSAlexander Kurz module_i2c_driver(max14656_i2c_driver);
3239d60595aSAlexander Kurz 
3249d60595aSAlexander Kurz MODULE_DESCRIPTION("MAX14656 USB charger detector");
3259d60595aSAlexander Kurz MODULE_LICENSE("GPL v2");
326