162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  LEDs triggers for power supply class
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright © 2007  Anton Vorontsov <cbou@mail.ru>
662306a36Sopenharmony_ci *  Copyright © 2004  Szabolcs Gyurko
762306a36Sopenharmony_ci *  Copyright © 2003  Ian Molton <spyro@f2s.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Modified: 2004, Oct     Szabolcs Gyurko
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/power_supply.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/leds.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "power_supply.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Battery specific LEDs triggers. */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic void power_supply_update_bat_leds(struct power_supply *psy)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	union power_supply_propval status;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
2762306a36Sopenharmony_ci		return;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	dev_dbg(&psy->dev, "%s %d\n", __func__, status.intval);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	switch (status.intval) {
3262306a36Sopenharmony_ci	case POWER_SUPPLY_STATUS_FULL:
3362306a36Sopenharmony_ci		led_trigger_event(psy->charging_full_trig, LED_FULL);
3462306a36Sopenharmony_ci		led_trigger_event(psy->charging_trig, LED_OFF);
3562306a36Sopenharmony_ci		led_trigger_event(psy->full_trig, LED_FULL);
3662306a36Sopenharmony_ci		/* Going from blink to LED on requires a LED_OFF event to stop blink */
3762306a36Sopenharmony_ci		led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF);
3862306a36Sopenharmony_ci		led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL);
3962306a36Sopenharmony_ci		break;
4062306a36Sopenharmony_ci	case POWER_SUPPLY_STATUS_CHARGING:
4162306a36Sopenharmony_ci		led_trigger_event(psy->charging_full_trig, LED_FULL);
4262306a36Sopenharmony_ci		led_trigger_event(psy->charging_trig, LED_FULL);
4362306a36Sopenharmony_ci		led_trigger_event(psy->full_trig, LED_OFF);
4462306a36Sopenharmony_ci		led_trigger_blink(psy->charging_blink_full_solid_trig, 0, 0);
4562306a36Sopenharmony_ci		break;
4662306a36Sopenharmony_ci	default:
4762306a36Sopenharmony_ci		led_trigger_event(psy->charging_full_trig, LED_OFF);
4862306a36Sopenharmony_ci		led_trigger_event(psy->charging_trig, LED_OFF);
4962306a36Sopenharmony_ci		led_trigger_event(psy->full_trig, LED_OFF);
5062306a36Sopenharmony_ci		led_trigger_event(psy->charging_blink_full_solid_trig,
5162306a36Sopenharmony_ci			LED_OFF);
5262306a36Sopenharmony_ci		break;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int power_supply_create_bat_triggers(struct power_supply *psy)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
5962306a36Sopenharmony_ci					"%s-charging-or-full", psy->desc->name);
6062306a36Sopenharmony_ci	if (!psy->charging_full_trig_name)
6162306a36Sopenharmony_ci		goto charging_full_failed;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	psy->charging_trig_name = kasprintf(GFP_KERNEL,
6462306a36Sopenharmony_ci					"%s-charging", psy->desc->name);
6562306a36Sopenharmony_ci	if (!psy->charging_trig_name)
6662306a36Sopenharmony_ci		goto charging_failed;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->desc->name);
6962306a36Sopenharmony_ci	if (!psy->full_trig_name)
7062306a36Sopenharmony_ci		goto full_failed;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
7362306a36Sopenharmony_ci		"%s-charging-blink-full-solid", psy->desc->name);
7462306a36Sopenharmony_ci	if (!psy->charging_blink_full_solid_trig_name)
7562306a36Sopenharmony_ci		goto charging_blink_full_solid_failed;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	led_trigger_register_simple(psy->charging_full_trig_name,
7862306a36Sopenharmony_ci				    &psy->charging_full_trig);
7962306a36Sopenharmony_ci	led_trigger_register_simple(psy->charging_trig_name,
8062306a36Sopenharmony_ci				    &psy->charging_trig);
8162306a36Sopenharmony_ci	led_trigger_register_simple(psy->full_trig_name,
8262306a36Sopenharmony_ci				    &psy->full_trig);
8362306a36Sopenharmony_ci	led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
8462306a36Sopenharmony_ci				    &psy->charging_blink_full_solid_trig);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cicharging_blink_full_solid_failed:
8962306a36Sopenharmony_ci	kfree(psy->full_trig_name);
9062306a36Sopenharmony_cifull_failed:
9162306a36Sopenharmony_ci	kfree(psy->charging_trig_name);
9262306a36Sopenharmony_cicharging_failed:
9362306a36Sopenharmony_ci	kfree(psy->charging_full_trig_name);
9462306a36Sopenharmony_cicharging_full_failed:
9562306a36Sopenharmony_ci	return -ENOMEM;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic void power_supply_remove_bat_triggers(struct power_supply *psy)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	led_trigger_unregister_simple(psy->charging_full_trig);
10162306a36Sopenharmony_ci	led_trigger_unregister_simple(psy->charging_trig);
10262306a36Sopenharmony_ci	led_trigger_unregister_simple(psy->full_trig);
10362306a36Sopenharmony_ci	led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
10462306a36Sopenharmony_ci	kfree(psy->charging_blink_full_solid_trig_name);
10562306a36Sopenharmony_ci	kfree(psy->full_trig_name);
10662306a36Sopenharmony_ci	kfree(psy->charging_trig_name);
10762306a36Sopenharmony_ci	kfree(psy->charging_full_trig_name);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* Generated power specific LEDs triggers. */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void power_supply_update_gen_leds(struct power_supply *psy)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	union power_supply_propval online;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
11762306a36Sopenharmony_ci		return;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (online.intval)
12262306a36Sopenharmony_ci		led_trigger_event(psy->online_trig, LED_FULL);
12362306a36Sopenharmony_ci	else
12462306a36Sopenharmony_ci		led_trigger_event(psy->online_trig, LED_OFF);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int power_supply_create_gen_triggers(struct power_supply *psy)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online",
13062306a36Sopenharmony_ci					  psy->desc->name);
13162306a36Sopenharmony_ci	if (!psy->online_trig_name)
13262306a36Sopenharmony_ci		return -ENOMEM;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic void power_supply_remove_gen_triggers(struct power_supply *psy)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	led_trigger_unregister_simple(psy->online_trig);
14262306a36Sopenharmony_ci	kfree(psy->online_trig_name);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Choice what triggers to create&update. */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_civoid power_supply_update_leds(struct power_supply *psy)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
15062306a36Sopenharmony_ci		power_supply_update_bat_leds(psy);
15162306a36Sopenharmony_ci	else
15262306a36Sopenharmony_ci		power_supply_update_gen_leds(psy);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciint power_supply_create_triggers(struct power_supply *psy)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
15862306a36Sopenharmony_ci		return power_supply_create_bat_triggers(psy);
15962306a36Sopenharmony_ci	return power_supply_create_gen_triggers(psy);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_civoid power_supply_remove_triggers(struct power_supply *psy)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	if (psy->desc->type == POWER_SUPPLY_TYPE_BATTERY)
16562306a36Sopenharmony_ci		power_supply_remove_bat_triggers(psy);
16662306a36Sopenharmony_ci	else
16762306a36Sopenharmony_ci		power_supply_remove_gen_triggers(psy);
16862306a36Sopenharmony_ci}
169