1 /* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/init.h>
9 #include <linux/leds.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
17 #define DRIVER_NAME "leds-sunfire"
18 #define PFX DRIVER_NAME ": "
20 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
21 MODULE_DESCRIPTION("Sun Fire LED driver");
22 MODULE_LICENSE("GPL");
25 struct led_classdev led_cdev
;
28 #define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
30 static void __clockboard_set(struct led_classdev
*led_cdev
,
31 enum led_brightness led_val
, u8 bit
)
33 struct sunfire_led
*p
= to_sunfire_led(led_cdev
);
34 u8 reg
= upa_readb(p
->reg
);
51 upa_writeb(reg
, p
->reg
);
54 static void clockboard_left_set(struct led_classdev
*led_cdev
,
55 enum led_brightness led_val
)
57 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_LLED
);
60 static void clockboard_middle_set(struct led_classdev
*led_cdev
,
61 enum led_brightness led_val
)
63 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_MLED
);
66 static void clockboard_right_set(struct led_classdev
*led_cdev
,
67 enum led_brightness led_val
)
69 __clockboard_set(led_cdev
, led_val
, CLOCK_CTRL_RLED
);
72 static void __fhc_set(struct led_classdev
*led_cdev
,
73 enum led_brightness led_val
, u32 bit
)
75 struct sunfire_led
*p
= to_sunfire_led(led_cdev
);
76 u32 reg
= upa_readl(p
->reg
);
79 case FHC_CONTROL_LLED
:
93 upa_writel(reg
, p
->reg
);
96 static void fhc_left_set(struct led_classdev
*led_cdev
,
97 enum led_brightness led_val
)
99 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_LLED
);
102 static void fhc_middle_set(struct led_classdev
*led_cdev
,
103 enum led_brightness led_val
)
105 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_MLED
);
108 static void fhc_right_set(struct led_classdev
*led_cdev
,
109 enum led_brightness led_val
)
111 __fhc_set(led_cdev
, led_val
, FHC_CONTROL_RLED
);
114 typedef void (*set_handler
)(struct led_classdev
*, enum led_brightness
);
118 const char *default_trigger
;
121 #define NUM_LEDS_PER_BOARD 3
122 struct sunfire_drvdata
{
123 struct sunfire_led leds
[NUM_LEDS_PER_BOARD
];
126 static int __devinit
sunfire_led_generic_probe(struct platform_device
*pdev
,
127 struct led_type
*types
)
129 struct sunfire_drvdata
*p
;
130 int i
, err
= -EINVAL
;
132 if (pdev
->num_resources
!= 1) {
133 printk(KERN_ERR PFX
"Wrong number of resources %d, should be 1\n",
134 pdev
->num_resources
);
138 p
= kzalloc(sizeof(*p
), GFP_KERNEL
);
140 printk(KERN_ERR PFX
"Could not allocate struct sunfire_drvdata\n");
144 for (i
= 0; i
< NUM_LEDS_PER_BOARD
; i
++) {
145 struct led_classdev
*lp
= &p
->leds
[i
].led_cdev
;
147 p
->leds
[i
].reg
= (void __iomem
*) pdev
->resource
[0].start
;
148 lp
->name
= types
[i
].name
;
149 lp
->brightness
= LED_FULL
;
150 lp
->brightness_set
= types
[i
].handler
;
151 lp
->default_trigger
= types
[i
].default_trigger
;
153 err
= led_classdev_register(&pdev
->dev
, lp
);
155 printk(KERN_ERR PFX
"Could not register %s LED\n",
157 goto out_unregister_led_cdevs
;
161 dev_set_drvdata(&pdev
->dev
, p
);
167 out_unregister_led_cdevs
:
168 for (i
--; i
>= 0; i
--)
169 led_classdev_unregister(&p
->leds
[i
].led_cdev
);
173 static int __devexit
sunfire_led_generic_remove(struct platform_device
*pdev
)
175 struct sunfire_drvdata
*p
= dev_get_drvdata(&pdev
->dev
);
178 for (i
= 0; i
< NUM_LEDS_PER_BOARD
; i
++)
179 led_classdev_unregister(&p
->leds
[i
].led_cdev
);
186 static struct led_type clockboard_led_types
[NUM_LEDS_PER_BOARD
] = {
188 .name
= "clockboard-left",
189 .handler
= clockboard_left_set
,
192 .name
= "clockboard-middle",
193 .handler
= clockboard_middle_set
,
196 .name
= "clockboard-right",
197 .handler
= clockboard_right_set
,
198 .default_trigger
= "heartbeat",
202 static int __devinit
sunfire_clockboard_led_probe(struct platform_device
*pdev
)
204 return sunfire_led_generic_probe(pdev
, clockboard_led_types
);
207 static struct led_type fhc_led_types
[NUM_LEDS_PER_BOARD
] = {
210 .handler
= fhc_left_set
,
213 .name
= "fhc-middle",
214 .handler
= fhc_middle_set
,
218 .handler
= fhc_right_set
,
219 .default_trigger
= "heartbeat",
223 static int __devinit
sunfire_fhc_led_probe(struct platform_device
*pdev
)
225 return sunfire_led_generic_probe(pdev
, fhc_led_types
);
228 MODULE_ALIAS("platform:sunfire-clockboard-leds");
229 MODULE_ALIAS("platform:sunfire-fhc-leds");
231 static struct platform_driver sunfire_clockboard_led_driver
= {
232 .probe
= sunfire_clockboard_led_probe
,
233 .remove
= __devexit_p(sunfire_led_generic_remove
),
235 .name
= "sunfire-clockboard-leds",
236 .owner
= THIS_MODULE
,
240 static struct platform_driver sunfire_fhc_led_driver
= {
241 .probe
= sunfire_fhc_led_probe
,
242 .remove
= __devexit_p(sunfire_led_generic_remove
),
244 .name
= "sunfire-fhc-leds",
245 .owner
= THIS_MODULE
,
249 static int __init
sunfire_leds_init(void)
251 int err
= platform_driver_register(&sunfire_clockboard_led_driver
);
254 printk(KERN_ERR PFX
"Could not register clock board LED driver\n");
258 err
= platform_driver_register(&sunfire_fhc_led_driver
);
260 printk(KERN_ERR PFX
"Could not register FHC LED driver\n");
261 platform_driver_unregister(&sunfire_clockboard_led_driver
);
267 static void __exit
sunfire_leds_exit(void)
269 platform_driver_unregister(&sunfire_clockboard_led_driver
);
270 platform_driver_unregister(&sunfire_fhc_led_driver
);
273 module_init(sunfire_leds_init
);
274 module_exit(sunfire_leds_exit
);