1 /* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/leds.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
19 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
20 MODULE_DESCRIPTION("Sun Fire LED driver");
21 MODULE_LICENSE("GPL");
24 struct led_classdev led_cdev
;
27 #define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
29 static void __clockboard_set(struct led_classdev
*led_cdev
,
30 enum led_brightness led_val
, u8 bit
)
32 struct sunfire_led
*p
= to_sunfire_led(led_cdev
);
33 u8 reg
= upa_readb(p
->reg
);
50 upa_writeb(reg
, p
->reg
);
53 static void clockboard_left_set(struct led_classdev
*led_cdev
,
54 enum led_brightness led_val
)
56 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_LLED
);
59 static void clockboard_middle_set(struct led_classdev
*led_cdev
,
60 enum led_brightness led_val
)
62 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_MLED
);
65 static void clockboard_right_set(struct led_classdev
*led_cdev
,
66 enum led_brightness led_val
)
68 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_RLED
);
71 static void __fhc_set(struct led_classdev
*led_cdev
,
72 enum led_brightness led_val
, u32 bit
)
74 struct sunfire_led
*p
= to_sunfire_led(led_cdev
);
75 u32 reg
= upa_readl(p
->reg
);
78 case FHC_CONTROL_LLED
:
92 upa_writel(reg
, p
->reg
);
95 static void fhc_left_set(struct led_classdev
*led_cdev
,
96 enum led_brightness led_val
)
98 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_LLED
);
101 static void fhc_middle_set(struct led_classdev
*led_cdev
,
102 enum led_brightness led_val
)
104 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_MLED
);
107 static void fhc_right_set(struct led_classdev
*led_cdev
,
108 enum led_brightness led_val
)
110 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_RLED
);
113 typedef void (*set_handler
)(struct led_classdev
*, enum led_brightness
);
117 const char *default_trigger
;
120 #define NUM_LEDS_PER_BOARD 3
121 struct sunfire_drvdata
{
122 struct sunfire_led leds
[NUM_LEDS_PER_BOARD
];
125 static int sunfire_led_generic_probe(struct platform_device
*pdev
,
126 struct led_type
*types
)
128 struct sunfire_drvdata
*p
;
131 if (pdev
->num_resources
!= 1) {
132 dev_err(&pdev
->dev
, "Wrong number of resources %d, should be 1\n",
133 pdev
->num_resources
);
137 p
= devm_kzalloc(&pdev
->dev
, sizeof(*p
), GFP_KERNEL
);
141 for (i
= 0; i
< NUM_LEDS_PER_BOARD
; i
++) {
142 struct led_classdev
*lp
= &p
->leds
[i
].led_cdev
;
144 p
->leds
[i
].reg
= (void __iomem
*) pdev
->resource
[0].start
;
145 lp
->name
= types
[i
].name
;
146 lp
->brightness
= LED_FULL
;
147 lp
->brightness_set
= types
[i
].handler
;
148 lp
->default_trigger
= types
[i
].default_trigger
;
150 err
= led_classdev_register(&pdev
->dev
, lp
);
152 dev_err(&pdev
->dev
, "Could not register %s LED\n",
154 for (i
--; i
>= 0; i
--)
155 led_classdev_unregister(&p
->leds
[i
].led_cdev
);
160 platform_set_drvdata(pdev
, p
);
165 static int sunfire_led_generic_remove(struct platform_device
*pdev
)
167 struct sunfire_drvdata
*p
= platform_get_drvdata(pdev
);
170 for (i
= 0; i
< NUM_LEDS_PER_BOARD
; i
++)
171 led_classdev_unregister(&p
->leds
[i
].led_cdev
);
176 static struct led_type clockboard_led_types
[NUM_LEDS_PER_BOARD
] = {
178 .name
= "clockboard-left",
179 .handler
= clockboard_left_set
,
182 .name
= "clockboard-middle",
183 .handler
= clockboard_middle_set
,
186 .name
= "clockboard-right",
187 .handler
= clockboard_right_set
,
188 .default_trigger
= "heartbeat",
192 static int sunfire_clockboard_led_probe(struct platform_device
*pdev
)
194 return sunfire_led_generic_probe(pdev
, clockboard_led_types
);
197 static struct led_type fhc_led_types
[NUM_LEDS_PER_BOARD
] = {
200 .handler
= fhc_left_set
,
203 .name
= "fhc-middle",
204 .handler
= fhc_middle_set
,
208 .handler
= fhc_right_set
,
209 .default_trigger
= "heartbeat",
213 static int sunfire_fhc_led_probe(struct platform_device
*pdev
)
215 return sunfire_led_generic_probe(pdev
, fhc_led_types
);
218 MODULE_ALIAS("platform:sunfire-clockboard-leds");
219 MODULE_ALIAS("platform:sunfire-fhc-leds");
221 static struct platform_driver sunfire_clockboard_led_driver
= {
222 .probe
= sunfire_clockboard_led_probe
,
223 .remove
= sunfire_led_generic_remove
,
225 .name
= "sunfire-clockboard-leds",
229 static struct platform_driver sunfire_fhc_led_driver
= {
230 .probe
= sunfire_fhc_led_probe
,
231 .remove
= sunfire_led_generic_remove
,
233 .name
= "sunfire-fhc-leds",
237 static int __init
sunfire_leds_init(void)
239 int err
= platform_driver_register(&sunfire_clockboard_led_driver
);
242 pr_err("Could not register clock board LED driver\n");
246 err
= platform_driver_register(&sunfire_fhc_led_driver
);
248 pr_err("Could not register FHC LED driver\n");
249 platform_driver_unregister(&sunfire_clockboard_led_driver
);
255 static void __exit
sunfire_leds_exit(void)
257 platform_driver_unregister(&sunfire_clockboard_led_driver
);
258 platform_driver_unregister(&sunfire_fhc_led_driver
);
261 module_init(sunfire_leds_init
);
262 module_exit(sunfire_leds_exit
);