18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for UCS1002 Programmable USB Port Power Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Zodiac Inflight Innovations
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/bits.h>
88c2ecf20Sopenharmony_ci#include <linux/freezer.h>
98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/kthread.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/of.h>
178c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
188c2ecf20Sopenharmony_ci#include <linux/power_supply.h>
198c2ecf20Sopenharmony_ci#include <linux/regmap.h>
208c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
218c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* UCS1002 Registers */
248c2ecf20Sopenharmony_ci#define UCS1002_REG_CURRENT_MEASUREMENT	0x00
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * The Total Accumulated Charge registers store the total accumulated
288c2ecf20Sopenharmony_ci * charge delivered from the VS source to a portable device. The total
298c2ecf20Sopenharmony_ci * value is calculated using four registers, from 01h to 04h. The bit
308c2ecf20Sopenharmony_ci * weighting of the registers is given in mA/hrs.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#define UCS1002_REG_TOTAL_ACC_CHARGE	0x01
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Other Status Register */
358c2ecf20Sopenharmony_ci#define UCS1002_REG_OTHER_STATUS	0x0f
368c2ecf20Sopenharmony_ci#  define F_ADET_PIN			BIT(4)
378c2ecf20Sopenharmony_ci#  define F_CHG_ACT			BIT(3)
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Interrupt Status */
408c2ecf20Sopenharmony_ci#define UCS1002_REG_INTERRUPT_STATUS	0x10
418c2ecf20Sopenharmony_ci#  define F_ERR				BIT(7)
428c2ecf20Sopenharmony_ci#  define F_DISCHARGE_ERR		BIT(6)
438c2ecf20Sopenharmony_ci#  define F_RESET			BIT(5)
448c2ecf20Sopenharmony_ci#  define F_MIN_KEEP_OUT		BIT(4)
458c2ecf20Sopenharmony_ci#  define F_TSD				BIT(3)
468c2ecf20Sopenharmony_ci#  define F_OVER_VOLT			BIT(2)
478c2ecf20Sopenharmony_ci#  define F_BACK_VOLT			BIT(1)
488c2ecf20Sopenharmony_ci#  define F_OVER_ILIM			BIT(0)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Pin Status Register */
518c2ecf20Sopenharmony_ci#define UCS1002_REG_PIN_STATUS		0x14
528c2ecf20Sopenharmony_ci#  define UCS1002_PWR_STATE_MASK	0x03
538c2ecf20Sopenharmony_ci#  define F_PWR_EN_PIN			BIT(6)
548c2ecf20Sopenharmony_ci#  define F_M2_PIN			BIT(5)
558c2ecf20Sopenharmony_ci#  define F_M1_PIN			BIT(4)
568c2ecf20Sopenharmony_ci#  define F_EM_EN_PIN			BIT(3)
578c2ecf20Sopenharmony_ci#  define F_SEL_PIN			BIT(2)
588c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_MASK		GENMASK(5, 3)
598c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_PASSTHROUGH	F_M2_PIN
608c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_DEDICATED	F_EM_EN_PIN
618c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_BC12_DCP	(F_M2_PIN | F_EM_EN_PIN)
628c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_BC12_SDP	F_M1_PIN
638c2ecf20Sopenharmony_ci#  define F_ACTIVE_MODE_BC12_CDP	(F_M1_PIN | F_M2_PIN | F_EM_EN_PIN)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* General Configuration Register */
668c2ecf20Sopenharmony_ci#define UCS1002_REG_GENERAL_CFG		0x15
678c2ecf20Sopenharmony_ci#  define F_RATION_EN			BIT(3)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* Emulation Configuration Register */
708c2ecf20Sopenharmony_ci#define UCS1002_REG_EMU_CFG		0x16
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* Switch Configuration Register */
738c2ecf20Sopenharmony_ci#define UCS1002_REG_SWITCH_CFG		0x17
748c2ecf20Sopenharmony_ci#  define F_PIN_IGNORE			BIT(7)
758c2ecf20Sopenharmony_ci#  define F_EM_EN_SET			BIT(5)
768c2ecf20Sopenharmony_ci#  define F_M2_SET			BIT(4)
778c2ecf20Sopenharmony_ci#  define F_M1_SET			BIT(3)
788c2ecf20Sopenharmony_ci#  define F_S0_SET			BIT(2)
798c2ecf20Sopenharmony_ci#  define F_PWR_EN_SET			BIT(1)
808c2ecf20Sopenharmony_ci#  define F_LATCH_SET			BIT(0)
818c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_MASK	GENMASK(5, 3)
828c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_PASSTHROUGH	F_M2_SET
838c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_DEDICATED	F_EM_EN_SET
848c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_BC12_DCP	(F_M2_SET | F_EM_EN_SET)
858c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_BC12_SDP	F_M1_SET
868c2ecf20Sopenharmony_ci#  define V_SET_ACTIVE_MODE_BC12_CDP	(F_M1_SET | F_M2_SET | F_EM_EN_SET)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Current Limit Register */
898c2ecf20Sopenharmony_ci#define UCS1002_REG_ILIMIT		0x19
908c2ecf20Sopenharmony_ci#  define UCS1002_ILIM_SW_MASK		GENMASK(3, 0)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* Product ID */
938c2ecf20Sopenharmony_ci#define UCS1002_REG_PRODUCT_ID		0xfd
948c2ecf20Sopenharmony_ci#  define UCS1002_PRODUCT_ID		0x4e
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* Manufacture name */
978c2ecf20Sopenharmony_ci#define UCS1002_MANUFACTURER		"SMSC"
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistruct ucs1002_info {
1008c2ecf20Sopenharmony_ci	struct power_supply *charger;
1018c2ecf20Sopenharmony_ci	struct i2c_client *client;
1028c2ecf20Sopenharmony_ci	struct regmap *regmap;
1038c2ecf20Sopenharmony_ci	struct regulator_desc *regulator_descriptor;
1048c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
1058c2ecf20Sopenharmony_ci	bool present;
1068c2ecf20Sopenharmony_ci	bool output_disable;
1078c2ecf20Sopenharmony_ci	struct delayed_work health_poll;
1088c2ecf20Sopenharmony_ci	int health;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic enum power_supply_property ucs1002_props[] = {
1138c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
1148c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_NOW,
1158c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
1168c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_MAX,
1178c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT, /* the presence of PED */
1188c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_MANUFACTURER,
1198c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_USB_TYPE,
1208c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int ucs1002_get_online(struct ucs1002_info *info,
1248c2ecf20Sopenharmony_ci			      union power_supply_propval *val)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	unsigned int reg;
1278c2ecf20Sopenharmony_ci	int ret;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, &reg);
1308c2ecf20Sopenharmony_ci	if (ret)
1318c2ecf20Sopenharmony_ci		return ret;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	val->intval = !!(reg & F_CHG_ACT);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int ucs1002_get_charge(struct ucs1002_info *info,
1398c2ecf20Sopenharmony_ci			      union power_supply_propval *val)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	/*
1428c2ecf20Sopenharmony_ci	 * To fit within 32 bits some values are rounded (uA/h)
1438c2ecf20Sopenharmony_ci	 *
1448c2ecf20Sopenharmony_ci	 * For Total Accumulated Charge Middle Low Byte register, addr
1458c2ecf20Sopenharmony_ci	 * 03h, byte 2
1468c2ecf20Sopenharmony_ci	 *
1478c2ecf20Sopenharmony_ci	 *   B0: 0.01084 mA/h rounded to 11 uA/h
1488c2ecf20Sopenharmony_ci	 *   B1: 0.02169 mA/h rounded to 22 uA/h
1498c2ecf20Sopenharmony_ci	 *   B2: 0.04340 mA/h rounded to 43 uA/h
1508c2ecf20Sopenharmony_ci	 *   B3: 0.08676 mA/h rounded to 87 uA/h
1518c2ecf20Sopenharmony_ci	 *   B4: 0.17350 mA/h rounded to 173 uÁ/h
1528c2ecf20Sopenharmony_ci	 *
1538c2ecf20Sopenharmony_ci	 * For Total Accumulated Charge Low Byte register, addr 04h,
1548c2ecf20Sopenharmony_ci	 * byte 3
1558c2ecf20Sopenharmony_ci	 *
1568c2ecf20Sopenharmony_ci	 *   B6: 0.00271 mA/h rounded to 3 uA/h
1578c2ecf20Sopenharmony_ci	 *   B7: 0.005422 mA/h rounded to 5 uA/h
1588c2ecf20Sopenharmony_ci	 */
1598c2ecf20Sopenharmony_ci	static const int bit_weights_uAh[BITS_PER_TYPE(u32)] = {
1608c2ecf20Sopenharmony_ci		/*
1618c2ecf20Sopenharmony_ci		 * Bit corresponding to low byte (offset 0x04)
1628c2ecf20Sopenharmony_ci		 * B0 B1 B2 B3 B4 B5 B6 B7
1638c2ecf20Sopenharmony_ci		 */
1648c2ecf20Sopenharmony_ci		0, 0, 0, 0, 0, 0, 3, 5,
1658c2ecf20Sopenharmony_ci		/*
1668c2ecf20Sopenharmony_ci		 * Bit corresponding to middle low byte (offset 0x03)
1678c2ecf20Sopenharmony_ci		 * B0 B1 B2 B3 B4 B5 B6 B7
1688c2ecf20Sopenharmony_ci		 */
1698c2ecf20Sopenharmony_ci		11, 22, 43, 87, 173, 347, 694, 1388,
1708c2ecf20Sopenharmony_ci		/*
1718c2ecf20Sopenharmony_ci		 * Bit corresponding to middle high byte (offset 0x02)
1728c2ecf20Sopenharmony_ci		 * B0 B1 B2 B3 B4 B5 B6 B7
1738c2ecf20Sopenharmony_ci		 */
1748c2ecf20Sopenharmony_ci		2776, 5552, 11105, 22210, 44420, 88840, 177700, 355400,
1758c2ecf20Sopenharmony_ci		/*
1768c2ecf20Sopenharmony_ci		 * Bit corresponding to high byte (offset 0x01)
1778c2ecf20Sopenharmony_ci		 * B0 B1 B2 B3 B4 B5 B6 B7
1788c2ecf20Sopenharmony_ci		 */
1798c2ecf20Sopenharmony_ci		710700, 1421000, 2843000, 5685000, 11371000, 22742000,
1808c2ecf20Sopenharmony_ci		45484000, 90968000,
1818c2ecf20Sopenharmony_ci	};
1828c2ecf20Sopenharmony_ci	unsigned long total_acc_charger;
1838c2ecf20Sopenharmony_ci	unsigned int reg;
1848c2ecf20Sopenharmony_ci	int i, ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	ret = regmap_bulk_read(info->regmap, UCS1002_REG_TOTAL_ACC_CHARGE,
1878c2ecf20Sopenharmony_ci			       &reg, sizeof(u32));
1888c2ecf20Sopenharmony_ci	if (ret)
1898c2ecf20Sopenharmony_ci		return ret;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	total_acc_charger = be32_to_cpu(reg); /* BE as per offsets above */
1928c2ecf20Sopenharmony_ci	val->intval = 0;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	for_each_set_bit(i, &total_acc_charger, ARRAY_SIZE(bit_weights_uAh))
1958c2ecf20Sopenharmony_ci		val->intval += bit_weights_uAh[i];
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int ucs1002_get_current(struct ucs1002_info *info,
2018c2ecf20Sopenharmony_ci			       union power_supply_propval *val)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	/*
2048c2ecf20Sopenharmony_ci	 * The Current Measurement register stores the measured
2058c2ecf20Sopenharmony_ci	 * current value delivered to the portable device. The range
2068c2ecf20Sopenharmony_ci	 * is from 9.76 mA to 2.5 A.
2078c2ecf20Sopenharmony_ci	 */
2088c2ecf20Sopenharmony_ci	static const int bit_weights_uA[BITS_PER_TYPE(u8)] = {
2098c2ecf20Sopenharmony_ci		9760, 19500, 39000, 78100, 156200, 312300, 624600, 1249300,
2108c2ecf20Sopenharmony_ci	};
2118c2ecf20Sopenharmony_ci	unsigned long current_measurement;
2128c2ecf20Sopenharmony_ci	unsigned int reg;
2138c2ecf20Sopenharmony_ci	int i, ret;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_CURRENT_MEASUREMENT, &reg);
2168c2ecf20Sopenharmony_ci	if (ret)
2178c2ecf20Sopenharmony_ci		return ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	current_measurement = reg;
2208c2ecf20Sopenharmony_ci	val->intval = 0;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	for_each_set_bit(i, &current_measurement, ARRAY_SIZE(bit_weights_uA))
2238c2ecf20Sopenharmony_ci		val->intval += bit_weights_uA[i];
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci/*
2298c2ecf20Sopenharmony_ci * The Current Limit register stores the maximum current used by the
2308c2ecf20Sopenharmony_ci * port switch. The range is from 500mA to 2.5 A.
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_cistatic const u32 ucs1002_current_limit_uA[] = {
2338c2ecf20Sopenharmony_ci	500000, 900000, 1000000, 1200000, 1500000, 1800000, 2000000, 2500000,
2348c2ecf20Sopenharmony_ci};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int ucs1002_get_max_current(struct ucs1002_info *info,
2378c2ecf20Sopenharmony_ci				   union power_supply_propval *val)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	unsigned int reg;
2408c2ecf20Sopenharmony_ci	int ret;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (info->output_disable) {
2438c2ecf20Sopenharmony_ci		val->intval = 0;
2448c2ecf20Sopenharmony_ci		return 0;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, &reg);
2488c2ecf20Sopenharmony_ci	if (ret)
2498c2ecf20Sopenharmony_ci		return ret;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	val->intval = ucs1002_current_limit_uA[reg & UCS1002_ILIM_SW_MASK];
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return 0;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic int ucs1002_set_max_current(struct ucs1002_info *info, u32 val)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	unsigned int reg;
2598c2ecf20Sopenharmony_ci	int ret, idx;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (val == 0) {
2628c2ecf20Sopenharmony_ci		info->output_disable = true;
2638c2ecf20Sopenharmony_ci		regulator_disable_regmap(info->rdev);
2648c2ecf20Sopenharmony_ci		return 0;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	for (idx = 0; idx < ARRAY_SIZE(ucs1002_current_limit_uA); idx++) {
2688c2ecf20Sopenharmony_ci		if (val == ucs1002_current_limit_uA[idx])
2698c2ecf20Sopenharmony_ci			break;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (idx == ARRAY_SIZE(ucs1002_current_limit_uA))
2738c2ecf20Sopenharmony_ci		return -EINVAL;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ret = regmap_write(info->regmap, UCS1002_REG_ILIMIT, idx);
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci	/*
2798c2ecf20Sopenharmony_ci	 * Any current limit setting exceeding the one set via ILIM
2808c2ecf20Sopenharmony_ci	 * pin will be rejected, so we read out freshly changed limit
2818c2ecf20Sopenharmony_ci	 * to make sure that it took effect.
2828c2ecf20Sopenharmony_ci	 */
2838c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_ILIMIT, &reg);
2848c2ecf20Sopenharmony_ci	if (ret)
2858c2ecf20Sopenharmony_ci		return ret;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (reg != idx)
2888c2ecf20Sopenharmony_ci		return -EINVAL;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	info->output_disable = false;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (info->rdev && info->rdev->use_count &&
2938c2ecf20Sopenharmony_ci	    !regulator_is_enabled_regmap(info->rdev))
2948c2ecf20Sopenharmony_ci		regulator_enable_regmap(info->rdev);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return 0;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic enum power_supply_usb_type ucs1002_usb_types[] = {
3008c2ecf20Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_PD,
3018c2ecf20Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_SDP,
3028c2ecf20Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_DCP,
3038c2ecf20Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_CDP,
3048c2ecf20Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_UNKNOWN,
3058c2ecf20Sopenharmony_ci};
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int ucs1002_set_usb_type(struct ucs1002_info *info, int val)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	unsigned int mode;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (val < 0 || val >= ARRAY_SIZE(ucs1002_usb_types))
3128c2ecf20Sopenharmony_ci		return -EINVAL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	switch (ucs1002_usb_types[val]) {
3158c2ecf20Sopenharmony_ci	case POWER_SUPPLY_USB_TYPE_PD:
3168c2ecf20Sopenharmony_ci		mode = V_SET_ACTIVE_MODE_DEDICATED;
3178c2ecf20Sopenharmony_ci		break;
3188c2ecf20Sopenharmony_ci	case POWER_SUPPLY_USB_TYPE_SDP:
3198c2ecf20Sopenharmony_ci		mode = V_SET_ACTIVE_MODE_BC12_SDP;
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	case POWER_SUPPLY_USB_TYPE_DCP:
3228c2ecf20Sopenharmony_ci		mode = V_SET_ACTIVE_MODE_BC12_DCP;
3238c2ecf20Sopenharmony_ci		break;
3248c2ecf20Sopenharmony_ci	case POWER_SUPPLY_USB_TYPE_CDP:
3258c2ecf20Sopenharmony_ci		mode = V_SET_ACTIVE_MODE_BC12_CDP;
3268c2ecf20Sopenharmony_ci		break;
3278c2ecf20Sopenharmony_ci	default:
3288c2ecf20Sopenharmony_ci		return -EINVAL;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
3328c2ecf20Sopenharmony_ci				  V_SET_ACTIVE_MODE_MASK, mode);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int ucs1002_get_usb_type(struct ucs1002_info *info,
3368c2ecf20Sopenharmony_ci				union power_supply_propval *val)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	enum power_supply_usb_type type;
3398c2ecf20Sopenharmony_ci	unsigned int reg;
3408c2ecf20Sopenharmony_ci	int ret;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, &reg);
3438c2ecf20Sopenharmony_ci	if (ret)
3448c2ecf20Sopenharmony_ci		return ret;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	switch (reg & F_ACTIVE_MODE_MASK) {
3478c2ecf20Sopenharmony_ci	default:
3488c2ecf20Sopenharmony_ci		type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
3498c2ecf20Sopenharmony_ci		break;
3508c2ecf20Sopenharmony_ci	case F_ACTIVE_MODE_DEDICATED:
3518c2ecf20Sopenharmony_ci		type = POWER_SUPPLY_USB_TYPE_PD;
3528c2ecf20Sopenharmony_ci		break;
3538c2ecf20Sopenharmony_ci	case F_ACTIVE_MODE_BC12_SDP:
3548c2ecf20Sopenharmony_ci		type = POWER_SUPPLY_USB_TYPE_SDP;
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci	case F_ACTIVE_MODE_BC12_DCP:
3578c2ecf20Sopenharmony_ci		type = POWER_SUPPLY_USB_TYPE_DCP;
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case F_ACTIVE_MODE_BC12_CDP:
3608c2ecf20Sopenharmony_ci		type = POWER_SUPPLY_USB_TYPE_CDP;
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	val->intval = type;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int ucs1002_get_property(struct power_supply *psy,
3708c2ecf20Sopenharmony_ci				enum power_supply_property psp,
3718c2ecf20Sopenharmony_ci				union power_supply_propval *val)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct ucs1002_info *info = power_supply_get_drvdata(psy);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	switch (psp) {
3768c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
3778c2ecf20Sopenharmony_ci		return ucs1002_get_online(info, val);
3788c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
3798c2ecf20Sopenharmony_ci		return ucs1002_get_charge(info, val);
3808c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
3818c2ecf20Sopenharmony_ci		return ucs1002_get_current(info, val);
3828c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
3838c2ecf20Sopenharmony_ci		return ucs1002_get_max_current(info, val);
3848c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_USB_TYPE:
3858c2ecf20Sopenharmony_ci		return ucs1002_get_usb_type(info, val);
3868c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
3878c2ecf20Sopenharmony_ci		val->intval = info->health;
3888c2ecf20Sopenharmony_ci		return 0;
3898c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
3908c2ecf20Sopenharmony_ci		val->intval = info->present;
3918c2ecf20Sopenharmony_ci		return 0;
3928c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_MANUFACTURER:
3938c2ecf20Sopenharmony_ci		val->strval = UCS1002_MANUFACTURER;
3948c2ecf20Sopenharmony_ci		return 0;
3958c2ecf20Sopenharmony_ci	default:
3968c2ecf20Sopenharmony_ci		return -EINVAL;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int ucs1002_set_property(struct power_supply *psy,
4018c2ecf20Sopenharmony_ci				enum power_supply_property psp,
4028c2ecf20Sopenharmony_ci				const union power_supply_propval *val)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct ucs1002_info *info = power_supply_get_drvdata(psy);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	switch (psp) {
4078c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
4088c2ecf20Sopenharmony_ci		return ucs1002_set_max_current(info, val->intval);
4098c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_USB_TYPE:
4108c2ecf20Sopenharmony_ci		return ucs1002_set_usb_type(info, val->intval);
4118c2ecf20Sopenharmony_ci	default:
4128c2ecf20Sopenharmony_ci		return -EINVAL;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int ucs1002_property_is_writeable(struct power_supply *psy,
4178c2ecf20Sopenharmony_ci					 enum power_supply_property psp)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	switch (psp) {
4208c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
4218c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_USB_TYPE:
4228c2ecf20Sopenharmony_ci		return true;
4238c2ecf20Sopenharmony_ci	default:
4248c2ecf20Sopenharmony_ci		return false;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic const struct power_supply_desc ucs1002_charger_desc = {
4298c2ecf20Sopenharmony_ci	.name			= "ucs1002",
4308c2ecf20Sopenharmony_ci	.type			= POWER_SUPPLY_TYPE_USB,
4318c2ecf20Sopenharmony_ci	.usb_types		= ucs1002_usb_types,
4328c2ecf20Sopenharmony_ci	.num_usb_types		= ARRAY_SIZE(ucs1002_usb_types),
4338c2ecf20Sopenharmony_ci	.get_property		= ucs1002_get_property,
4348c2ecf20Sopenharmony_ci	.set_property		= ucs1002_set_property,
4358c2ecf20Sopenharmony_ci	.property_is_writeable	= ucs1002_property_is_writeable,
4368c2ecf20Sopenharmony_ci	.properties		= ucs1002_props,
4378c2ecf20Sopenharmony_ci	.num_properties		= ARRAY_SIZE(ucs1002_props),
4388c2ecf20Sopenharmony_ci};
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic void ucs1002_health_poll(struct work_struct *work)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct ucs1002_info *info = container_of(work, struct ucs1002_info,
4438c2ecf20Sopenharmony_ci						 health_poll.work);
4448c2ecf20Sopenharmony_ci	int ret;
4458c2ecf20Sopenharmony_ci	u32 reg;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_INTERRUPT_STATUS, &reg);
4488c2ecf20Sopenharmony_ci	if (ret)
4498c2ecf20Sopenharmony_ci		return;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* bad health and no status change, just schedule us again in a while */
4528c2ecf20Sopenharmony_ci	if ((reg & F_ERR) && info->health != POWER_SUPPLY_HEALTH_GOOD) {
4538c2ecf20Sopenharmony_ci		schedule_delayed_work(&info->health_poll,
4548c2ecf20Sopenharmony_ci				      msecs_to_jiffies(2000));
4558c2ecf20Sopenharmony_ci		return;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (reg & F_TSD)
4598c2ecf20Sopenharmony_ci		info->health = POWER_SUPPLY_HEALTH_OVERHEAT;
4608c2ecf20Sopenharmony_ci	else if (reg & (F_OVER_VOLT | F_BACK_VOLT))
4618c2ecf20Sopenharmony_ci		info->health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
4628c2ecf20Sopenharmony_ci	else if (reg & F_OVER_ILIM)
4638c2ecf20Sopenharmony_ci		info->health = POWER_SUPPLY_HEALTH_OVERCURRENT;
4648c2ecf20Sopenharmony_ci	else if (reg & (F_DISCHARGE_ERR | F_MIN_KEEP_OUT))
4658c2ecf20Sopenharmony_ci		info->health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
4668c2ecf20Sopenharmony_ci	else
4678c2ecf20Sopenharmony_ci		info->health = POWER_SUPPLY_HEALTH_GOOD;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	sysfs_notify(&info->charger->dev.kobj, NULL, "health");
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic irqreturn_t ucs1002_charger_irq(int irq, void *data)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	int ret, regval;
4758c2ecf20Sopenharmony_ci	bool present;
4768c2ecf20Sopenharmony_ci	struct ucs1002_info *info = data;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	present = info->present;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_OTHER_STATUS, &regval);
4818c2ecf20Sopenharmony_ci	if (ret)
4828c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* update attached status */
4858c2ecf20Sopenharmony_ci	info->present = regval & F_ADET_PIN;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* notify the change */
4888c2ecf20Sopenharmony_ci	if (present != info->present)
4898c2ecf20Sopenharmony_ci		power_supply_changed(info->charger);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic irqreturn_t ucs1002_alert_irq(int irq, void *data)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct ucs1002_info *info = data;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	mod_delayed_work(system_wq, &info->health_poll, 0);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int ucs1002_regulator_enable(struct regulator_dev *rdev)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct ucs1002_info *info = rdev_get_drvdata(rdev);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/*
5088c2ecf20Sopenharmony_ci	 * If the output is disabled due to 0 maximum current, just pretend the
5098c2ecf20Sopenharmony_ci	 * enable did work. The regulator will be enabled as soon as we get a
5108c2ecf20Sopenharmony_ci	 * a non-zero maximum current budget.
5118c2ecf20Sopenharmony_ci	 */
5128c2ecf20Sopenharmony_ci	if (info->output_disable)
5138c2ecf20Sopenharmony_ci		return 0;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return regulator_enable_regmap(rdev);
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic const struct regulator_ops ucs1002_regulator_ops = {
5198c2ecf20Sopenharmony_ci	.is_enabled	= regulator_is_enabled_regmap,
5208c2ecf20Sopenharmony_ci	.enable		= ucs1002_regulator_enable,
5218c2ecf20Sopenharmony_ci	.disable	= regulator_disable_regmap,
5228c2ecf20Sopenharmony_ci};
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic const struct regulator_desc ucs1002_regulator_descriptor = {
5258c2ecf20Sopenharmony_ci	.name		= "ucs1002-vbus",
5268c2ecf20Sopenharmony_ci	.ops		= &ucs1002_regulator_ops,
5278c2ecf20Sopenharmony_ci	.type		= REGULATOR_VOLTAGE,
5288c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
5298c2ecf20Sopenharmony_ci	.enable_reg	= UCS1002_REG_SWITCH_CFG,
5308c2ecf20Sopenharmony_ci	.enable_mask	= F_PWR_EN_SET,
5318c2ecf20Sopenharmony_ci	.enable_val	= F_PWR_EN_SET,
5328c2ecf20Sopenharmony_ci	.fixed_uV	= 5000000,
5338c2ecf20Sopenharmony_ci	.n_voltages	= 1,
5348c2ecf20Sopenharmony_ci};
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic int ucs1002_probe(struct i2c_client *client,
5378c2ecf20Sopenharmony_ci			 const struct i2c_device_id *dev_id)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
5408c2ecf20Sopenharmony_ci	struct power_supply_config charger_config = {};
5418c2ecf20Sopenharmony_ci	const struct regmap_config regmap_config = {
5428c2ecf20Sopenharmony_ci		.reg_bits = 8,
5438c2ecf20Sopenharmony_ci		.val_bits = 8,
5448c2ecf20Sopenharmony_ci	};
5458c2ecf20Sopenharmony_ci	struct regulator_config regulator_config = {};
5468c2ecf20Sopenharmony_ci	int irq_a_det, irq_alert, ret;
5478c2ecf20Sopenharmony_ci	struct ucs1002_info *info;
5488c2ecf20Sopenharmony_ci	unsigned int regval;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
5518c2ecf20Sopenharmony_ci	if (!info)
5528c2ecf20Sopenharmony_ci		return -ENOMEM;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	info->regmap = devm_regmap_init_i2c(client, &regmap_config);
5558c2ecf20Sopenharmony_ci	ret = PTR_ERR_OR_ZERO(info->regmap);
5568c2ecf20Sopenharmony_ci	if (ret) {
5578c2ecf20Sopenharmony_ci		dev_err(dev, "Regmap initialization failed: %d\n", ret);
5588c2ecf20Sopenharmony_ci		return ret;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	info->client = client;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	irq_a_det = of_irq_get_byname(dev->of_node, "a_det");
5648c2ecf20Sopenharmony_ci	irq_alert = of_irq_get_byname(dev->of_node, "alert");
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	charger_config.of_node = dev->of_node;
5678c2ecf20Sopenharmony_ci	charger_config.drv_data = info;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_PRODUCT_ID, &regval);
5708c2ecf20Sopenharmony_ci	if (ret) {
5718c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to read product ID: %d\n", ret);
5728c2ecf20Sopenharmony_ci		return ret;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (regval != UCS1002_PRODUCT_ID) {
5768c2ecf20Sopenharmony_ci		dev_err(dev,
5778c2ecf20Sopenharmony_ci			"Product ID does not match (0x%02x != 0x%02x)\n",
5788c2ecf20Sopenharmony_ci			regval, UCS1002_PRODUCT_ID);
5798c2ecf20Sopenharmony_ci		return -ENODEV;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Enable charge rationing by default */
5838c2ecf20Sopenharmony_ci	ret = regmap_update_bits(info->regmap, UCS1002_REG_GENERAL_CFG,
5848c2ecf20Sopenharmony_ci				 F_RATION_EN, F_RATION_EN);
5858c2ecf20Sopenharmony_ci	if (ret) {
5868c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to read general config: %d\n", ret);
5878c2ecf20Sopenharmony_ci		return ret;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/*
5918c2ecf20Sopenharmony_ci	 * Ignore the M1, M2, PWR_EN, and EM_EN pin states. Set active
5928c2ecf20Sopenharmony_ci	 * mode selection to BC1.2 CDP.
5938c2ecf20Sopenharmony_ci	 */
5948c2ecf20Sopenharmony_ci	ret = regmap_update_bits(info->regmap, UCS1002_REG_SWITCH_CFG,
5958c2ecf20Sopenharmony_ci				 V_SET_ACTIVE_MODE_MASK | F_PIN_IGNORE,
5968c2ecf20Sopenharmony_ci				 V_SET_ACTIVE_MODE_BC12_CDP | F_PIN_IGNORE);
5978c2ecf20Sopenharmony_ci	if (ret) {
5988c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to configure default mode: %d\n", ret);
5998c2ecf20Sopenharmony_ci		return ret;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci	/*
6028c2ecf20Sopenharmony_ci	 * Be safe and set initial current limit to 500mA
6038c2ecf20Sopenharmony_ci	 */
6048c2ecf20Sopenharmony_ci	ret = ucs1002_set_max_current(info, 500000);
6058c2ecf20Sopenharmony_ci	if (ret) {
6068c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to set max current default: %d\n", ret);
6078c2ecf20Sopenharmony_ci		return ret;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	info->charger = devm_power_supply_register(dev, &ucs1002_charger_desc,
6118c2ecf20Sopenharmony_ci						   &charger_config);
6128c2ecf20Sopenharmony_ci	ret = PTR_ERR_OR_ZERO(info->charger);
6138c2ecf20Sopenharmony_ci	if (ret) {
6148c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register power supply: %d\n", ret);
6158c2ecf20Sopenharmony_ci		return ret;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	ret = regmap_read(info->regmap, UCS1002_REG_PIN_STATUS, &regval);
6198c2ecf20Sopenharmony_ci	if (ret) {
6208c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to read pin status: %d\n", ret);
6218c2ecf20Sopenharmony_ci		return ret;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	info->regulator_descriptor =
6258c2ecf20Sopenharmony_ci		devm_kmemdup(dev, &ucs1002_regulator_descriptor,
6268c2ecf20Sopenharmony_ci			     sizeof(ucs1002_regulator_descriptor),
6278c2ecf20Sopenharmony_ci			     GFP_KERNEL);
6288c2ecf20Sopenharmony_ci	if (!info->regulator_descriptor)
6298c2ecf20Sopenharmony_ci		return -ENOMEM;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	info->regulator_descriptor->enable_is_inverted = !(regval & F_SEL_PIN);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	regulator_config.dev = dev;
6348c2ecf20Sopenharmony_ci	regulator_config.of_node = dev->of_node;
6358c2ecf20Sopenharmony_ci	regulator_config.regmap = info->regmap;
6368c2ecf20Sopenharmony_ci	regulator_config.driver_data = info;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	info->rdev = devm_regulator_register(dev, info->regulator_descriptor,
6398c2ecf20Sopenharmony_ci				       &regulator_config);
6408c2ecf20Sopenharmony_ci	ret = PTR_ERR_OR_ZERO(info->rdev);
6418c2ecf20Sopenharmony_ci	if (ret) {
6428c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to register VBUS regulator: %d\n", ret);
6438c2ecf20Sopenharmony_ci		return ret;
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	info->health = POWER_SUPPLY_HEALTH_GOOD;
6478c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&info->health_poll, ucs1002_health_poll);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (irq_a_det > 0) {
6508c2ecf20Sopenharmony_ci		ret = devm_request_threaded_irq(dev, irq_a_det, NULL,
6518c2ecf20Sopenharmony_ci						ucs1002_charger_irq,
6528c2ecf20Sopenharmony_ci						IRQF_ONESHOT,
6538c2ecf20Sopenharmony_ci						"ucs1002-a_det", info);
6548c2ecf20Sopenharmony_ci		if (ret) {
6558c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to request A_DET threaded irq: %d\n",
6568c2ecf20Sopenharmony_ci				ret);
6578c2ecf20Sopenharmony_ci			return ret;
6588c2ecf20Sopenharmony_ci		}
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (irq_alert > 0) {
6628c2ecf20Sopenharmony_ci		ret = devm_request_irq(dev, irq_alert, ucs1002_alert_irq,
6638c2ecf20Sopenharmony_ci				       0,"ucs1002-alert", info);
6648c2ecf20Sopenharmony_ci		if (ret) {
6658c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to request ALERT threaded irq: %d\n",
6668c2ecf20Sopenharmony_ci				ret);
6678c2ecf20Sopenharmony_ci			return ret;
6688c2ecf20Sopenharmony_ci		}
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	return 0;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic const struct of_device_id ucs1002_of_match[] = {
6758c2ecf20Sopenharmony_ci	{ .compatible = "microchip,ucs1002", },
6768c2ecf20Sopenharmony_ci	{ /* sentinel */ },
6778c2ecf20Sopenharmony_ci};
6788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ucs1002_of_match);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic struct i2c_driver ucs1002_driver = {
6818c2ecf20Sopenharmony_ci	.driver = {
6828c2ecf20Sopenharmony_ci		   .name = "ucs1002",
6838c2ecf20Sopenharmony_ci		   .of_match_table = ucs1002_of_match,
6848c2ecf20Sopenharmony_ci	},
6858c2ecf20Sopenharmony_ci	.probe = ucs1002_probe,
6868c2ecf20Sopenharmony_ci};
6878c2ecf20Sopenharmony_cimodule_i2c_driver(ucs1002_driver);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microchip UCS1002 Programmable USB Port Power Controller");
6908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");
6918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
6928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
693