197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa/*
297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  LEDs driver for the Cobalt Raq series.
397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *
4ada8e9514b5880f81cdbbd212d121380ceef7accYoichi Yuasa *  Copyright (C) 2007  Yoichi Yuasa <yuasa@linux-mips.org>
597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *
697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  This program is free software; you can redistribute it and/or modify
797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  it under the terms of the GNU General Public License as published by
897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  the Free Software Foundation; either version 2 of the License, or
997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  (at your option) any later version.
1097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *
1197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  This program is distributed in the hope that it will be useful,
1297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  GNU General Public License for more details.
1597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *
1697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  You should have received a copy of the GNU General Public License
1797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa *  along with this program; if not, write to the Free Software
184d404fd5c51772720e9c72aa3185bd5119bc6e69Németh Márton *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa */
2097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/init.h>
2197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/io.h>
2297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/ioport.h>
2397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/leds.h>
2497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/platform_device.h>
2597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/spinlock.h>
2697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#include <linux/types.h>
27d131c4962854b900ded69348acfd96007fcc893fPaul Gortmaker#include <linux/export.h>
2897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
2997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#define LED_WEB		0x04
3097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa#define LED_POWER_OFF	0x08
3197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
3297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic void __iomem *led_port;
3397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic u8 led_value;
3497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic DEFINE_SPINLOCK(led_value_lock);
3597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
3697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic void raq_web_led_set(struct led_classdev *led_cdev,
374d404fd5c51772720e9c72aa3185bd5119bc6e69Németh Márton			    enum led_brightness brightness)
3897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa{
3997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	unsigned long flags;
4097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
4197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	spin_lock_irqsave(&led_value_lock, flags);
4297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
4397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (brightness)
4497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		led_value |= LED_WEB;
4597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	else
4697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		led_value &= ~LED_WEB;
4797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	writeb(led_value, led_port);
4897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
4997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	spin_unlock_irqrestore(&led_value_lock, flags);
5097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa}
5197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
5297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic struct led_classdev raq_web_led = {
53db3f520738a8c5bf593e13d4ac71f8da9ffcb964Olaf Hering	.name		= "raq::web",
5497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.brightness_set	= raq_web_led_set,
5597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa};
5697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
5797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic void raq_power_off_led_set(struct led_classdev *led_cdev,
584d404fd5c51772720e9c72aa3185bd5119bc6e69Németh Márton				  enum led_brightness brightness)
5997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa{
6097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	unsigned long flags;
6197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
6297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	spin_lock_irqsave(&led_value_lock, flags);
6397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
6497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (brightness)
6597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		led_value |= LED_POWER_OFF;
6697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	else
6797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		led_value &= ~LED_POWER_OFF;
6897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	writeb(led_value, led_port);
6997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
7097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	spin_unlock_irqrestore(&led_value_lock, flags);
7197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa}
7297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
7397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic struct led_classdev raq_power_off_led = {
74db3f520738a8c5bf593e13d4ac71f8da9ffcb964Olaf Hering	.name			= "raq::power-off",
7597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.brightness_set		= raq_power_off_led_set,
7697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.default_trigger	= "power-off",
7797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa};
7897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
7997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
8097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa{
8197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	struct resource *res;
8297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	int retval;
8397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
8497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (!res)
8697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		return -EBUSY;
8797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
88d3aad6399a240300534d83ffdacfc40e6ed4fa73H Hartley Sweeten	led_port = ioremap(res->start, resource_size(res));
8997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (!led_port)
9097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		return -ENOMEM;
9197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
9297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	retval = led_classdev_register(&pdev->dev, &raq_power_off_led);
9397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (retval)
9497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		goto err_iounmap;
9597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
9697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	retval = led_classdev_register(&pdev->dev, &raq_web_led);
9797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (retval)
9897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		goto err_unregister;
9997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
10097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	return 0;
10197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
10297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasaerr_unregister:
10397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	led_classdev_unregister(&raq_power_off_led);
10497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
10597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasaerr_iounmap:
10697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	iounmap(led_port);
10797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	led_port = NULL;
10897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
10997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	return retval;
11097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa}
11197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
11297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic int __devexit cobalt_raq_led_remove(struct platform_device *pdev)
11397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa{
11497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	led_classdev_unregister(&raq_power_off_led);
11597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	led_classdev_unregister(&raq_web_led);
11697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
11797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	if (led_port) {
11897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		iounmap(led_port);
11997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		led_port = NULL;
12097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	}
12197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
12297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	return 0;
12397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa}
12497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
12597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic struct platform_driver cobalt_raq_led_driver = {
12697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.probe	= cobalt_raq_led_probe,
12797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.remove	= __devexit_p(cobalt_raq_led_remove),
12897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	.driver = {
12997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		.name	= "cobalt-raq-leds",
13097da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa		.owner	= THIS_MODULE,
13197da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	},
13297da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa};
13397da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
13497da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasastatic int __init cobalt_raq_led_init(void)
13597da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa{
13697da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa	return platform_driver_register(&cobalt_raq_led_driver);
13797da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa}
13897da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasa
13997da7aaf46fedcf1a38a88e5ffc2c40df23e8013Yoichi Yuasamodule_init(cobalt_raq_led_init);
140