led子系统
driver/leds/led-class.c
leds_init
class_create
static const struct attribute_group *led_groups[] = {
&led_group,
#ifdef CONFIG_LEDS_TRIGGERS
&led_trigger_group,
#endif
NULL,
};
led_classdev_unregister
led_classdev_register
devm_led_classdev_register
devm_led_classdev_release
leds_init
class_create
static const struct attribute_group *led_groups[] = {
&led_group,
#ifdef CONFIG_LEDS_TRIGGERS
&led_trigger_group,
#endif
NULL,
};
led_classdev_unregister
led_classdev_register
devm_led_classdev_register
devm_led_classdev_release
driver/leds/led-core.c
led_sysfs_enable
led_update_brightness
led_blink_set_oneshot
led_blink_set
led_init_core
led_sysfs_enable
led_update_brightness
led_blink_set_oneshot
led_blink_set
led_init_core
driver/leds/led-triggers.c
led_trigger_register_simple
led_trigger_event
led_trigger_register
led_trigger_set_default
led_trigger_store
led_trigger_register_simple
led_trigger_event
led_trigger_register
led_trigger_set_default
led_trigger_store
include/linux/leds.h
driver/leds/trigger/ledtrig-camera.c
ledtrig_flash_ctrl
ledtrig_torch_ctrl
ledtrig_camera_init
driver/leds/trigger/ledtrig-camera.c
ledtrig_flash_ctrl
ledtrig_torch_ctrl
ledtrig_camera_init
driver/leds/trigger/ledtrig-oneshot.c
driver/leds/trigger/ledtrig-timer.c
driver/leds/trigger/ledtrig-heartbeat.c
container_of作用是通过结构体某个成员地址从而拿到整个结构体地址。
先看leds-sprd-gpio-rgb.c
sprd_leds_gpio_rgb_driver
sprd_leds_gpio_rgb_probe
of_get_gpio
devm_gpio_request
p->cdev.brightness_set = sprd_leds_gpio_rgb_set;
led_classdev_register
sprd_leds_gpio_rgb_driver
sprd_leds_gpio_rgb_probe
of_get_gpio
devm_gpio_request
p->cdev.brightness_set = sprd_leds_gpio_rgb_set;
led_classdev_register
sprd_leds_gpio_rgb_set
container_of(led_cdev, struct sprd_leds_gpio_rgb, cdev)//通过结构体某个成员地址从而拿到整个结构体地址。
sprd_leds_rgb_work
sprd_leds_gpio_rgb_enable/sprd_leds_gpio_rgb_disable
container_of(led_cdev, struct sprd_leds_gpio_rgb, cdev)//通过结构体某个成员地址从而拿到整个结构体地址。
sprd_leds_rgb_work
sprd_leds_gpio_rgb_enable/sprd_leds_gpio_rgb_disable
再看leds-gpio.c
gpio_led_driver
gpio_led_probe
priv = gpio_leds_create(pdev);
devm_get_gpiod_from_child
fwnode_property_present(child, "label")
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
fwnode_property_read_string(child, "default-state",
&state)
fwnode_property_present(child, "retain-state-suspended")
create_gpio_led
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->cdev.blink_set = gpio_blink_set;
led_dat->cdev.brightness_set = gpio_led_set;
ret = gpiod_direction_output(led_dat->gpiod, state);
INIT_WORK(&led_dat->work, gpio_led_work);
return led_classdev_register(parent, &led_dat->cdev);
gpio_led_driver
gpio_led_probe
priv = gpio_leds_create(pdev);
devm_get_gpiod_from_child
fwnode_property_present(child, "label")
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
fwnode_property_read_string(child, "default-state",
&state)
fwnode_property_present(child, "retain-state-suspended")
create_gpio_led
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->cdev.blink_set = gpio_blink_set;
led_dat->cdev.brightness_set = gpio_led_set;
ret = gpiod_direction_output(led_dat->gpiod, state);
INIT_WORK(&led_dat->work, gpio_led_work);
return led_classdev_register(parent, &led_dat->cdev);
static void gpio_led_work(struct work_struct *work)
led_dat->platform_gpio_blink_set(led_dat->gpiod,
led_dat->new_level, NULL, NULL);
led_dat->platform_gpio_blink_set(led_dat->gpiod,
led_dat->new_level, NULL, NULL);
再看leds-lp8860.c
lp8860_driver
lp8860_probe
of_property_read_string(np, "label", &led->label)
devm_gpiod_get_optional(&client->dev,
"enable", GPIOD_OUT_LOW);
led->regulator = devm_regulator_get(&client->dev, "vled");
led->led_dev.brightness_set = lp8860_brightness_set;
INIT_WORK(&led->work, lp8860_led_brightness_work);
i2c_set_clientdata(client, led);
lp8860_init
ret = led_classdev_register(&client->dev, &led->led_dev);
lp8860_driver
lp8860_probe
of_property_read_string(np, "label", &led->label)
devm_gpiod_get_optional(&client->dev,
"enable", GPIOD_OUT_LOW);
led->regulator = devm_regulator_get(&client->dev, "vled");
led->led_dev.brightness_set = lp8860_brightness_set;
INIT_WORK(&led->work, lp8860_led_brightness_work);
i2c_set_clientdata(client, led);
lp8860_init
ret = led_classdev_register(&client->dev, &led->led_dev);
lp8860_led_brightness_work
ret = lp8860_fault_check(led);
regmap_write
ret = lp8860_fault_check(led);
regmap_write
lp8860_brightness_set
schedule_work(&led->work);
schedule_work(&led->work);
现在看led_classdev_register
led_classdev_register
led_classdev_next_name
device_create_with_groups
list_add_tail
led_update_brightness(led_cdev);
led_init_core(led_cdev);
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
setup_timer(&led_cdev->blink_timer, led_timer_function,
(unsigned long)led_cdev);
led_trigger_set_default(led_cdev);
led_trigger_set(led_cdev, trig);
led_classdev_register
led_classdev_next_name
device_create_with_groups
list_add_tail
led_update_brightness(led_cdev);
led_init_core(led_cdev);
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
setup_timer(&led_cdev->blink_timer, led_timer_function,
(unsigned long)led_cdev);
led_trigger_set_default(led_cdev);
led_trigger_set(led_cdev, trig);
再看ledtrig-gpio.c
gpio_trig_init
led_trigger_register
list_add_tail(&trig->next_trig, &trigger_list);
led_trigger_set(led_cdev, trig);
trig->activate(led_cdev);
dev_attr_gpio
dev_attr_inverted
dev_attr_desired_brightness
INIT_WORK(&gpio_data->work, gpio_trig_work);
gpio_trig_init
led_trigger_register
list_add_tail(&trig->next_trig, &trigger_list);
led_trigger_set(led_cdev, trig);
trig->activate(led_cdev);
dev_attr_gpio
dev_attr_inverted
dev_attr_desired_brightness
INIT_WORK(&gpio_data->work, gpio_trig_work);
dev_attr_gpio
gpio_trig_gpio_show
gpio_data->gpio
gpio_trig_gpio_store
request_irq(gpio_to_irq(gpio), gpio_trig_irq,
IRQF_SHARED | IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
gpio_data->gpio = gpio;
gpio_trig_gpio_show
gpio_data->gpio
gpio_trig_gpio_store
request_irq(gpio_to_irq(gpio), gpio_trig_irq,
IRQF_SHARED | IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING, "ledtrig-gpio", led);
gpio_data->gpio = gpio;
dev_attr_inverted
gpio_trig_inverted_show
gpio_data->inverted
gpio_trig_inverted_store
schedule_work(&gpio_data->work);
gpio_trig_inverted_show
gpio_data->inverted
gpio_trig_inverted_store
schedule_work(&gpio_data->work);
dev_attr_desired_brightness
gpio_trig_brightness_show
gpio_data->desired_brightness
gpio_trig_brightness_store
gpio_data->desired_brightness = desired_brightness;
gpio_trig_brightness_show
gpio_data->desired_brightness
gpio_trig_brightness_store
gpio_data->desired_brightness = desired_brightness;
所谓的led子系统,其实就是led和led-trigger相匹配。led设置设备的驱动,led-trigger来设置灯效触发方式。
设备驱动将led_cdev->node加到leds_list
然后list_for_each_entry(led_cdev, &leds_list, node) 找到leds_list的 led_cdev 执行led_trigger_set(led_cdev, NULL);
但是前提是需要一个led_dat->cdev.default_trigger存在。
设备驱动将led_cdev->node加到leds_list
然后list_for_each_entry(led_cdev, &leds_list, node) 找到leds_list的 led_cdev 执行led_trigger_set(led_cdev, NULL);
但是前提是需要一个led_dat->cdev.default_trigger存在。