/* * drivers/power/supply/axp152_vbus_power.c * (C) Copyright 2020-2025 * Allwinner Technology Co., Ltd. * * vbus driver of axp152 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * */ #include #include #include #include #include #include #include #include #include #include #include struct vbus_power { struct axp20x_dev *axp20x; char *bootreason; struct delayed_work vbus_work; unsigned int interval; }; static struct vbus_power vbus; static enum power_supply_property axp152_usb_ac_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, }; static int axp152_read_vbus_state(union power_supply_propval *val) { int ret = 0; unsigned int data; ret = regmap_read(vbus.axp20x->regmap, AXP152_GPIO_INPUT, &data); if (ret < 0) return ret; /* vbus is good when vbus state set */ val->intval = !!(~data & (1 << 1)); return ret; } static int axp152_usb_ac_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { int ret = 0; switch (psp) { case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_PRESENT: ret = axp152_read_vbus_state(val); break; default: break; } return ret; } #if 0 /* check the gpio1's status in per 1s */ static void check_vbus_status(struct work_struct *work) { unsigned int val; struct vbus_power *vbus_dev = container_of(work, struct vbus_power, vbus_work.work); regmap_read(vbus_dev->axp20x->regmap, AXP152_GPIO_INPUT, &val); schedule_delayed_work(&vbus.vbus_work, vbus.interval); } #endif static int axp152_vbus_probe(struct platform_device *pdev) { struct power_supply_desc *ac_desc; struct power_supply *ac; // unsigned int val, vbus_val; int ret = 0; struct power_supply_config psy_cfg = { .of_node = pdev->dev.of_node, }; vbus.axp20x = dev_get_drvdata(pdev->dev.parent); if (!vbus.axp20x) { dev_err(&pdev->dev, "Parent drvdata not set\n"); return -EINVAL; } #if 0 /* set gpio1 control */ regmap_read(vbus.axp20x->regmap, AXP152_GPIO1_CTRL, &val); val &= ~(0x7); val |= 0x3; regmap_write(vbus.axp20x->regmap, AXP152_GPIO1_CTRL, val); /* check the source of power on*/ regmap_read(vbus.axp20x->regmap, AXP152_PWR_OP_MODE, &val); /* check the vbus */ regmap_read(vbus.axp20x->regmap, AXP152_GPIO_INPUT, &vbus_val); vbus.interval = msecs_to_jiffies(1 * 1000); INIT_DELAYED_WORK(&vbus.vbus_work, check_vbus_status); schedule_delayed_work(&vbus.vbus_work, vbus.interval); #endif ac_desc = devm_kzalloc(&pdev->dev, sizeof(*ac_desc), GFP_KERNEL); if (!ac_desc) { ret = -ENOMEM; goto err; } ac_desc->name = "ac"; ac_desc->type = POWER_SUPPLY_TYPE_MAINS; ac_desc->properties = axp152_usb_ac_props; ac_desc->num_properties = ARRAY_SIZE(axp152_usb_ac_props); ac_desc->get_property = axp152_usb_ac_get_property; ac_desc->set_property = NULL; ac_desc->property_is_writeable = NULL; ac = power_supply_register(&pdev->dev, ac_desc, &psy_cfg); if (IS_ERR(ac)) { printk("failed to register vbus_power\n"); ret = PTR_ERR(ac); goto err; } return 0; err: power_supply_unregister(ac); return ret; } static const struct of_device_id axp152_vbus_match[] = { { .compatible = "x-powers,axp152-vbus" }, { }, }; static struct platform_driver axp152_vbus_driver = { .probe = axp152_vbus_probe, .driver = { .name = "axp152-vbus", .of_match_table = axp152_vbus_match, }, }; module_platform_driver(axp152_vbus_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR(""); MODULE_DESCRIPTION("vbus Driver for axp152 PMIC");