Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | // SPDX-License-Identifier: GPL-2.0+ /* * Software blinking helpers * Copyright (C) 2024 IOPSYS Software Solutions AB * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> */ #include <cyclic.h> #include <dm.h> #include <led.h> #include <time.h> #include <stdlib.h> #define CYCLIC_NAME_PREFIX "led_sw_blink_" static void led_sw_blink(struct cyclic_info *c) { struct led_sw_blink *sw_blink; struct udevice *dev; struct led_ops *ops; sw_blink = container_of(c, struct led_sw_blink, cyclic); dev = sw_blink->dev; ops = led_get_ops(dev); switch (sw_blink->state) { case LED_SW_BLINK_ST_OFF: sw_blink->state = LED_SW_BLINK_ST_ON; ops->set_state(dev, LEDST_ON); break; case LED_SW_BLINK_ST_ON: sw_blink->state = LED_SW_BLINK_ST_OFF; ops->set_state(dev, LEDST_OFF); break; case LED_SW_BLINK_ST_NOT_READY: /* * led_set_period has been called, but * led_set_state(LDST_BLINK) has not yet, * so doing nothing */ break; default: break; } } int led_sw_set_period(struct udevice *dev, int period_ms) { struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev); struct led_sw_blink *sw_blink = uc_plat->sw_blink; struct led_ops *ops = led_get_ops(dev); int half_period_us; half_period_us = period_ms * 1000 / 2; if (!sw_blink) { int len = sizeof(struct led_sw_blink) + strlen(CYCLIC_NAME_PREFIX) + strlen(uc_plat->label) + 1; sw_blink = calloc(1, len); if (!sw_blink) return -ENOMEM; sw_blink->dev = dev; sw_blink->state = LED_SW_BLINK_ST_DISABLED; strcpy((char *)sw_blink->cyclic_name, CYCLIC_NAME_PREFIX); strcat((char *)sw_blink->cyclic_name, uc_plat->label); uc_plat->sw_blink = sw_blink; } if (sw_blink->state == LED_SW_BLINK_ST_DISABLED) { cyclic_register(&sw_blink->cyclic, led_sw_blink, half_period_us, sw_blink->cyclic_name); } else { sw_blink->cyclic.delay_us = half_period_us; sw_blink->cyclic.start_time_us = timer_get_us(); } sw_blink->state = LED_SW_BLINK_ST_NOT_READY; ops->set_state(dev, LEDST_OFF); return 0; } bool led_sw_is_blinking(struct udevice *dev) { struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev); struct led_sw_blink *sw_blink = uc_plat->sw_blink; if (!sw_blink) return false; return sw_blink->state > LED_SW_BLINK_ST_NOT_READY; } bool led_sw_on_state_change(struct udevice *dev, enum led_state_t state) { struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev); struct led_sw_blink *sw_blink = uc_plat->sw_blink; if (!sw_blink || sw_blink->state == LED_SW_BLINK_ST_DISABLED) return false; if (state == LEDST_BLINK) { struct led_ops *ops = led_get_ops(dev); /* * toggle LED initially and start blinking on next * led_sw_blink() call. */ switch (ops->get_state(dev)) { case LEDST_ON: ops->set_state(dev, LEDST_OFF); sw_blink->state = LED_SW_BLINK_ST_OFF; default: ops->set_state(dev, LEDST_ON); sw_blink->state = LED_SW_BLINK_ST_ON; } return true; } /* stop blinking */ uc_plat->sw_blink = NULL; cyclic_unregister(&sw_blink->cyclic); free(sw_blink); return false; } |