1/*
2 * LEDs driver for PCEngines WRAP
3 *
4 * Copyright (C) 2006 Kristian Kielhofner <kris@krisk.org>
5 *
6 * Based on leds-net48xx.c
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/platform_device.h>
16#include <linux/leds.h>
17#include <linux/err.h>
18#include <asm/io.h>
19#include <linux/scx200_gpio.h>
20
21#define DRVNAME "wrap-led"
22#define WRAP_ERROR_LED_GPIO	3
23#define	WRAP_EXTRA_LED_GPIO	18
24
25static struct platform_device *pdev;
26
27static void wrap_error_led_set(struct led_classdev *led_cdev,
28		enum led_brightness value)
29{
30	if (value)
31		scx200_gpio_set_low(WRAP_ERROR_LED_GPIO);
32	else
33		scx200_gpio_set_high(WRAP_ERROR_LED_GPIO);
34}
35
36static void wrap_extra_led_set(struct led_classdev *led_cdev,
37		enum led_brightness value)
38{
39	if (value)
40		scx200_gpio_set_low(WRAP_EXTRA_LED_GPIO);
41	else
42		scx200_gpio_set_high(WRAP_EXTRA_LED_GPIO);
43}
44
45static struct led_classdev wrap_error_led = {
46	.name		= "wrap:error",
47	.brightness_set	= wrap_error_led_set,
48};
49
50static struct led_classdev wrap_extra_led = {
51	.name           = "wrap:extra",
52	.brightness_set = wrap_extra_led_set,
53};
54
55#ifdef CONFIG_PM
56static int wrap_led_suspend(struct platform_device *dev,
57		pm_message_t state)
58{
59	led_classdev_suspend(&wrap_error_led);
60	led_classdev_suspend(&wrap_extra_led);
61	return 0;
62}
63
64static int wrap_led_resume(struct platform_device *dev)
65{
66	led_classdev_resume(&wrap_error_led);
67	led_classdev_resume(&wrap_extra_led);
68	return 0;
69}
70#else
71#define wrap_led_suspend NULL
72#define wrap_led_resume NULL
73#endif
74
75static int wrap_led_probe(struct platform_device *pdev)
76{
77	int ret;
78
79	ret = led_classdev_register(&pdev->dev, &wrap_error_led);
80	if (ret == 0) {
81		ret = led_classdev_register(&pdev->dev, &wrap_extra_led);
82		if (ret < 0)
83			led_classdev_unregister(&wrap_error_led);
84	}
85	return ret;
86}
87
88static int wrap_led_remove(struct platform_device *pdev)
89{
90	led_classdev_unregister(&wrap_error_led);
91	led_classdev_unregister(&wrap_extra_led);
92	return 0;
93}
94
95static struct platform_driver wrap_led_driver = {
96	.probe		= wrap_led_probe,
97	.remove		= wrap_led_remove,
98	.suspend	= wrap_led_suspend,
99	.resume		= wrap_led_resume,
100	.driver		= {
101		.name		= DRVNAME,
102		.owner		= THIS_MODULE,
103	},
104};
105
106static int __init wrap_led_init(void)
107{
108	int ret;
109
110	if (!scx200_gpio_present()) {
111		ret = -ENODEV;
112		goto out;
113	}
114
115	ret = platform_driver_register(&wrap_led_driver);
116	if (ret < 0)
117		goto out;
118
119	pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
120	if (IS_ERR(pdev)) {
121		ret = PTR_ERR(pdev);
122		platform_driver_unregister(&wrap_led_driver);
123		goto out;
124	}
125
126out:
127	return ret;
128}
129
130static void __exit wrap_led_exit(void)
131{
132	platform_device_unregister(pdev);
133	platform_driver_unregister(&wrap_led_driver);
134}
135
136module_init(wrap_led_init);
137module_exit(wrap_led_exit);
138
139MODULE_AUTHOR("Kristian Kielhofner <kris@krisk.org>");
140MODULE_DESCRIPTION("PCEngines WRAP LED driver");
141MODULE_LICENSE("GPL");
142