1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 24da498fcSLinus Walleij /* 34da498fcSLinus Walleij * 44da498fcSLinus Walleij * h3xxx atmel micro companion support, notification LED subdevice 54da498fcSLinus Walleij * 64da498fcSLinus Walleij * Author : Linus Walleij <linus.walleij@linaro.org> 74da498fcSLinus Walleij */ 84da498fcSLinus Walleij 94da498fcSLinus Walleij #include <linux/module.h> 104da498fcSLinus Walleij #include <linux/platform_device.h> 114da498fcSLinus Walleij #include <linux/mfd/ipaq-micro.h> 124da498fcSLinus Walleij #include <linux/leds.h> 134da498fcSLinus Walleij 144da498fcSLinus Walleij #define LED_YELLOW 0x00 154da498fcSLinus Walleij #define LED_GREEN 0x01 164da498fcSLinus Walleij 174da498fcSLinus Walleij #define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */ 184da498fcSLinus Walleij #define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */ 194da498fcSLinus Walleij #define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */ 204da498fcSLinus Walleij 21ba1c8179SJacek Anaszewski static int micro_leds_brightness_set(struct led_classdev *led_cdev, 224da498fcSLinus Walleij enum led_brightness value) 234da498fcSLinus Walleij { 244da498fcSLinus Walleij struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); 254da498fcSLinus Walleij /* 264da498fcSLinus Walleij * In this message: 274da498fcSLinus Walleij * Byte 0 = LED color: 0 = yellow, 1 = green 284da498fcSLinus Walleij * yellow LED is always ~30 blinks per minute 294da498fcSLinus Walleij * Byte 1 = duration (flags?) appears to be ignored 304da498fcSLinus Walleij * Byte 2 = green ontime in 1/10 sec (deciseconds) 314da498fcSLinus Walleij * 1 = 1/10 second 324da498fcSLinus Walleij * 0 = 256/10 second 334da498fcSLinus Walleij * Byte 3 = green offtime in 1/10 sec (deciseconds) 344da498fcSLinus Walleij * 1 = 1/10 second 354da498fcSLinus Walleij * 0 = 256/10 seconds 364da498fcSLinus Walleij */ 374da498fcSLinus Walleij struct ipaq_micro_msg msg = { 384da498fcSLinus Walleij .id = MSG_NOTIFY_LED, 394da498fcSLinus Walleij .tx_len = 4, 404da498fcSLinus Walleij }; 414da498fcSLinus Walleij 424da498fcSLinus Walleij msg.tx_data[0] = LED_GREEN; 434da498fcSLinus Walleij msg.tx_data[1] = 0; 444da498fcSLinus Walleij if (value) { 454da498fcSLinus Walleij msg.tx_data[2] = 0; /* Duty cycle 256 */ 464da498fcSLinus Walleij msg.tx_data[3] = 1; 474da498fcSLinus Walleij } else { 484da498fcSLinus Walleij msg.tx_data[2] = 1; 494da498fcSLinus Walleij msg.tx_data[3] = 0; /* Duty cycle 256 */ 504da498fcSLinus Walleij } 51ba1c8179SJacek Anaszewski return ipaq_micro_tx_msg_sync(micro, &msg); 524da498fcSLinus Walleij } 534da498fcSLinus Walleij 544da498fcSLinus Walleij /* Maximum duty cycle in ms 256/10 sec = 25600 ms */ 554da498fcSLinus Walleij #define IPAQ_LED_MAX_DUTY 25600 564da498fcSLinus Walleij 574da498fcSLinus Walleij static int micro_leds_blink_set(struct led_classdev *led_cdev, 584da498fcSLinus Walleij unsigned long *delay_on, 594da498fcSLinus Walleij unsigned long *delay_off) 604da498fcSLinus Walleij { 614da498fcSLinus Walleij struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent); 624da498fcSLinus Walleij /* 634da498fcSLinus Walleij * In this message: 644da498fcSLinus Walleij * Byte 0 = LED color: 0 = yellow, 1 = green 654da498fcSLinus Walleij * yellow LED is always ~30 blinks per minute 664da498fcSLinus Walleij * Byte 1 = duration (flags?) appears to be ignored 674da498fcSLinus Walleij * Byte 2 = green ontime in 1/10 sec (deciseconds) 684da498fcSLinus Walleij * 1 = 1/10 second 694da498fcSLinus Walleij * 0 = 256/10 second 704da498fcSLinus Walleij * Byte 3 = green offtime in 1/10 sec (deciseconds) 714da498fcSLinus Walleij * 1 = 1/10 second 724da498fcSLinus Walleij * 0 = 256/10 seconds 734da498fcSLinus Walleij */ 744da498fcSLinus Walleij struct ipaq_micro_msg msg = { 754da498fcSLinus Walleij .id = MSG_NOTIFY_LED, 764da498fcSLinus Walleij .tx_len = 4, 774da498fcSLinus Walleij }; 784da498fcSLinus Walleij 794da498fcSLinus Walleij msg.tx_data[0] = LED_GREEN; 804da498fcSLinus Walleij if (*delay_on > IPAQ_LED_MAX_DUTY || 814da498fcSLinus Walleij *delay_off > IPAQ_LED_MAX_DUTY) 824da498fcSLinus Walleij return -EINVAL; 834da498fcSLinus Walleij 844da498fcSLinus Walleij if (*delay_on == 0 && *delay_off == 0) { 854da498fcSLinus Walleij *delay_on = 100; 864da498fcSLinus Walleij *delay_off = 100; 874da498fcSLinus Walleij } 884da498fcSLinus Walleij 894da498fcSLinus Walleij msg.tx_data[1] = 0; 904da498fcSLinus Walleij if (*delay_on >= IPAQ_LED_MAX_DUTY) 914da498fcSLinus Walleij msg.tx_data[2] = 0; 924da498fcSLinus Walleij else 934da498fcSLinus Walleij msg.tx_data[2] = (u8) DIV_ROUND_CLOSEST(*delay_on, 100); 944da498fcSLinus Walleij if (*delay_off >= IPAQ_LED_MAX_DUTY) 954da498fcSLinus Walleij msg.tx_data[3] = 0; 964da498fcSLinus Walleij else 974da498fcSLinus Walleij msg.tx_data[3] = (u8) DIV_ROUND_CLOSEST(*delay_off, 100); 984da498fcSLinus Walleij return ipaq_micro_tx_msg_sync(micro, &msg); 994da498fcSLinus Walleij } 1004da498fcSLinus Walleij 1014da498fcSLinus Walleij static struct led_classdev micro_led = { 1024da498fcSLinus Walleij .name = "led-ipaq-micro", 103ba1c8179SJacek Anaszewski .brightness_set_blocking = micro_leds_brightness_set, 1044da498fcSLinus Walleij .blink_set = micro_leds_blink_set, 1054da498fcSLinus Walleij .flags = LED_CORE_SUSPENDRESUME, 1064da498fcSLinus Walleij }; 1074da498fcSLinus Walleij 1084da498fcSLinus Walleij static int micro_leds_probe(struct platform_device *pdev) 1094da498fcSLinus Walleij { 1104da498fcSLinus Walleij int ret; 1114da498fcSLinus Walleij 112431557f4SMuhammad Falak R Wani ret = devm_led_classdev_register(&pdev->dev, µ_led); 1134da498fcSLinus Walleij if (ret) { 1144da498fcSLinus Walleij dev_err(&pdev->dev, "registering led failed: %d\n", ret); 1154da498fcSLinus Walleij return ret; 1164da498fcSLinus Walleij } 1174da498fcSLinus Walleij dev_info(&pdev->dev, "iPAQ micro notification LED driver\n"); 1184da498fcSLinus Walleij 1194da498fcSLinus Walleij return 0; 1204da498fcSLinus Walleij } 1214da498fcSLinus Walleij 122e661c897SWei Yongjun static struct platform_driver micro_leds_device_driver = { 1234da498fcSLinus Walleij .driver = { 1244da498fcSLinus Walleij .name = "ipaq-micro-leds", 1254da498fcSLinus Walleij }, 1264da498fcSLinus Walleij .probe = micro_leds_probe, 1274da498fcSLinus Walleij }; 1284da498fcSLinus Walleij module_platform_driver(micro_leds_device_driver); 1294da498fcSLinus Walleij 1304da498fcSLinus Walleij MODULE_LICENSE("GPL"); 1314da498fcSLinus Walleij MODULE_DESCRIPTION("driver for iPAQ Atmel micro leds"); 1324da498fcSLinus Walleij MODULE_ALIAS("platform:ipaq-micro-leds"); 133