1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * LED Driver for SGI Octane machines 4 */ 5 6 #include <asm/io.h> 7 #include <linux/module.h> 8 #include <linux/kernel.h> 9 #include <linux/platform_device.h> 10 #include <linux/leds.h> 11 12 #define IP30_LED_SYSTEM 0 13 #define IP30_LED_FAULT 1 14 15 struct ip30_led { 16 struct led_classdev cdev; 17 u32 __iomem *reg; 18 }; 19 20 static void ip30led_set(struct led_classdev *led_cdev, 21 enum led_brightness value) 22 { 23 struct ip30_led *led = container_of(led_cdev, struct ip30_led, cdev); 24 25 writel(value, led->reg); 26 } 27 28 static int ip30led_create(struct platform_device *pdev, int num) 29 { 30 struct resource *res; 31 struct ip30_led *data; 32 33 res = platform_get_resource(pdev, IORESOURCE_MEM, num); 34 if (!res) 35 return -EBUSY; 36 37 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 38 if (!data) 39 return -ENOMEM; 40 41 data->reg = devm_ioremap_resource(&pdev->dev, res); 42 if (IS_ERR(data->reg)) 43 return PTR_ERR(data->reg); 44 45 46 switch (num) { 47 case IP30_LED_SYSTEM: 48 data->cdev.name = "white:power"; 49 break; 50 case IP30_LED_FAULT: 51 data->cdev.name = "red:fault"; 52 break; 53 default: 54 return -EINVAL; 55 } 56 57 data->cdev.brightness = readl(data->reg); 58 data->cdev.max_brightness = 1; 59 data->cdev.brightness_set = ip30led_set; 60 61 return devm_led_classdev_register(&pdev->dev, &data->cdev); 62 } 63 64 static int ip30led_probe(struct platform_device *pdev) 65 { 66 int ret; 67 68 ret = ip30led_create(pdev, IP30_LED_SYSTEM); 69 if (ret < 0) 70 return ret; 71 72 return ip30led_create(pdev, IP30_LED_FAULT); 73 } 74 75 static struct platform_driver ip30led_driver = { 76 .probe = ip30led_probe, 77 .driver = { 78 .name = "ip30-leds", 79 }, 80 }; 81 82 module_platform_driver(ip30led_driver); 83 84 MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>"); 85 MODULE_DESCRIPTION("SGI Octane LED driver"); 86 MODULE_LICENSE("GPL"); 87 MODULE_ALIAS("platform:ip30-leds"); 88