^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2015 Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/extcon-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/mfd/axp20x.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/usb/role.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/cpu_device_id.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/intel-family.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Power source status register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define PS_STAT_VBUS_TRIGGER BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define PS_STAT_BAT_CHRG_DIR BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PS_STAT_VBUS_ABOVE_VHOLD BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PS_STAT_VBUS_VALID BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define PS_STAT_VBUS_PRESENT BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* BC module global register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define BC_GLOBAL_RUN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define BC_GLOBAL_DET_STAT BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define BC_GLOBAL_DBP_TOUT BIT(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define BC_GLOBAL_VLGC_COM_SEL BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define BC_GLOBAL_DCD_TOUT_MASK (BIT(6)|BIT(5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define BC_GLOBAL_DCD_TOUT_300MS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define BC_GLOBAL_DCD_TOUT_100MS 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define BC_GLOBAL_DCD_TOUT_500MS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define BC_GLOBAL_DCD_TOUT_900MS 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define BC_GLOBAL_DCD_DET_SEL BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* BC module vbus control and status register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define VBUS_CNTL_DPDM_PD_EN BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define VBUS_CNTL_DPDM_FD_EN BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define VBUS_CNTL_FIRST_PO_STAT BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* BC USB status register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define USB_STAT_BUS_STAT_MASK (BIT(3)|BIT(2)|BIT(1)|BIT(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define USB_STAT_BUS_STAT_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define USB_STAT_BUS_STAT_ATHD 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define USB_STAT_BUS_STAT_CONN 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define USB_STAT_BUS_STAT_SUSP 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define USB_STAT_BUS_STAT_CONF 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define USB_STAT_USB_SS_MODE BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define USB_STAT_DEAD_BAT_DET BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define USB_STAT_DBP_UNCFG BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* BC detect status register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define DET_STAT_MASK (BIT(7)|BIT(6)|BIT(5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define DET_STAT_SHIFT 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define DET_STAT_SDP 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define DET_STAT_CDP 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define DET_STAT_DCP 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) enum axp288_extcon_reg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) AXP288_PS_STAT_REG = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) AXP288_PS_BOOT_REASON_REG = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) AXP288_BC_GLOBAL_REG = 0x2c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) AXP288_BC_VBUS_CNTL_REG = 0x2d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) AXP288_BC_USB_STAT_REG = 0x2e,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) AXP288_BC_DET_STAT_REG = 0x2f,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) enum axp288_extcon_irq {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) VBUS_FALLING_IRQ = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) VBUS_RISING_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) MV_CHNG_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) BC_USB_CHNG_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) EXTCON_IRQ_END,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static const unsigned int axp288_extcon_cables[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) EXTCON_CHG_USB_SDP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) EXTCON_CHG_USB_CDP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) EXTCON_CHG_USB_DCP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) EXTCON_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) EXTCON_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct axp288_extcon_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct regmap_irq_chip_data *regmap_irqc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct usb_role_switch *role_sw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct work_struct role_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int irq[EXTCON_IRQ_END];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct extcon_dev *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct extcon_dev *id_extcon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct notifier_block id_nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unsigned int previous_cable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) bool vbus_attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static const struct x86_cpu_id cherry_trail_cpu_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Power up/down reason string array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static const char * const axp288_pwr_up_down_info[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) "Last wake caused by user pressing the power button",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) "Last wake caused by a charger insertion",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) "Last wake caused by a battery insertion",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) "Last wake caused by SOC initiated global reset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) "Last wake caused by cold reset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) "Last shutdown caused by PMIC UVLO threshold",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) "Last shutdown caused by SOC initiated cold off",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "Last shutdown caused by user pressing the power button",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * Decode and log the given "reset source indicator" (rsi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * register and then clear it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned int val, i, clear_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) unsigned long bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) dev_err(info->dev, "failed to read reset source indicator\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for_each_set_bit(i, &bits, ARRAY_SIZE(axp288_pwr_up_down_info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) clear_mask = bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* Clear the register value for next reboot (write 1 to clear bit) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * The below code to control the USB role-switch on devices with an AXP288
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * may seem out of place, but there are 2 reasons why this is the best place
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * to control the USB role-switch on such devices:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * 1) On many devices the USB role is controlled by AML code, but the AML code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * only switches between the host and none roles, because of Windows not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * really using device mode. To make device mode work we need to toggle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * between the none/device roles based on Vbus presence, and this driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * gets interrupts on Vbus insertion / removal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * 2) In order for our BC1.2 charger detection to work properly the role
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * mux must be properly set to device mode before we do the detection.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* Returns the id-pin value, note pulled low / false == host-mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static bool axp288_get_id_pin(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) enum usb_role role;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (info->id_extcon)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return extcon_get_state(info->id_extcon, EXTCON_USB_HOST) <= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* We cannot access the id-pin, see what mode the AML code has set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) role = usb_role_switch_get_role(info->role_sw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return role != USB_ROLE_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static void axp288_usb_role_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct axp288_extcon_info *info =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) container_of(work, struct axp288_extcon_info, role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) enum usb_role role;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) bool id_pin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) id_pin = axp288_get_id_pin(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (!id_pin)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) role = USB_ROLE_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) else if (info->vbus_attach)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) role = USB_ROLE_DEVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) role = USB_ROLE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ret = usb_role_switch_set_role(info->role_sw, role);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) dev_err(info->dev, "failed to set role: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static bool axp288_get_vbus_attach(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int ret, pwr_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) dev_err(info->dev, "failed to read vbus status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return !!(pwr_stat & PS_STAT_VBUS_VALID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int ret, stat, cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) u8 chrg_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) unsigned int cable = info->previous_cable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) bool vbus_attach = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) vbus_attach = axp288_get_vbus_attach(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!vbus_attach)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) goto no_vbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* Check charger detection completion status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) goto dev_det_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (cfg & BC_GLOBAL_DET_STAT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) dev_dbg(info->dev, "can't complete the charger detection\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) goto dev_det_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto dev_det_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) switch (chrg_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) case DET_STAT_SDP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_dbg(info->dev, "sdp cable is connected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) cable = EXTCON_CHG_USB_SDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case DET_STAT_CDP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) dev_dbg(info->dev, "cdp cable is connected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) cable = EXTCON_CHG_USB_CDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case DET_STAT_DCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) dev_dbg(info->dev, "dcp cable is connected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) cable = EXTCON_CHG_USB_DCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) dev_warn(info->dev, "unknown (reserved) bc detect result\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) cable = EXTCON_CHG_USB_SDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) no_vbus:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) extcon_set_state_sync(info->edev, info->previous_cable, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (info->previous_cable == EXTCON_CHG_USB_SDP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) extcon_set_state_sync(info->edev, EXTCON_USB, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (vbus_attach) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) extcon_set_state_sync(info->edev, cable, vbus_attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (cable == EXTCON_CHG_USB_SDP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) extcon_set_state_sync(info->edev, EXTCON_USB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) vbus_attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) info->previous_cable = cable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (info->role_sw && info->vbus_attach != vbus_attach) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) info->vbus_attach = vbus_attach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /* Setting the role can take a while */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) queue_work(system_long_wq, &info->role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) dev_det_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) dev_err(info->dev, "failed to detect BC Mod\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static int axp288_extcon_id_evt(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) unsigned long event, void *param)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct axp288_extcon_info *info =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) container_of(nb, struct axp288_extcon_info, id_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) /* We may not sleep and setting the role can take a while */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) queue_work(system_long_wq, &info->role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static irqreturn_t axp288_extcon_isr(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct axp288_extcon_info *info = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) ret = axp288_handle_chrg_det_event(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) dev_err(info->dev, "failed to handle the interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static void axp288_extcon_enable(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) BC_GLOBAL_RUN, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /* Enable the charger detection logic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) BC_GLOBAL_RUN, BC_GLOBAL_RUN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static void axp288_put_role_sw(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct axp288_extcon_info *info = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) cancel_work_sync(&info->role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) usb_role_switch_put(info->role_sw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static int axp288_extcon_find_role_sw(struct axp288_extcon_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) const struct software_node *swnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) struct fwnode_handle *fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!x86_match_cpu(cherry_trail_cpu_ids))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (!swnode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) fwnode = software_node_fwnode(swnode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) info->role_sw = usb_role_switch_find_by_fwnode(fwnode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) fwnode_handle_put(fwnode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return info->role_sw ? 0 : -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int axp288_extcon_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) struct axp288_extcon_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct acpi_device *adev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int ret, i, pirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) info->regmap = axp20x->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) info->regmap_irqc = axp20x->regmap_irqc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) info->previous_cable = EXTCON_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) INIT_WORK(&info->role_work, axp288_usb_role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) info->id_nb.notifier_call = axp288_extcon_id_evt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ret = axp288_extcon_find_role_sw(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (info->role_sw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (adev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) put_device(&adev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (!info->id_extcon)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) dev_info(dev, "controlling USB role\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) dev_info(dev, "controlling USB role based on Vbus presence\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) info->vbus_attach = axp288_get_vbus_attach(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) axp288_extcon_log_rsi(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) /* Initialize extcon device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) info->edev = devm_extcon_dev_allocate(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) axp288_extcon_cables);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (IS_ERR(info->edev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return PTR_ERR(info->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Register extcon device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = devm_extcon_dev_register(&pdev->dev, info->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dev_err(&pdev->dev, "failed to register extcon device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) for (i = 0; i < EXTCON_IRQ_END; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) pirq = platform_get_irq(pdev, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (pirq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return pirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (info->irq[i] < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) "failed to get virtual interrupt=%d\n", pirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) ret = info->irq[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) NULL, axp288_extcon_isr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) IRQF_ONESHOT | IRQF_NO_SUSPEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pdev->name, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) dev_err(&pdev->dev, "failed to request interrupt=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) info->irq[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (info->id_extcon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) ret = devm_extcon_register_notifier_all(dev, info->id_extcon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) &info->id_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /* Make sure the role-sw is set correctly before doing BC detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (info->role_sw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) queue_work(system_long_wq, &info->role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) flush_work(&info->role_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) /* Start charger cable type detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) axp288_extcon_enable(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) device_init_wakeup(dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static int __maybe_unused axp288_extcon_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) struct axp288_extcon_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (device_may_wakeup(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) enable_irq_wake(info->irq[VBUS_RISING_IRQ]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) static int __maybe_unused axp288_extcon_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct axp288_extcon_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * Wakeup when a charger is connected to do charger-type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * connection and generate an extcon event which makes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * axp288 charger driver set the input current limit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (device_may_wakeup(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) disable_irq_wake(info->irq[VBUS_RISING_IRQ]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static SIMPLE_DEV_PM_OPS(axp288_extcon_pm_ops, axp288_extcon_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) axp288_extcon_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static const struct platform_device_id axp288_extcon_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) { .name = "axp288_extcon" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) MODULE_DEVICE_TABLE(platform, axp288_extcon_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static struct platform_driver axp288_extcon_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) .probe = axp288_extcon_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .id_table = axp288_extcon_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) .name = "axp288_extcon",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) .pm = &axp288_extcon_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) module_platform_driver(axp288_extcon_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) MODULE_LICENSE("GPL v2");