linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver
@ 2010-05-23 13:57 Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 1/9] MIPS: add subdirectory for platform extension drivers Wu Zhangjin
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:57 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

This patchset adds the platform specific driver for the YeeLoong netbook made
by Lemote.

Changes from v11:
  o Fixup of the brightness driver (from Zhou Yajin)
    use the right arguments for the backlight_device_register()

Wu Zhangjin (9):
  MIPS: add subdirectory for platform extension drivers
  Loongson: YeeLoong: add platform driver
  Loongson: YeeLoong: add backlight driver
  Loongson: YeeLoong: add hardware monitoring driver
  Loongson: YeeLoong: add video output driver
  Loongson: YeeLoong: add suspend support
  Loongson: YeeLoong: add input/hotkey driver
  Loongson: YeeLoong: add power_supply based battery driver
  Loongson: YeeLoong: Co-operate with the revisions of EC

 arch/mips/include/asm/mach-loongson/ec_kb3310b.h |  190 ++++
 arch/mips/include/asm/mach-loongson/loongson.h   |    6 +
 arch/mips/loongson/common/cmdline.c              |    8 +
 arch/mips/loongson/lemote-2f/Makefile            |    2 +-
 arch/mips/loongson/lemote-2f/ec_kb3310b.c        |   12 +-
 arch/mips/loongson/lemote-2f/ec_kb3310b.h        |  188 ----
 arch/mips/loongson/lemote-2f/platform.c          |   39 +
 arch/mips/loongson/lemote-2f/pm.c                |    4 +-
 arch/mips/loongson/lemote-2f/reset.c             |    2 +-
 drivers/platform/Kconfig                         |    4 +
 drivers/platform/Makefile                        |    1 +
 drivers/platform/mips/Kconfig                    |   32 +
 drivers/platform/mips/Makefile                   |    5 +
 drivers/platform/mips/yeeloong_laptop.c          | 1200 ++++++++++++++++++++++
 14 files changed, 1493 insertions(+), 200 deletions(-)
 create mode 100644 arch/mips/include/asm/mach-loongson/ec_kb3310b.h
 delete mode 100644 arch/mips/loongson/lemote-2f/ec_kb3310b.h
 create mode 100644 arch/mips/loongson/lemote-2f/platform.c
 create mode 100644 drivers/platform/mips/Kconfig
 create mode 100644 drivers/platform/mips/Makefile
 create mode 100644 drivers/platform/mips/yeeloong_laptop.c

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] MIPS: add subdirectory for platform extension drivers
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
@ 2010-05-23 13:57 ` Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 3/9] Loongson: YeeLoong: add backlight driver Wu Zhangjin
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:57 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

It is really hard to split the platform specific subdrivers into
different subsystems, which will generate lots of duplicated source
code, break the whole support into several pieces and also will make the
users be difficult to choose the suitable subdrivers in different
places.

So, I did like the forks have done under drivers/platform/x86, created
the drivers/platform/mips/ for putting the future MIPS netbook/laptop/pc
extension drivers in.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/Kconfig      |    4 ++++
 drivers/platform/mips/Kconfig |   18 ++++++++++++++++++
 2 files changed, 22 insertions(+), 0 deletions(-)
 create mode 100644 drivers/platform/mips/Kconfig

diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 8390dca..4fa78d5 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -1,3 +1,7 @@
 if X86
 source "drivers/platform/x86/Kconfig"
 endif
+
+if MIPS
+source "drivers/platform/mips/Kconfig"
+endif
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
new file mode 100644
index 0000000..2f77693
--- /dev/null
+++ b/drivers/platform/mips/Kconfig
@@ -0,0 +1,18 @@
+#
+# MIPS Platform Specific Drivers
+#
+
+menuconfig MIPS_PLATFORM_DEVICES
+	bool "MIPS Platform Specific Device Drivers"
+	default y
+	help
+	  Say Y here to get to see options for device drivers of various
+	  MIPS platforms, including vendor-specific netbook/laptop/pc extension
+	  drivers.  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+if MIPS_PLATFORM_DEVICES
+
+
+endif # MIPS_PLATFORM_DEVICES
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/9] Loongson: YeeLoong: add backlight driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 1/9] MIPS: add subdirectory for platform extension drivers Wu Zhangjin
@ 2010-05-23 13:57 ` Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 4/9] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:57 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin, Zhou Yajin

This patch adds YeeLoong Backlight Driver, it provides standard
interface(/sys/class/backlight/) for user-space applications(e.g.
kpowersave, gnome-power-manager) to control the brightness of the
backlight.

Signed-off-by: Zhou Yajin <yajinzhou@vm-kernel.org>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/Kconfig           |    1 +
 drivers/platform/mips/yeeloong_laptop.c |   83 +++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 5ac5215..c1ba03d 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -17,6 +17,7 @@ if MIPS_PLATFORM_DEVICES
 config LEMOTE_YEELOONG2F
 	tristate "Lemote YeeLoong Laptop"
 	depends on LEMOTE_MACH2F
+	select BACKLIGHT_CLASS_DEVICE
 	help
 	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
 	  compatible to FuLoong2F mini PC, but it has an extra Embedded
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 09f606c..0ec8c03 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -10,6 +10,81 @@
 
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/backlight.h>	/* for backlight subdriver */
+#include <linux/fb.h>
+
+#include <ec_kb3310b.h>
+
+/* backlight subdriver */
+#define MAX_BRIGHTNESS	8
+
+static int yeeloong_set_brightness(struct backlight_device *bd)
+{
+	unsigned int level, current_level;
+	static unsigned int old_level;
+
+	level = (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+		 bd->props.power == FB_BLANK_UNBLANK) ?
+	    bd->props.brightness : 0;
+
+	if (level > MAX_BRIGHTNESS)
+		level = MAX_BRIGHTNESS;
+	else if (level < 0)
+		level = 0;
+
+	/* Avoid to modify the brightness when EC is tuning it */
+	if (old_level != level) {
+		current_level = ec_read(REG_DISPLAY_BRIGHTNESS);
+		if (old_level == current_level)
+			ec_write(REG_DISPLAY_BRIGHTNESS, level);
+		old_level = level;
+	}
+
+	return 0;
+}
+
+static int yeeloong_get_brightness(struct backlight_device *bd)
+{
+	return ec_read(REG_DISPLAY_BRIGHTNESS);
+}
+
+static const struct backlight_ops backlight_ops = {
+	.get_brightness = yeeloong_get_brightness,
+	.update_status = yeeloong_set_brightness,
+};
+
+static struct backlight_device *yeeloong_backlight_dev;
+
+static int yeeloong_backlight_init(void)
+{
+	int ret;
+	struct backlight_properties props;
+
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = MAX_BRIGHTNESS;
+	yeeloong_backlight_dev = backlight_device_register("backlight0", NULL,
+			NULL, &backlight_ops, &props);
+
+	if (IS_ERR(yeeloong_backlight_dev)) {
+		ret = PTR_ERR(yeeloong_backlight_dev);
+		yeeloong_backlight_dev = NULL;
+		return ret;
+	}
+
+	yeeloong_backlight_dev->props.brightness =
+		yeeloong_get_brightness(yeeloong_backlight_dev);
+	backlight_update_status(yeeloong_backlight_dev);
+
+	return 0;
+}
+
+static void yeeloong_backlight_exit(void)
+{
+	if (yeeloong_backlight_dev) {
+		backlight_device_unregister(yeeloong_backlight_dev);
+		yeeloong_backlight_dev = NULL;
+	}
+}
 
 static struct platform_device_id platform_device_ids[] = {
 	{
@@ -41,11 +116,19 @@ static int __init yeeloong_init(void)
 		return ret;
 	}
 
+	ret = yeeloong_backlight_init();
+	if (ret) {
+		pr_err("Fail to register yeeloong backlight driver.\n");
+		yeeloong_backlight_exit();
+		return ret;
+	}
+
 	return 0;
 }
 
 static void __exit yeeloong_exit(void)
 {
+	yeeloong_backlight_exit();
 	platform_driver_unregister(&platform_driver);
 
 	pr_info("Unload YeeLoong Platform Specific Driver.\n");
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/9] Loongson: YeeLoong: add hardware monitoring driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 1/9] MIPS: add subdirectory for platform extension drivers Wu Zhangjin
  2010-05-23 13:57 ` [PATCH 3/9] Loongson: YeeLoong: add backlight driver Wu Zhangjin
@ 2010-05-23 13:57 ` Wu Zhangjin
  2010-05-23 13:58 ` [PATCH 5/9] Loongson: YeeLoong: add video output driver Wu Zhangjin
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:57 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

Changes from v11 5/8:

	o add a get_bat_info() macro to cleanup the battery related
	operation.

Changes from v10 5/8:

	o ensure the whole fan related source code follow the hwmon
	interfaces.

Changes from v9 5/8:

	o ensure the fan controlling interface is compatible with the
	one described in Documentation/hwmon/sysfs-interface

----------------

This patch adds hardware monitoring driver, it provides standard
interface(/sys/class/hwmon/) for lm-sensors/sensors-applet to monitor
the temperatures of CPU and battery, the PWM of fan, the current,
voltage of battery.

Please refer to Documentation/hwmon/userspace-tools and
Documentation/hwmon/sysfs-interface to get more information about the
hwmon.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/Kconfig           |    1 +
 drivers/platform/mips/yeeloong_laptop.c |  253 ++++++++++++++++++++++++++++++-
 2 files changed, 250 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index c1ba03d..d4ce744 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -18,6 +18,7 @@ config LEMOTE_YEELOONG2F
 	tristate "Lemote YeeLoong Laptop"
 	depends on LEMOTE_MACH2F
 	select BACKLIGHT_CLASS_DEVICE
+	select HWMON
 	help
 	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
 	  compatible to FuLoong2F mini PC, but it has an extra Embedded
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 0ec8c03..a422acb 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -12,6 +12,8 @@
 #include <linux/platform_device.h>
 #include <linux/backlight.h>	/* for backlight subdriver */
 #include <linux/fb.h>
+#include <linux/hwmon.h>	/* for hwmon subdriver */
+#include <linux/hwmon-sysfs.h>
 
 #include <ec_kb3310b.h>
 
@@ -27,10 +29,7 @@ static int yeeloong_set_brightness(struct backlight_device *bd)
 		 bd->props.power == FB_BLANK_UNBLANK) ?
 	    bd->props.brightness : 0;
 
-	if (level > MAX_BRIGHTNESS)
-		level = MAX_BRIGHTNESS;
-	else if (level < 0)
-		level = 0;
+	level = SENSORS_LIMIT(level, 0, MAX_BRIGHTNESS);
 
 	/* Avoid to modify the brightness when EC is tuning it */
 	if (old_level != level) {
@@ -86,6 +85,244 @@ static void yeeloong_backlight_exit(void)
 	}
 }
 
+/* hwmon subdriver */
+
+#define MIN_FAN_SPEED 0
+#define MAX_FAN_SPEED 3
+
+static int get_fan_pwm_enable(void)
+{
+	int level, mode;
+
+	level = ec_read(REG_FAN_SPEED_LEVEL);
+	mode = ec_read(REG_FAN_AUTO_MAN_SWITCH);
+
+	if (level == MAX_FAN_SPEED && mode == BIT_FAN_MANUAL)
+		mode = 0;
+	else if (mode == BIT_FAN_MANUAL)
+		mode = 1;
+	else
+		mode = 2;
+
+	return mode;
+}
+
+static void set_fan_pwm_enable(int mode)
+{
+	switch (mode) {
+	case 0:
+		/* fullspeed */
+		ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL);
+		ec_write(REG_FAN_SPEED_LEVEL, MAX_FAN_SPEED);
+		break;
+	case 1:
+		ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_MANUAL);
+		break;
+	case 2:
+		ec_write(REG_FAN_AUTO_MAN_SWITCH, BIT_FAN_AUTO);
+		break;
+	default:
+		break;
+	}
+}
+
+static int get_fan_pwm(void)
+{
+	return ec_read(REG_FAN_SPEED_LEVEL);
+}
+
+static void set_fan_pwm(int value)
+{
+	int mode;
+
+	mode = ec_read(REG_FAN_AUTO_MAN_SWITCH);
+	if (mode != BIT_FAN_MANUAL)
+		return;
+
+	value = SENSORS_LIMIT(value, 0, 3);
+
+	/* We must ensure the fan is on */
+	if (value > 0)
+		ec_write(REG_FAN_CONTROL, BIT_FAN_CONTROL_ON);
+
+	ec_write(REG_FAN_SPEED_LEVEL, value);
+}
+
+static int get_fan_rpm(void)
+{
+	int value;
+
+	value = FAN_SPEED_DIVIDER /
+	    (((ec_read(REG_FAN_SPEED_HIGH) & 0x0f) << 8) |
+	     ec_read(REG_FAN_SPEED_LOW));
+
+	return value;
+}
+
+static int get_cpu_temp(void)
+{
+	s8 value;
+
+	value = ec_read(REG_TEMPERATURE_VALUE);
+
+	return value * 1000;
+}
+
+static int get_cpu_temp_max(void)
+{
+	return 60 * 1000;
+}
+
+#define get_bat_info(type) \
+	((ec_read(REG_BAT_##type##_HIGH) << 8) | \
+	 (ec_read(REG_BAT_##type##_LOW)))
+
+static int get_battery_temp(void)
+{
+	int value;
+
+	value = get_bat_info(TEMPERATURE);
+
+	return value * 1000;
+}
+
+static int get_battery_temp_alarm(void)
+{
+	int status;
+
+	status = (ec_read(REG_BAT_CHARGE_STATUS) &
+			BIT_BAT_CHARGE_STATUS_OVERTEMP);
+
+	return !!status;
+}
+
+static int get_battery_current(void)
+{
+	s16 value;
+
+	value = get_bat_info(CURRENT);
+
+	return -value;
+}
+
+static int get_battery_voltage(void)
+{
+	int value;
+
+	value = get_bat_info(VOLTAGE);
+
+	return value;
+}
+
+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count)
+{
+	int ret;
+	unsigned long value;
+
+	if (!count)
+		return 0;
+
+	ret = strict_strtoul(buf, 10, &value);
+	if (ret)
+		return ret;
+
+	set(value);
+
+	return count;
+}
+
+static ssize_t show_sys_hwmon(int (*get) (void), char *buf)
+{
+	return sprintf(buf, "%d\n", get());
+}
+
+#define CREATE_SENSOR_ATTR(_name, _mode, _set, _get)		\
+	static ssize_t show_##_name(struct device *dev,			\
+				    struct device_attribute *attr,	\
+				    char *buf)				\
+	{								\
+		return show_sys_hwmon(_set, buf);			\
+	}								\
+	static ssize_t store_##_name(struct device *dev,		\
+				     struct device_attribute *attr,	\
+				     const char *buf, size_t count)	\
+	{								\
+		return store_sys_hwmon(_get, buf, count);		\
+	}								\
+	static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+
+CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
+CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR, get_fan_pwm, set_fan_pwm);
+CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, get_fan_pwm_enable,
+		set_fan_pwm_enable);
+CREATE_SENSOR_ATTR(temp1_input, S_IRUGO, get_cpu_temp, NULL);
+CREATE_SENSOR_ATTR(temp1_max, S_IRUGO, get_cpu_temp_max, NULL);
+CREATE_SENSOR_ATTR(temp2_input, S_IRUGO, get_battery_temp, NULL);
+CREATE_SENSOR_ATTR(temp2_max_alarm, S_IRUGO, get_battery_temp_alarm, NULL);
+CREATE_SENSOR_ATTR(curr1_input, S_IRUGO, get_battery_current, NULL);
+CREATE_SENSOR_ATTR(in1_input, S_IRUGO, get_battery_voltage, NULL);
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "yeeloong\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_name.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group hwmon_attribute_group = {
+	.attrs = hwmon_attributes
+};
+
+static struct device *yeeloong_hwmon_dev;
+
+static int yeeloong_hwmon_init(void)
+{
+	int ret;
+
+	yeeloong_hwmon_dev = hwmon_device_register(NULL);
+	if (IS_ERR(yeeloong_hwmon_dev)) {
+		pr_err("Fail to register yeeloong hwmon device\n");
+		yeeloong_hwmon_dev = NULL;
+		return PTR_ERR(yeeloong_hwmon_dev);
+	}
+	ret = sysfs_create_group(&yeeloong_hwmon_dev->kobj,
+				 &hwmon_attribute_group);
+	if (ret) {
+		hwmon_device_unregister(yeeloong_hwmon_dev);
+		yeeloong_hwmon_dev = NULL;
+		return ret;
+	}
+	/* ensure fan is set to auto mode */
+	set_fan_pwm_enable(2);
+
+	return 0;
+}
+
+static void yeeloong_hwmon_exit(void)
+{
+	if (yeeloong_hwmon_dev) {
+		sysfs_remove_group(&yeeloong_hwmon_dev->kobj,
+				   &hwmon_attribute_group);
+		hwmon_device_unregister(yeeloong_hwmon_dev);
+		yeeloong_hwmon_dev = NULL;
+	}
+}
+
 static struct platform_device_id platform_device_ids[] = {
 	{
 		.name = "yeeloong_laptop",
@@ -123,11 +360,19 @@ static int __init yeeloong_init(void)
 		return ret;
 	}
 
+	ret = yeeloong_hwmon_init();
+	if (ret) {
+		pr_err("Fail to register yeeloong hwmon driver.\n");
+		yeeloong_hwmon_exit();
+		return ret;
+	}
+
 	return 0;
 }
 
 static void __exit yeeloong_exit(void)
 {
+	yeeloong_hwmon_exit();
 	yeeloong_backlight_exit();
 	platform_driver_unregister(&platform_driver);
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/9] Loongson: YeeLoong: add video output driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (2 preceding siblings ...)
  2010-05-23 13:57 ` [PATCH 4/9] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
@ 2010-05-23 13:58 ` Wu Zhangjin
  2010-05-23 13:58 ` [PATCH 6/9] Loongson: YeeLoong: add suspend support Wu Zhangjin
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:58 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

This patch adds Video Output Driver, it provides standard
interface(/sys/class/video_output) to turn on/off the video output of
LCD, CRT.

Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/Kconfig           |    1 +
 drivers/platform/mips/yeeloong_laptop.c |  139 +++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index d4ce744..e1285f7 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -19,6 +19,7 @@ config LEMOTE_YEELOONG2F
 	depends on LEMOTE_MACH2F
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
+	select VIDEO_OUTPUT_CONTROL
 	help
 	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
 	  compatible to FuLoong2F mini PC, but it has an extra Embedded
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index a422acb..9fd70ae 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -14,6 +14,7 @@
 #include <linux/fb.h>
 #include <linux/hwmon.h>	/* for hwmon subdriver */
 #include <linux/hwmon-sysfs.h>
+#include <linux/video_output.h>	/* for video output subdriver */
 
 #include <ec_kb3310b.h>
 
@@ -323,6 +324,136 @@ static void yeeloong_hwmon_exit(void)
 	}
 }
 
+/* video output subdriver */
+
+static int lcd_video_output_get(struct output_device *od)
+{
+	return ec_read(REG_DISPLAY_LCD);
+}
+
+#define LCD	0
+#define CRT	1
+
+static void display_vo_set(int display, int on)
+{
+	int addr;
+	unsigned long value;
+
+	addr = (display == LCD) ? 0x31 : 0x21;
+
+	outb(addr, 0x3c4);
+	value = inb(0x3c5);
+
+	if (display == LCD)
+		value |= (on ? 0x03 : 0x02);
+	else {
+		if (on)
+			clear_bit(7, &value);
+		else
+			set_bit(7, &value);
+	}
+
+	outb(addr, 0x3c4);
+	outb(value, 0x3c5);
+}
+
+static int lcd_video_output_set(struct output_device *od)
+{
+	unsigned long status;
+
+	status = !!od->request_state;
+
+	display_vo_set(LCD, status);
+	ec_write(REG_BACKLIGHT_CTRL, status);
+
+	return 0;
+}
+
+static struct output_properties lcd_output_properties = {
+	.set_state = lcd_video_output_set,
+	.get_status = lcd_video_output_get,
+};
+
+static int crt_video_output_get(struct output_device *od)
+{
+	return ec_read(REG_CRT_DETECT);
+}
+
+static int crt_video_output_set(struct output_device *od)
+{
+	unsigned long status;
+
+	status = !!od->request_state;
+
+	if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG)
+		display_vo_set(CRT, status);
+
+	return 0;
+}
+
+static struct output_properties crt_output_properties = {
+	.set_state = crt_video_output_set,
+	.get_status = crt_video_output_get,
+};
+
+static struct output_device *lcd_output_dev, *crt_output_dev;
+
+static void yeeloong_lcd_vo_set(int status)
+{
+	lcd_output_dev->request_state = status;
+	lcd_video_output_set(lcd_output_dev);
+}
+
+static void yeeloong_crt_vo_set(int status)
+{
+	crt_output_dev->request_state = status;
+	crt_video_output_set(crt_output_dev);
+}
+
+static int yeeloong_vo_init(void)
+{
+	int ret;
+
+	/* Register video output device: lcd, crt */
+	lcd_output_dev = video_output_register("LCD", NULL, NULL,
+			&lcd_output_properties);
+
+	if (IS_ERR(lcd_output_dev)) {
+		ret = PTR_ERR(lcd_output_dev);
+		lcd_output_dev = NULL;
+		return ret;
+	}
+	/* Ensure LCD is on by default */
+	yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+
+	crt_output_dev = video_output_register("CRT", NULL, NULL,
+			&crt_output_properties);
+
+	if (IS_ERR(crt_output_dev)) {
+		ret = PTR_ERR(crt_output_dev);
+		crt_output_dev = NULL;
+		return ret;
+	}
+
+	/* Turn off CRT by default, and will be enabled when the CRT
+	 * connectting event reported by SCI */
+	yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+
+	return 0;
+}
+
+static void yeeloong_vo_exit(void)
+{
+	if (lcd_output_dev) {
+		video_output_unregister(lcd_output_dev);
+		lcd_output_dev = NULL;
+	}
+	if (crt_output_dev) {
+		video_output_unregister(crt_output_dev);
+		crt_output_dev = NULL;
+	}
+}
+
 static struct platform_device_id platform_device_ids[] = {
 	{
 		.name = "yeeloong_laptop",
@@ -367,11 +498,19 @@ static int __init yeeloong_init(void)
 		return ret;
 	}
 
+	ret = yeeloong_vo_init();
+	if (ret) {
+		pr_err("Fail to register yeeloong video output driver.\n");
+		yeeloong_vo_exit();
+		return ret;
+	}
+
 	return 0;
 }
 
 static void __exit yeeloong_exit(void)
 {
+	yeeloong_vo_exit();
 	yeeloong_hwmon_exit();
 	yeeloong_backlight_exit();
 	platform_driver_unregister(&platform_driver);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/9] Loongson: YeeLoong: add suspend support
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (3 preceding siblings ...)
  2010-05-23 13:58 ` [PATCH 5/9] Loongson: YeeLoong: add video output driver Wu Zhangjin
@ 2010-05-23 13:58 ` Wu Zhangjin
  2010-05-23 13:58 ` [PATCH 7/9] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:58 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

This patch add support to suspend the yeeloong platform specific
devices(LCD, CRT, USB...).

Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/yeeloong_laptop.c |   41 ++++++++++++++++++++++++++++--
 1 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 9fd70ae..16e34e8 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -454,6 +454,38 @@ static void yeeloong_vo_exit(void)
 	}
 }
 
+#ifdef CONFIG_PM
+static void usb_ports_set(int status)
+{
+	status = !!status;
+
+	ec_write(REG_USB0_FLAG, status);
+	ec_write(REG_USB1_FLAG, status);
+	ec_write(REG_USB2_FLAG, status);
+}
+
+static int yeeloong_suspend(struct device *dev)
+{
+	yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+	yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+	usb_ports_set(BIT_USB_FLAG_OFF);
+
+	return 0;
+}
+
+static int yeeloong_resume(struct device *dev)
+{
+	usb_ports_set(BIT_USB_FLAG_ON);
+	yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
+	yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+
+	return 0;
+}
+
+static const SIMPLE_DEV_PM_OPS(yeeloong_pm_ops, yeeloong_suspend,
+	yeeloong_resume);
+#endif
+
 static struct platform_device_id platform_device_ids[] = {
 	{
 		.name = "yeeloong_laptop",
@@ -465,9 +497,12 @@ MODULE_DEVICE_TABLE(platform, platform_device_ids);
 
 static struct platform_driver platform_driver = {
 	.driver = {
-		   .name = "yeeloong_laptop",
-		   .owner = THIS_MODULE,
-		   },
+		.name = "yeeloong_laptop",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &yeeloong_pm_ops,
+#endif
+	},
 	.id_table = platform_device_ids,
 };
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/9] Loongson: YeeLoong: add input/hotkey driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (4 preceding siblings ...)
  2010-05-23 13:58 ` [PATCH 6/9] Loongson: YeeLoong: add suspend support Wu Zhangjin
@ 2010-05-23 13:58 ` Wu Zhangjin
  2010-05-23 13:58 ` [PATCH 8/9] Loongson: YeeLoong: add power_supply based battery driver Wu Zhangjin
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:58 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

Changes from v10 8/8:

  o Split the EC related code out into the next patch.

Changes from v9 8/8:

  o Remove the wifi related actions

  With the standard rfkill support(/sys/class/rfkill/) in the wifi
  driver, there is no need to handle the wifi related actions except
  reporting the KEY_WLAN event to user-space. the related applications
  will response this event and do corresponding actions(access the
  rfkill interfaces).

------------------

This patch adds Hotkey Driver, which will do related actions for The
hotkey event(/sys/class/input) and report the corresponding input keys
to the user-space applications.

(This patch is based on the sparse keymap library in:

git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input next

of Dmitry Torokhov. that sparse keymap support is also queued for
2.6.33. Before the above branch is pulled by linus, this patch is not
appliable.)

Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/Kconfig           |    2 +
 drivers/platform/mips/yeeloong_laptop.c |  385 +++++++++++++++++++++++++++++++
 2 files changed, 387 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index e1285f7..01560b0 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -20,6 +20,8 @@ config LEMOTE_YEELOONG2F
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
 	select VIDEO_OUTPUT_CONTROL
+	select INPUT_SPARSEKMAP
+	depends on INPUT
 	help
 	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
 	  compatible to FuLoong2F mini PC, but it has an extra Embedded
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 16e34e8..817e8fc 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -15,6 +15,12 @@
 #include <linux/hwmon.h>	/* for hwmon subdriver */
 #include <linux/hwmon-sysfs.h>
 #include <linux/video_output.h>	/* for video output subdriver */
+#include <linux/input.h>	/* for hotkey subdriver */
+#include <linux/input/sparse-keymap.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <cs5536/cs5536.h>
 
 #include <ec_kb3310b.h>
 
@@ -454,6 +460,377 @@ static void yeeloong_vo_exit(void)
 	}
 }
 
+/* hotkey subdriver */
+
+static struct input_dev *yeeloong_hotkey_dev;
+
+static const struct key_entry yeeloong_keymap[] = {
+	{KE_SW, EVENT_LID, { SW_LID } },
+	{KE_KEY, EVENT_CAMERA, { KEY_CAMERA } }, /* Fn + ESC */
+	{KE_KEY, EVENT_SLEEP, { KEY_SLEEP } }, /* Fn + F1 */
+	{KE_KEY, EVENT_DISPLAYTOGGLE, { KEY_DISPLAYTOGGLE } }, /* Fn + F2 */
+	{KE_KEY, EVENT_SWITCHVIDEOMODE, { KEY_SWITCHVIDEOMODE } }, /* Fn + F3 */
+	{KE_KEY, EVENT_AUDIO_MUTE, { KEY_MUTE } }, /* Fn + F4 */
+	{KE_KEY, EVENT_WLAN, { KEY_WLAN } }, /* Fn + F5 */
+	{KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSUP } }, /* Fn + up */
+	{KE_KEY, EVENT_DISPLAY_BRIGHTNESS, { KEY_BRIGHTNESSDOWN } }, /* Fn + down */
+	{KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEUP } }, /* Fn + right */
+	{KE_KEY, EVENT_AUDIO_VOLUME, { KEY_VOLUMEDOWN } }, /* Fn + left */
+	{KE_END, 0}
+};
+
+static struct key_entry *get_event_key_entry(int event, int status)
+{
+	struct key_entry *ke;
+	static int old_brightness_status = -1;
+	static int old_volume_status = -1;
+
+	ke = sparse_keymap_entry_from_scancode(yeeloong_hotkey_dev, event);
+	if (!ke)
+		return NULL;
+
+	switch (event) {
+	case EVENT_DISPLAY_BRIGHTNESS:
+		/* current status > old one, means up */
+		if ((status < old_brightness_status) || (0 == status))
+			ke++;
+		old_brightness_status = status;
+		break;
+	case EVENT_AUDIO_VOLUME:
+		if ((status < old_volume_status) || (0 == status))
+			ke++;
+		old_volume_status = status;
+		break;
+	default:
+		break;
+	}
+
+	return ke;
+}
+
+static int report_lid_switch(int status)
+{
+	input_report_switch(yeeloong_hotkey_dev, SW_LID, !status);
+	input_sync(yeeloong_hotkey_dev);
+
+	return status;
+}
+
+static int crt_detect_handler(int status)
+{
+	if (status) {
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+	} else {
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+	}
+	return status;
+}
+
+static int displaytoggle_handler(int status)
+{
+	yeeloong_lcd_vo_set(status);
+
+	return status;
+}
+
+static int switchvideomode_handler(int status)
+{
+	static int video_output_status;
+
+	/* Only enable switch video output button
+	 * when CRT is connected */
+	if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_UNPLUG)
+		return 0;
+	/* 0. no CRT connected: LCD on, CRT off
+	 * 1. BOTH on
+	 * 2. LCD off, CRT on
+	 * 3. BOTH off
+	 * 4. LCD on, CRT off
+	 */
+	video_output_status++;
+	if (video_output_status > 4)
+		video_output_status = 1;
+
+	switch (video_output_status) {
+	case 1:
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
+		break;
+	case 2:
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
+		break;
+	case 3:
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+		break;
+	case 4:
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+		yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+		break;
+	default:
+		/* Ensure LCD is on */
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+		break;
+	}
+	return video_output_status;
+}
+
+static int camera_handler(int status)
+{
+	int value;
+
+	value = ec_read(REG_CAMERA_CONTROL);
+	ec_write(REG_CAMERA_CONTROL, value | (1 << 1));
+
+	return status;
+}
+
+static int usb2_handler(int status)
+{
+	pr_emerg("USB2 Over Current occurred\n");
+
+	return status;
+}
+
+static int usb0_handler(int status)
+{
+	pr_emerg("USB0 Over Current occurred\n");
+
+	return status;
+}
+
+static void do_event_action(int event)
+{
+	sci_handler handler;
+	int reg, status;
+	struct key_entry *ke;
+
+	reg = 0;
+	handler = NULL;
+
+	switch (event) {
+	case EVENT_LID:
+		reg = REG_LID_DETECT;
+		break;
+	case EVENT_SWITCHVIDEOMODE:
+		handler = switchvideomode_handler;
+		break;
+	case EVENT_CRT_DETECT:
+		reg = REG_CRT_DETECT;
+		handler = crt_detect_handler;
+		break;
+	case EVENT_CAMERA:
+		reg = REG_CAMERA_STATUS;
+		handler = camera_handler;
+		break;
+	case EVENT_USB_OC2:
+		reg = REG_USB2_FLAG;
+		handler = usb2_handler;
+		break;
+	case EVENT_USB_OC0:
+		reg = REG_USB0_FLAG;
+		handler = usb0_handler;
+		break;
+	case EVENT_DISPLAYTOGGLE:
+		reg = REG_DISPLAY_LCD;
+		handler = displaytoggle_handler;
+		break;
+	case EVENT_AUDIO_MUTE:
+		reg = REG_AUDIO_MUTE;
+		break;
+	case EVENT_DISPLAY_BRIGHTNESS:
+		reg = REG_DISPLAY_BRIGHTNESS;
+		break;
+	case EVENT_AUDIO_VOLUME:
+		reg = REG_AUDIO_VOLUME;
+		break;
+	default:
+		break;
+	}
+
+	if (reg != 0)
+		status = ec_read(reg);
+
+	if (handler != NULL)
+		status = handler(status);
+
+	pr_info("%s: event: %d status: %d\n", __func__, event, status);
+
+	/* Report current key to user-space */
+	ke = get_event_key_entry(event, status);
+	if (ke) {
+		if (ke->keycode == SW_LID)
+			report_lid_switch(status);
+		else
+			sparse_keymap_report_entry(yeeloong_hotkey_dev, ke, 1,
+					true);
+	}
+}
+
+/*
+ * SCI(system control interrupt) main interrupt routine
+ *
+ * We will do the query and get event number together so the interrupt routine
+ * should be longer than 120us now at least 3ms elpase for it.
+ */
+static irqreturn_t sci_irq_handler(int irq, void *dev_id)
+{
+	int ret, event;
+
+	if (SCI_IRQ_NUM != irq)
+		return IRQ_NONE;
+
+	/* Query the event number */
+	ret = ec_query_event_num();
+	if (ret < 0)
+		return IRQ_NONE;
+
+	event = ec_get_event_num();
+	if (event < EVENT_START || event > EVENT_END)
+		return IRQ_NONE;
+
+	/* Execute corresponding actions */
+	do_event_action(event);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Config and init some msr and gpio register properly.
+ */
+static int sci_irq_init(void)
+{
+	u32 hi, lo;
+	u32 gpio_base;
+	unsigned long flags;
+	int ret;
+
+	/* Get gpio base */
+	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
+	gpio_base = lo & 0xff00;
+
+	/* Filter the former kb3310 interrupt for security */
+	ret = ec_query_event_num();
+	if (ret)
+		return ret;
+
+	/* For filtering next number interrupt */
+	udelay(10000);
+
+	/* Set gpio native registers and msrs for GPIO27 SCI EVENT PIN
+	 * gpio :
+	 *      input, pull-up, no-invert, event-count and value 0,
+	 *      no-filter, no edge mode
+	 *      gpio27 map to Virtual gpio0
+	 * msr :
+	 *      no primary and lpc
+	 *      Unrestricted Z input to IG10 from Virtual gpio 0.
+	 */
+	local_irq_save(flags);
+	_rdmsr(0x80000024, &hi, &lo);
+	lo &= ~(1 << 10);
+	_wrmsr(0x80000024, hi, lo);
+	_rdmsr(0x80000025, &hi, &lo);
+	lo &= ~(1 << 10);
+	_wrmsr(0x80000025, hi, lo);
+	_rdmsr(0x80000023, &hi, &lo);
+	lo |= (0x0a << 0);
+	_wrmsr(0x80000023, hi, lo);
+	local_irq_restore(flags);
+
+	/* Set gpio27 as sci interrupt
+	 *
+	 * input, pull-up, no-fliter, no-negedge, invert
+	 * the sci event is just about 120us
+	 */
+	asm(".set noreorder\n");
+	/*  input enable */
+	outl(0x00000800, (gpio_base | 0xA0));
+	/*  revert the input */
+	outl(0x00000800, (gpio_base | 0xA4));
+	/*  event-int enable */
+	outl(0x00000800, (gpio_base | 0xB8));
+	asm(".set reorder\n");
+
+	return 0;
+}
+
+static struct irqaction sci_irqaction = {
+	.handler = sci_irq_handler,
+	.name = "sci",
+	.flags = IRQF_SHARED,
+};
+
+static int yeeloong_hotkey_init(void)
+{
+	int ret;
+
+	ret = sci_irq_init();
+	if (ret)
+		return -EFAULT;
+
+	ret = setup_irq(SCI_IRQ_NUM, &sci_irqaction);
+	if (ret)
+		return -EFAULT;
+
+	yeeloong_hotkey_dev = input_allocate_device();
+
+	if (!yeeloong_hotkey_dev) {
+		remove_irq(SCI_IRQ_NUM, &sci_irqaction);
+		return -ENOMEM;
+	}
+
+	yeeloong_hotkey_dev->name = "HotKeys";
+	yeeloong_hotkey_dev->phys = "button/input0";
+	yeeloong_hotkey_dev->id.bustype = BUS_HOST;
+	yeeloong_hotkey_dev->dev.parent = NULL;
+
+	ret = sparse_keymap_setup(yeeloong_hotkey_dev, yeeloong_keymap, NULL);
+	if (ret) {
+		pr_err("Fail to setup input device keymap\n");
+		input_free_device(yeeloong_hotkey_dev);
+		return ret;
+	}
+
+	ret = input_register_device(yeeloong_hotkey_dev);
+	if (ret) {
+		sparse_keymap_free(yeeloong_hotkey_dev);
+		input_free_device(yeeloong_hotkey_dev);
+		return ret;
+	}
+
+	/* Update the current status of LID */
+	report_lid_switch(BIT_LID_DETECT_ON);
+
+#ifdef CONFIG_LOONGSON_SUSPEND
+	/* Install the real yeeloong_report_lid_status for pm.c */
+	yeeloong_report_lid_status = report_lid_switch;
+#endif
+
+	return 0;
+}
+
+static void yeeloong_hotkey_exit(void)
+{
+	/* Free irq */
+	remove_irq(SCI_IRQ_NUM, &sci_irqaction);
+
+#ifdef CONFIG_LOONGSON_SUSPEND
+	/* Uninstall yeeloong_report_lid_status for pm.c */
+	if (yeeloong_report_lid_status == report_lid_switch)
+		yeeloong_report_lid_status = NULL;
+#endif
+
+	if (yeeloong_hotkey_dev) {
+		sparse_keymap_free(yeeloong_hotkey_dev);
+		input_unregister_device(yeeloong_hotkey_dev);
+		yeeloong_hotkey_dev = NULL;
+	}
+}
+
 #ifdef CONFIG_PM
 static void usb_ports_set(int status)
 {
@@ -540,11 +917,19 @@ static int __init yeeloong_init(void)
 		return ret;
 	}
 
+	ret = yeeloong_hotkey_init();
+	if (ret) {
+		pr_err("Fail to register yeeloong hotkey driver.\n");
+		yeeloong_hotkey_exit();
+		return ret;
+	}
+
 	return 0;
 }
 
 static void __exit yeeloong_exit(void)
 {
+	yeeloong_hotkey_exit();
 	yeeloong_vo_exit();
 	yeeloong_hwmon_exit();
 	yeeloong_backlight_exit();
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/9] Loongson: YeeLoong: add power_supply based battery driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (5 preceding siblings ...)
  2010-05-23 13:58 ` [PATCH 7/9] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
@ 2010-05-23 13:58 ` Wu Zhangjin
  2010-05-23 13:58 ` [PATCH 9/9] Loongson: YeeLoong: Co-operate with the revisions of EC Wu Zhangjin
  2010-05-23 13:59 ` [PATCH 2/9] Loongson: YeeLoong: add platform driver Wu Zhangjin
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:58 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin, Liu Shiwei

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 8602 bytes --]

Changes from old revision:

  o Fixes the bugs
  In the old driver, it didn't show the current charging status and reported
  the wrong full charge and voltage value.

    Capacity = Charge_full_last (Dynamic) / Charge_full_design (Fixed)
    Percentage Charge = Charge_now (Dyn-Dynamic) / Charge_full_last (Dynamic)

Based on the old emulated APM battery driver and the power_supply class,
this patch adds a new battery driver.

References:
1. Documentation/power/power_supply_class.txt
2. drivers/power/

Signed-off-by: Liu Shiwei <liushiwei@gmail.com>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 drivers/platform/mips/Kconfig           |    1 +
 drivers/platform/mips/yeeloong_laptop.c |  228 +++++++++++++++++++++++++++++++
 2 files changed, 229 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 01560b0..cdfccea 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -21,6 +21,7 @@ config LEMOTE_YEELOONG2F
 	select HWMON
 	select VIDEO_OUTPUT_CONTROL
 	select INPUT_SPARSEKMAP
+	select POWER_SUPPLY
 	depends on INPUT
 	help
 	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 817e8fc..e321c58 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -19,6 +19,7 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/power_supply.h>	/* for AC & Battery subdriver */
 
 #include <cs5536/cs5536.h>
 
@@ -330,6 +331,213 @@ static void yeeloong_hwmon_exit(void)
 	}
 }
 
+/* AC & Battery subdriver */
+
+static struct power_supply yeeloong_ac, yeeloong_bat;
+
+#define AC_OFFLINE          0
+#define AC_ONLINE           1
+
+static int yeeloong_get_ac_props(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = ((ec_read(REG_BAT_POWER)) & BIT_BAT_POWER_ACIN) ?
+			AC_ONLINE : AC_OFFLINE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property yeeloong_ac_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
+static struct power_supply yeeloong_ac = {
+	.name = "yeeloong-ac",
+	.type = POWER_SUPPLY_TYPE_MAINS,
+	.properties = yeeloong_ac_props,
+	.num_properties = ARRAY_SIZE(yeeloong_ac_props),
+	.get_property = yeeloong_get_ac_props,
+};
+
+#define BAT_CAP_CRITICAL 5
+#define BAT_CAP_HIGH     99
+
+static int yeeloong_bat_get_ex_property(enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	int bat_in, curr_cap, cap_level, status, charge, health;
+
+	status = ec_read(REG_BAT_STATUS);
+	bat_in = status & BIT_BAT_STATUS_IN;
+	curr_cap = get_bat_info(RELATIVE_CAP);
+	if (status & BIT_BAT_STATUS_FULL)
+		curr_cap = 100;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = bat_in;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = curr_cap;
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+		cap_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+		if (status & BIT_BAT_STATUS_LOW) {
+			cap_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+			if (curr_cap <= BAT_CAP_CRITICAL)
+				cap_level =
+					POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+		} else if (status & BIT_BAT_STATUS_FULL) {
+			cap_level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+			if (curr_cap >= BAT_CAP_HIGH)
+				cap_level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+		} else if (status & BIT_BAT_STATUS_DESTROY)
+			cap_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+		val->intval = cap_level;
+		break;
+	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+		/* seconds */
+		val->intval = bat_in ? (curr_cap - 3) * 54 + 142 : 0;
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!bat_in)
+			charge = POWER_SUPPLY_STATUS_UNKNOWN;
+		else {
+			if (status & BIT_BAT_STATUS_FULL) {
+				val->intval = POWER_SUPPLY_STATUS_FULL;
+				break;
+			}
+
+			charge = ec_read(REG_BAT_CHARGE);
+			if (charge & FLAG_BAT_CHARGE_DISCHARGE)
+				charge = POWER_SUPPLY_STATUS_DISCHARGING;
+			else if (charge & FLAG_BAT_CHARGE_CHARGE)
+				charge = POWER_SUPPLY_STATUS_CHARGING;
+			else
+				charge = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		}
+		val->intval = charge;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		if (!bat_in) /* no battery present */
+			health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		else { /* Assume it is good */
+			health = POWER_SUPPLY_HEALTH_GOOD;
+			if (status &
+				(BIT_BAT_STATUS_DESTROY | BIT_BAT_STATUS_LOW))
+				health = POWER_SUPPLY_HEALTH_DEAD;
+			if (ec_read(REG_BAT_CHARGE_STATUS) &
+				BIT_BAT_CHARGE_STATUS_OVERTEMP)
+				health = POWER_SUPPLY_HEALTH_OVERHEAT;
+		}
+		val->intval = health;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:	/* 1/100(%)*1000 µAh */
+		val->intval = curr_cap * get_bat_info(FULLCHG_CAP) * 10;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int yeeloong_get_bat_props(struct power_supply *psy,
+				     enum power_supply_property psp,
+				     union power_supply_propval *val)
+{
+	switch (psp) {
+	/* Fixed information */
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = get_bat_info(DESIGN_VOL) * 1000;	/* mV -> µV */
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = get_bat_info(DESIGN_CAP) * 1000;	/*mAh -> µAh*/
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = get_bat_info(FULLCHG_CAP) * 1000;	/* µAh */
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval =
+			(ec_read(REG_BAT_VENDOR) == FLAG_BAT_VENDOR_SANYO) ?
+			"SANYO" : "SIMPLO";
+		break;
+	/* Dynamic information */
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = get_battery_current() * 1000;	/* mA -> µA */
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = get_battery_voltage() * 1000;	/* mV -> µV */
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = get_battery_temp();	/* Celcius */
+		break;
+	/* Dynamic but relative information */
+	default:
+		return yeeloong_bat_get_ex_property(psp, val);
+	}
+
+	return 0;
+}
+
+static enum power_supply_property yeeloong_bat_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static struct power_supply yeeloong_bat = {
+	.name = "yeeloong-bat",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = yeeloong_bat_props,
+	.num_properties = ARRAY_SIZE(yeeloong_bat_props),
+	.get_property = yeeloong_get_bat_props,
+};
+
+static int ac_bat_initialized;
+
+static int yeeloong_bat_init(void)
+{
+	int ret;
+
+	ret = power_supply_register(NULL, &yeeloong_ac);
+	if (ret)
+		return ret;
+	ret = power_supply_register(NULL, &yeeloong_bat);
+	if (ret) {
+		power_supply_unregister(&yeeloong_ac);
+		return ret;
+	}
+	ac_bat_initialized = 1;
+
+	return 0;
+}
+
+static void yeeloong_bat_exit(void)
+{
+	ac_bat_initialized = 0;
+
+	power_supply_unregister(&yeeloong_ac);
+	power_supply_unregister(&yeeloong_bat);
+}
+
 /* video output subdriver */
 
 static int lcd_video_output_get(struct output_device *od)
@@ -602,6 +810,15 @@ static int usb0_handler(int status)
 	return status;
 }
 
+static int ac_bat_handler(int status)
+{
+	if (ac_bat_initialized) {
+		power_supply_changed(&yeeloong_ac);
+		power_supply_changed(&yeeloong_bat);
+	}
+	return status;
+}
+
 static void do_event_action(int event)
 {
 	sci_handler handler;
@@ -647,6 +864,9 @@ static void do_event_action(int event)
 	case EVENT_AUDIO_VOLUME:
 		reg = REG_AUDIO_VOLUME;
 		break;
+	case EVENT_AC_BAT:
+		handler = ac_bat_handler;
+		break;
 	default:
 		break;
 	}
@@ -903,6 +1123,13 @@ static int __init yeeloong_init(void)
 		return ret;
 	}
 
+	ret = yeeloong_bat_init();
+	if (ret) {
+		pr_err("Fail to register yeeloong battery driver.\n");
+		yeeloong_bat_exit();
+		return ret;
+	}
+
 	ret = yeeloong_hwmon_init();
 	if (ret) {
 		pr_err("Fail to register yeeloong hwmon driver.\n");
@@ -932,6 +1159,7 @@ static void __exit yeeloong_exit(void)
 	yeeloong_hotkey_exit();
 	yeeloong_vo_exit();
 	yeeloong_hwmon_exit();
+	yeeloong_bat_exit();
 	yeeloong_backlight_exit();
 	platform_driver_unregister(&platform_driver);
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 9/9] Loongson: YeeLoong: Co-operate with the revisions of EC
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (6 preceding siblings ...)
  2010-05-23 13:58 ` [PATCH 8/9] Loongson: YeeLoong: add power_supply based battery driver Wu Zhangjin
@ 2010-05-23 13:58 ` Wu Zhangjin
  2010-05-23 13:59 ` [PATCH 2/9] Loongson: YeeLoong: add platform driver Wu Zhangjin
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:58 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

This patch makes the platform drivers work with the revisions of EC.

  O When EC >= PQ1D26, EC will response the key of Fn+F2 and turn off
  the video output of LCD, we can no do it again in kernel.

  O When EC >= PQ1D27, EC will response the LID key and turn off the
  video output of LCD, we can not do it again in kernel.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/include/asm/mach-loongson/loongson.h |    6 ++++
 arch/mips/loongson/common/cmdline.c            |    8 ++++++
 drivers/platform/mips/yeeloong_laptop.c        |   32 +++++++++++++++++++++--
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index fcdbe3a..53d0bef 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -42,6 +42,12 @@ static inline void prom_init_uart_base(void)
 #endif
 }
 
+/*
+ * Copy kernel command line from arcs_cmdline
+ */
+#include <asm/setup.h>
+extern char loongson_cmdline[COMMAND_LINE_SIZE];
+
 /* irq operation functions */
 extern void bonito_irqdispatch(void);
 extern void __init bonito_irq_init(void);
diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c
index 1a06def..8f290c3 100644
--- a/arch/mips/loongson/common/cmdline.c
+++ b/arch/mips/loongson/common/cmdline.c
@@ -17,10 +17,15 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
+#include <linux/module.h>
 #include <asm/bootinfo.h>
 
 #include <loongson.h>
 
+/* the kernel command line copied from arcs_cmdline */
+char loongson_cmdline[COMMAND_LINE_SIZE];
+EXPORT_SYMBOL(loongson_cmdline);
+
 void __init prom_init_cmdline(void)
 {
 	int prom_argc;
@@ -50,4 +55,7 @@ void __init prom_init_cmdline(void)
 		strcat(arcs_cmdline, " root=/dev/hda1");
 
 	prom_init_machtype();
+
+	/* copy arcs_cmdline into loongson_cmdline */
+	strncpy(loongson_cmdline, arcs_cmdline, COMMAND_LINE_SIZE);
 }
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index e321c58..f6d91a5 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -23,8 +23,29 @@
 
 #include <cs5536/cs5536.h>
 
+#include <loongson.h>		/* for loongson_cmdline */
 #include <ec_kb3310b.h>
 
+/* common function */
+#define EC_VER_LEN 64
+
+static int ec_version_before(char *version)
+{
+	char *p, ec_ver[EC_VER_LEN];
+
+	p = strstr(loongson_cmdline, "EC_VER=");
+	if (!p)
+		memset(ec_ver, 0, EC_VER_LEN);
+	else {
+		strncpy(ec_ver, p, EC_VER_LEN);
+		p = strstr(ec_ver, " ");
+		if (p)
+			*p = '\0';
+	}
+
+	return (strncasecmp(ec_ver, version, 64) < 0);
+}
+
 /* backlight subdriver */
 #define MAX_BRIGHTNESS	8
 
@@ -738,7 +759,10 @@ static int crt_detect_handler(int status)
 
 static int displaytoggle_handler(int status)
 {
-	yeeloong_lcd_vo_set(status);
+	/* EC(>=PQ1D26) does this job for us, we can not do it again,
+	 * otherwise, the brightness will not resume to the normal level! */
+	if (ec_version_before("EC_VER=PQ1D26"))
+		yeeloong_lcd_vo_set(status);
 
 	return status;
 }
@@ -1063,7 +1087,8 @@ static void usb_ports_set(int status)
 
 static int yeeloong_suspend(struct device *dev)
 {
-	yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+	if (ec_version_before("EC_VER=PQ1D27"))
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
 	yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
 	usb_ports_set(BIT_USB_FLAG_OFF);
 
@@ -1074,7 +1099,8 @@ static int yeeloong_resume(struct device *dev)
 {
 	usb_ports_set(BIT_USB_FLAG_ON);
 	yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
-	yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+	if (ec_version_before("EC_VER=PQ1D27"))
+		yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
 
 	return 0;
 }
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/9] Loongson: YeeLoong: add platform driver
  2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
                   ` (7 preceding siblings ...)
  2010-05-23 13:58 ` [PATCH 9/9] Loongson: YeeLoong: Co-operate with the revisions of EC Wu Zhangjin
@ 2010-05-23 13:59 ` Wu Zhangjin
  8 siblings, 0 replies; 10+ messages in thread
From: Wu Zhangjin @ 2010-05-23 13:59 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, Wu Zhangjin

This patch adds platform driver for YeeLoong, Currently, This driver is
"empty", the subdrivers will be added in the coming patches.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/include/asm/mach-loongson/ec_kb3310b.h |  190 ++++++++++++++++++++++
 arch/mips/loongson/lemote-2f/Makefile            |    2 +-
 arch/mips/loongson/lemote-2f/ec_kb3310b.c        |   12 +-
 arch/mips/loongson/lemote-2f/ec_kb3310b.h        |  188 ---------------------
 arch/mips/loongson/lemote-2f/platform.c          |   39 +++++
 arch/mips/loongson/lemote-2f/pm.c                |    4 +-
 arch/mips/loongson/lemote-2f/reset.c             |    2 +-
 drivers/platform/Makefile                        |    1 +
 drivers/platform/mips/Kconfig                    |    8 +
 drivers/platform/mips/Makefile                   |    5 +
 drivers/platform/mips/yeeloong_laptop.c          |   59 +++++++
 11 files changed, 310 insertions(+), 200 deletions(-)
 create mode 100644 arch/mips/include/asm/mach-loongson/ec_kb3310b.h
 delete mode 100644 arch/mips/loongson/lemote-2f/ec_kb3310b.h
 create mode 100644 arch/mips/loongson/lemote-2f/platform.c
 create mode 100644 drivers/platform/mips/Makefile
 create mode 100644 drivers/platform/mips/yeeloong_laptop.c

diff --git a/arch/mips/include/asm/mach-loongson/ec_kb3310b.h b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
new file mode 100644
index 0000000..a4926df
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/ec_kb3310b.h
@@ -0,0 +1,190 @@
+/*
+ * KB3310B Embedded Controller
+ *
+ *  Copyright (C) 2008 Lemote Inc.
+ *  Author: liujl <liujl@lemote.com>, 2008-03-14
+ *  Copyright (C) 2009, 2010 Wu Zhangjin <wuzhangjin@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _EC_KB3310B_H
+#define _EC_KB3310B_H
+
+extern unsigned char ec_read(unsigned short addr);
+extern void ec_write(unsigned short addr, unsigned char val);
+extern int ec_query_seq(unsigned char cmd);
+extern int ec_query_event_num(void);
+extern int ec_get_event_num(void);
+
+typedef int (*sci_handler) (int status);
+extern sci_handler yeeloong_report_lid_status;
+
+#define SCI_IRQ_NUM 0x0A
+
+/*
+ * The following registers are determined by the EC index configuration.
+ * 1, fill the PORT_HIGH as EC register high part.
+ * 2, fill the PORT_LOW as EC register low part.
+ * 3, fill the PORT_DATA as EC register write data or get the data from it.
+ */
+#define	EC_IO_PORT_HIGH	0x0381
+#define	EC_IO_PORT_LOW	0x0382
+#define	EC_IO_PORT_DATA	0x0383
+
+/*
+ * EC delay time is 500us for register and status access
+ */
+#define	EC_REG_DELAY	500	/* unit : us */
+#define	EC_CMD_TIMEOUT	0x1000
+
+/*
+ * EC access port for SCI communication
+ */
+#define	EC_CMD_PORT		0x66
+#define	EC_STS_PORT		0x66
+#define	EC_DAT_PORT		0x62
+#define	CMD_INIT_IDLE_MODE	0xdd
+#define	CMD_EXIT_IDLE_MODE	0xdf
+#define	CMD_INIT_RESET_MODE	0xd8
+#define	CMD_REBOOT_SYSTEM	0x8c
+#define	CMD_GET_EVENT_NUM	0x84
+#define	CMD_PROGRAM_PIECE	0xda
+
+/* Temperature & Fan registers */
+#define	REG_TEMPERATURE_VALUE	0xF458
+#define	REG_FAN_AUTO_MAN_SWITCH 0xF459
+#define	BIT_FAN_AUTO		0
+#define	BIT_FAN_MANUAL		1
+#define	REG_FAN_CONTROL		0xF4D2
+#define	BIT_FAN_CONTROL_ON	(1 << 0)
+#define	BIT_FAN_CONTROL_OFF	(0 << 0)
+#define	REG_FAN_STATUS		0xF4DA
+#define	BIT_FAN_STATUS_ON	(1 << 0)
+#define	BIT_FAN_STATUS_OFF	(0 << 0)
+#define	REG_FAN_SPEED_HIGH	0xFE22
+#define	REG_FAN_SPEED_LOW	0xFE23
+#define	REG_FAN_SPEED_LEVEL	0xF4CC
+/* Fan speed divider */
+#define	FAN_SPEED_DIVIDER	480000	/* (60*1000*1000/62.5/2)*/
+
+/* Battery registers */
+#define	REG_BAT_DESIGN_CAP_HIGH		0xF77D
+#define	REG_BAT_DESIGN_CAP_LOW		0xF77E
+#define	REG_BAT_FULLCHG_CAP_HIGH	0xF780
+#define	REG_BAT_FULLCHG_CAP_LOW		0xF781
+#define	REG_BAT_DESIGN_VOL_HIGH		0xF782
+#define	REG_BAT_DESIGN_VOL_LOW		0xF783
+#define	REG_BAT_CURRENT_HIGH		0xF784
+#define	REG_BAT_CURRENT_LOW		0xF785
+#define	REG_BAT_VOLTAGE_HIGH		0xF786
+#define	REG_BAT_VOLTAGE_LOW		0xF787
+#define	REG_BAT_TEMPERATURE_HIGH	0xF788
+#define	REG_BAT_TEMPERATURE_LOW		0xF789
+#define	REG_BAT_RELATIVE_CAP_HIGH	0xF492
+#define	REG_BAT_RELATIVE_CAP_LOW	0xF493
+#define	REG_BAT_VENDOR			0xF4C4
+#define	FLAG_BAT_VENDOR_SANYO		0x01
+#define	FLAG_BAT_VENDOR_SIMPLO		0x02
+#define	REG_BAT_CELL_COUNT		0xF4C6
+#define	FLAG_BAT_CELL_3S1P		0x03
+#define	FLAG_BAT_CELL_3S2P		0x06
+#define	REG_BAT_CHARGE			0xF4A2
+#define	FLAG_BAT_CHARGE_DISCHARGE	0x01
+#define	FLAG_BAT_CHARGE_CHARGE		0x02
+#define	FLAG_BAT_CHARGE_ACPOWER		0x00
+#define	REG_BAT_STATUS			0xF4B0
+#define	BIT_BAT_STATUS_LOW		(1 << 5)
+#define	BIT_BAT_STATUS_DESTROY		(1 << 2)
+#define	BIT_BAT_STATUS_FULL		(1 << 1)
+#define	BIT_BAT_STATUS_IN		(1 << 0)
+#define	REG_BAT_CHARGE_STATUS		0xF4B1
+#define	BIT_BAT_CHARGE_STATUS_OVERTEMP	(1 << 2)
+#define	BIT_BAT_CHARGE_STATUS_PRECHG	(1 << 1)
+#define	REG_BAT_STATE			0xF482
+#define	BIT_BAT_STATE_CHARGING		(1 << 1)
+#define	BIT_BAT_STATE_DISCHARGING	(1 << 0)
+#define	REG_BAT_POWER			0xF440
+#define	BIT_BAT_POWER_S3		(1 << 2)
+#define	BIT_BAT_POWER_ON		(1 << 1)
+#define	BIT_BAT_POWER_ACIN		(1 << 0)
+
+/* Audio: rd/wr */
+#define	REG_AUDIO_VOLUME	0xF46C
+#define	REG_AUDIO_MUTE		0xF4E7
+#define	REG_AUDIO_BEEP		0xF4D0
+/* USB port power or not: rd/wr */
+#define	REG_USB0_FLAG		0xF461
+#define	REG_USB1_FLAG		0xF462
+#define	REG_USB2_FLAG		0xF463
+#define	BIT_USB_FLAG_ON		1
+#define	BIT_USB_FLAG_OFF	0
+/* LID */
+#define	REG_LID_DETECT		0xF4BD
+#define	BIT_LID_DETECT_ON	1
+#define	BIT_LID_DETECT_OFF	0
+/* CRT */
+#define	REG_CRT_DETECT		0xF4AD
+#define	BIT_CRT_DETECT_PLUG	1
+#define	BIT_CRT_DETECT_UNPLUG	0
+/* LCD backlight brightness adjust: 9 levels */
+#define	REG_DISPLAY_BRIGHTNESS	0xF4F5
+/* Black screen Status */
+#define	BIT_DISPLAY_LCD_ON	1
+#define	BIT_DISPLAY_LCD_OFF	0
+/* LCD backlight control: off/restore */
+#define	REG_BACKLIGHT_CTRL	0xF7BD
+#define	BIT_BACKLIGHT_ON	1
+#define	BIT_BACKLIGHT_OFF	0
+/* Reset the machine auto-clear: rd/wr */
+#define	REG_RESET		0xF4EC
+#define	BIT_RESET_ON		1
+/* Light the led: rd/wr */
+#define	REG_LED			0xF4C8
+#define	BIT_LED_RED_POWER	(1 << 0)
+#define	BIT_LED_ORANGE_POWER	(1 << 1)
+#define	BIT_LED_GREEN_CHARGE	(1 << 2)
+#define	BIT_LED_RED_CHARGE	(1 << 3)
+#define	BIT_LED_NUMLOCK		(1 << 4)
+/* Test led mode, all led on/off */
+#define	REG_LED_TEST		0xF4C2
+#define	BIT_LED_TEST_IN		1
+#define	BIT_LED_TEST_OUT	0
+/* Camera on/off */
+#define	REG_CAMERA_STATUS	0xF46A
+#define	BIT_CAMERA_STATUS_ON	1
+#define	BIT_CAMERA_STATUS_OFF	0
+#define	REG_CAMERA_CONTROL	0xF7B7
+#define	BIT_CAMERA_CONTROL_OFF	0
+#define	BIT_CAMERA_CONTROL_ON	1
+/* Wlan Status */
+#define	REG_WLAN		0xF4FA
+#define	BIT_WLAN_ON		1
+#define	BIT_WLAN_OFF		0
+#define	REG_DISPLAY_LCD		0xF79F
+
+/* SCI Event Number from EC */
+enum {
+	EVENT_LID = 0x23,	/*  Turn on/off LID */
+	EVENT_SWITCHVIDEOMODE,	/*  Fn+F3 for display switch */
+	EVENT_SLEEP,		/*  Fn+F1 for entering sleep mode */
+	EVENT_OVERTEMP,		/*  Over-temperature happened */
+	EVENT_CRT_DETECT,	/*  CRT is connected */
+	EVENT_CAMERA,		/*  Camera on/off */
+	EVENT_USB_OC2,		/*  USB2 Over Current occurred */
+	EVENT_USB_OC0,		/*  USB0 Over Current occurred */
+	EVENT_DISPLAYTOGGLE,	/*  Fn+F2, Turn on/off backlight */
+	EVENT_AUDIO_MUTE,	/*  Fn+F4, Mute on/off */
+	EVENT_DISPLAY_BRIGHTNESS,/* Fn+^/V, LCD backlight brightness adjust */
+	EVENT_AC_BAT,		/*  AC & Battery relative issue */
+	EVENT_AUDIO_VOLUME,	/*  Fn+<|>, Volume adjust */
+	EVENT_WLAN,		/*  Wlan on/off */
+};
+
+#define EVENT_START	EVENT_LID
+#define EVENT_END	EVENT_WLAN
+
+#endif /* !_EC_KB3310B_H */
diff --git a/arch/mips/loongson/lemote-2f/Makefile b/arch/mips/loongson/lemote-2f/Makefile
index 8699a53..10e9eb7 100644
--- a/arch/mips/loongson/lemote-2f/Makefile
+++ b/arch/mips/loongson/lemote-2f/Makefile
@@ -2,7 +2,7 @@
 # Makefile for lemote loongson2f family machines
 #
 
-obj-y += machtype.o irq.o reset.o ec_kb3310b.o
+obj-y += machtype.o irq.o reset.o ec_kb3310b.o platform.o
 
 #
 # Suspend Support
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.c b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
index 6405724..23c3c27 100644
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.c
+++ b/arch/mips/loongson/lemote-2f/ec_kb3310b.c
@@ -14,7 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
 
 static DEFINE_SPINLOCK(index_access_lock);
 static DEFINE_SPINLOCK(port_access_lock);
@@ -78,12 +78,9 @@ int ec_query_seq(unsigned char cmd)
 	spin_unlock_irqrestore(&port_access_lock, flags);
 
 	if (timeout <= 0) {
-		printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
+		pr_err("%s: deadable error : timeout...\n", __func__);
 		ret = -EINVAL;
-	} else
-		printk(KERN_INFO
-			   "(%x/%d)ec issued command %d status : 0x%x\n",
-			   timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
+	}
 
 	return ret;
 }
@@ -118,8 +115,7 @@ int ec_get_event_num(void)
 		udelay(EC_REG_DELAY);
 	}
 	if (timeout <= 0) {
-		pr_info("%s: get event number timeout.\n", __func__);
-
+		pr_err("%s: get event number timeout.\n", __func__);
 		return -EINVAL;
 	}
 	value = inb(EC_DAT_PORT);
diff --git a/arch/mips/loongson/lemote-2f/ec_kb3310b.h b/arch/mips/loongson/lemote-2f/ec_kb3310b.h
deleted file mode 100644
index 1595a21..0000000
--- a/arch/mips/loongson/lemote-2f/ec_kb3310b.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * KB3310B Embedded Controller
- *
- *  Copyright (C) 2008 Lemote Inc.
- *  Author: liujl <liujl@lemote.com>, 2008-03-14
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _EC_KB3310B_H
-#define _EC_KB3310B_H
-
-extern unsigned char ec_read(unsigned short addr);
-extern void ec_write(unsigned short addr, unsigned char val);
-extern int ec_query_seq(unsigned char cmd);
-extern int ec_query_event_num(void);
-extern int ec_get_event_num(void);
-
-typedef int (*sci_handler) (int status);
-extern sci_handler yeeloong_report_lid_status;
-
-#define SCI_IRQ_NUM 0x0A
-
-/*
- * The following registers are determined by the EC index configuration.
- * 1, fill the PORT_HIGH as EC register high part.
- * 2, fill the PORT_LOW as EC register low part.
- * 3, fill the PORT_DATA as EC register write data or get the data from it.
- */
-#define	EC_IO_PORT_HIGH	0x0381
-#define	EC_IO_PORT_LOW	0x0382
-#define	EC_IO_PORT_DATA	0x0383
-
-/*
- * EC delay time is 500us for register and status access
- */
-#define	EC_REG_DELAY	500	/* unit : us */
-#define	EC_CMD_TIMEOUT	0x1000
-
-/*
- * EC access port for SCI communication
- */
-#define	EC_CMD_PORT		0x66
-#define	EC_STS_PORT		0x66
-#define	EC_DAT_PORT		0x62
-#define	CMD_INIT_IDLE_MODE	0xdd
-#define	CMD_EXIT_IDLE_MODE	0xdf
-#define	CMD_INIT_RESET_MODE	0xd8
-#define	CMD_REBOOT_SYSTEM	0x8c
-#define	CMD_GET_EVENT_NUM	0x84
-#define	CMD_PROGRAM_PIECE	0xda
-
-/* temperature & fan registers */
-#define	REG_TEMPERATURE_VALUE	0xF458
-#define	REG_FAN_AUTO_MAN_SWITCH 0xF459
-#define	BIT_FAN_AUTO		0
-#define	BIT_FAN_MANUAL		1
-#define	REG_FAN_CONTROL		0xF4D2
-#define	BIT_FAN_CONTROL_ON	(1 << 0)
-#define	BIT_FAN_CONTROL_OFF	(0 << 0)
-#define	REG_FAN_STATUS		0xF4DA
-#define	BIT_FAN_STATUS_ON	(1 << 0)
-#define	BIT_FAN_STATUS_OFF	(0 << 0)
-#define	REG_FAN_SPEED_HIGH	0xFE22
-#define	REG_FAN_SPEED_LOW	0xFE23
-#define	REG_FAN_SPEED_LEVEL	0xF4CC
-/* fan speed divider */
-#define	FAN_SPEED_DIVIDER	480000	/* (60*1000*1000/62.5/2)*/
-
-/* battery registers */
-#define	REG_BAT_DESIGN_CAP_HIGH		0xF77D
-#define	REG_BAT_DESIGN_CAP_LOW		0xF77E
-#define	REG_BAT_FULLCHG_CAP_HIGH	0xF780
-#define	REG_BAT_FULLCHG_CAP_LOW		0xF781
-#define	REG_BAT_DESIGN_VOL_HIGH		0xF782
-#define	REG_BAT_DESIGN_VOL_LOW		0xF783
-#define	REG_BAT_CURRENT_HIGH		0xF784
-#define	REG_BAT_CURRENT_LOW		0xF785
-#define	REG_BAT_VOLTAGE_HIGH		0xF786
-#define	REG_BAT_VOLTAGE_LOW		0xF787
-#define	REG_BAT_TEMPERATURE_HIGH	0xF788
-#define	REG_BAT_TEMPERATURE_LOW		0xF789
-#define	REG_BAT_RELATIVE_CAP_HIGH	0xF492
-#define	REG_BAT_RELATIVE_CAP_LOW	0xF493
-#define	REG_BAT_VENDOR			0xF4C4
-#define	FLAG_BAT_VENDOR_SANYO		0x01
-#define	FLAG_BAT_VENDOR_SIMPLO		0x02
-#define	REG_BAT_CELL_COUNT		0xF4C6
-#define	FLAG_BAT_CELL_3S1P		0x03
-#define	FLAG_BAT_CELL_3S2P		0x06
-#define	REG_BAT_CHARGE			0xF4A2
-#define	FLAG_BAT_CHARGE_DISCHARGE	0x01
-#define	FLAG_BAT_CHARGE_CHARGE		0x02
-#define	FLAG_BAT_CHARGE_ACPOWER		0x00
-#define	REG_BAT_STATUS			0xF4B0
-#define	BIT_BAT_STATUS_LOW		(1 << 5)
-#define	BIT_BAT_STATUS_DESTROY		(1 << 2)
-#define	BIT_BAT_STATUS_FULL		(1 << 1)
-#define	BIT_BAT_STATUS_IN		(1 << 0)
-#define	REG_BAT_CHARGE_STATUS		0xF4B1
-#define	BIT_BAT_CHARGE_STATUS_OVERTEMP	(1 << 2)
-#define	BIT_BAT_CHARGE_STATUS_PRECHG	(1 << 1)
-#define	REG_BAT_STATE			0xF482
-#define	BIT_BAT_STATE_CHARGING		(1 << 1)
-#define	BIT_BAT_STATE_DISCHARGING	(1 << 0)
-#define	REG_BAT_POWER			0xF440
-#define	BIT_BAT_POWER_S3		(1 << 2)
-#define	BIT_BAT_POWER_ON		(1 << 1)
-#define	BIT_BAT_POWER_ACIN		(1 << 0)
-
-/* other registers */
-/* Audio: rd/wr */
-#define	REG_AUDIO_VOLUME	0xF46C
-#define	REG_AUDIO_MUTE		0xF4E7
-#define	REG_AUDIO_BEEP		0xF4D0
-/* USB port power or not: rd/wr */
-#define	REG_USB0_FLAG		0xF461
-#define	REG_USB1_FLAG		0xF462
-#define	REG_USB2_FLAG		0xF463
-#define	BIT_USB_FLAG_ON		1
-#define	BIT_USB_FLAG_OFF	0
-/* LID */
-#define	REG_LID_DETECT		0xF4BD
-#define	BIT_LID_DETECT_ON	1
-#define	BIT_LID_DETECT_OFF	0
-/* CRT */
-#define	REG_CRT_DETECT		0xF4AD
-#define	BIT_CRT_DETECT_PLUG	1
-#define	BIT_CRT_DETECT_UNPLUG	0
-/* LCD backlight brightness adjust: 9 levels */
-#define	REG_DISPLAY_BRIGHTNESS	0xF4F5
-/* Black screen Status */
-#define	BIT_DISPLAY_LCD_ON	1
-#define	BIT_DISPLAY_LCD_OFF	0
-/* LCD backlight control: off/restore */
-#define	REG_BACKLIGHT_CTRL	0xF7BD
-#define	BIT_BACKLIGHT_ON	1
-#define	BIT_BACKLIGHT_OFF	0
-/* Reset the machine auto-clear: rd/wr */
-#define	REG_RESET		0xF4EC
-#define	BIT_RESET_ON		1
-/* Light the led: rd/wr */
-#define	REG_LED			0xF4C8
-#define	BIT_LED_RED_POWER	(1 << 0)
-#define	BIT_LED_ORANGE_POWER	(1 << 1)
-#define	BIT_LED_GREEN_CHARGE	(1 << 2)
-#define	BIT_LED_RED_CHARGE	(1 << 3)
-#define	BIT_LED_NUMLOCK		(1 << 4)
-/* Test led mode, all led on/off */
-#define	REG_LED_TEST		0xF4C2
-#define	BIT_LED_TEST_IN		1
-#define	BIT_LED_TEST_OUT	0
-/* Camera on/off */
-#define	REG_CAMERA_STATUS	0xF46A
-#define	BIT_CAMERA_STATUS_ON	1
-#define	BIT_CAMERA_STATUS_OFF	0
-#define	REG_CAMERA_CONTROL	0xF7B7
-#define	BIT_CAMERA_CONTROL_OFF	0
-#define	BIT_CAMERA_CONTROL_ON	1
-/* Wlan Status */
-#define	REG_WLAN		0xF4FA
-#define	BIT_WLAN_ON		1
-#define	BIT_WLAN_OFF		0
-#define	REG_DISPLAY_LCD		0xF79F
-
-/* SCI Event Number from EC */
-enum {
-	EVENT_LID = 0x23,	/*  LID open/close */
-	EVENT_DISPLAY_TOGGLE,	/*  Fn+F3 for display switch */
-	EVENT_SLEEP,		/*  Fn+F1 for entering sleep mode */
-	EVENT_OVERTEMP,		/*  Over-temperature happened */
-	EVENT_CRT_DETECT,	/*  CRT is connected */
-	EVENT_CAMERA,		/*  Camera on/off */
-	EVENT_USB_OC2,		/*  USB2 Over Current occurred */
-	EVENT_USB_OC0,		/*  USB0 Over Current occurred */
-	EVENT_BLACK_SCREEN,	/*  Turn on/off backlight */
-	EVENT_AUDIO_MUTE,	/*  Mute on/off */
-	EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */
-	EVENT_AC_BAT,		/*  AC & Battery relative issue */
-	EVENT_AUDIO_VOLUME,	/*  Volume adjust */
-	EVENT_WLAN,		/*  Wlan on/off */
-	EVENT_END
-};
-
-#endif /* !_EC_KB3310B_H */
diff --git a/arch/mips/loongson/lemote-2f/platform.c b/arch/mips/loongson/lemote-2f/platform.c
new file mode 100644
index 0000000..edce0d5
--- /dev/null
+++ b/arch/mips/loongson/lemote-2f/platform.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009, 2010 Wu Zhangjin <wuzhangjin@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <asm/bootinfo.h>
+
+static struct platform_device yeeloong_pdev = {
+	.name = "yeeloong_laptop",
+	.id = -1,
+};
+
+static int __init lemote2f_platform_init(void)
+{
+	struct platform_device *pdev = NULL;
+
+	switch (mips_machtype) {
+	case MACH_LEMOTE_YL2F89:
+		pdev = &yeeloong_pdev;
+		break;
+	default:
+		break;
+
+	}
+
+	if (pdev != NULL)
+		return platform_device_register(pdev);
+
+	return -ENODEV;
+}
+
+device_initcall(lemote2f_platform_init);
diff --git a/arch/mips/loongson/lemote-2f/pm.c b/arch/mips/loongson/lemote-2f/pm.c
index cac4d38..ff0d94a 100644
--- a/arch/mips/loongson/lemote-2f/pm.c
+++ b/arch/mips/loongson/lemote-2f/pm.c
@@ -23,7 +23,7 @@
 #include <loongson.h>
 
 #include <cs5536/cs5536_mfgpt.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
 
 #define I8042_KBD_IRQ		1
 #define I8042_CTR_KBDINT	0x01
@@ -100,7 +100,7 @@ int wakeup_loongson(void)
 	if (irq < 0)
 		return 0;
 
-	printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
+	pr_info("%s: irq = %d\n", __func__, irq);
 
 	if (irq == I8042_KBD_IRQ)
 		return 1;
diff --git a/arch/mips/loongson/lemote-2f/reset.c b/arch/mips/loongson/lemote-2f/reset.c
index 36020a0..8cff901 100644
--- a/arch/mips/loongson/lemote-2f/reset.c
+++ b/arch/mips/loongson/lemote-2f/reset.c
@@ -20,7 +20,7 @@
 #include <loongson.h>
 
 #include <cs5536/cs5536.h>
-#include "ec_kb3310b.h"
+#include <ec_kb3310b.h>
 
 static void reset_cpu(void)
 {
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 782953a..8bdc97c 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_X86)		+= x86/
+obj-$(CONFIG_MIPS)		+= mips/
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 2f77693..5ac5215 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -14,5 +14,13 @@ menuconfig MIPS_PLATFORM_DEVICES
 
 if MIPS_PLATFORM_DEVICES
 
+config LEMOTE_YEELOONG2F
+	tristate "Lemote YeeLoong Laptop"
+	depends on LEMOTE_MACH2F
+	help
+	  YeeLoong netbook is a mini laptop made by Lemote, which is basically
+	  compatible to FuLoong2F mini PC, but it has an extra Embedded
+	  Controller(kb3310b) for battery, hotkey, backlight, temperature and
+	  fan management.
 
 endif # MIPS_PLATFORM_DEVICES
diff --git a/drivers/platform/mips/Makefile b/drivers/platform/mips/Makefile
new file mode 100644
index 0000000..506f920
--- /dev/null
+++ b/drivers/platform/mips/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for MIPS Platform-Specific Drivers
+#
+
+obj-$(CONFIG_LEMOTE_YEELOONG2F)	+= yeeloong_laptop.o
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
new file mode 100644
index 0000000..09f606c
--- /dev/null
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -0,0 +1,59 @@
+/*
+ * Driver for YeeLoong laptop extras
+ *
+ *  Copyright (C) 2009, 2010 Wu Zhangjin <wuzhangjin@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+static struct platform_device_id platform_device_ids[] = {
+	{
+		.name = "yeeloong_laptop",
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(platform, platform_device_ids);
+
+static struct platform_driver platform_driver = {
+	.driver = {
+		   .name = "yeeloong_laptop",
+		   .owner = THIS_MODULE,
+		   },
+	.id_table = platform_device_ids,
+};
+
+static int __init yeeloong_init(void)
+{
+	int ret;
+
+	pr_info("Load YeeLoong Laptop Platform Specific Driver.\n");
+
+	/* Register platform stuff */
+	ret = platform_driver_register(&platform_driver);
+	if (ret) {
+		pr_err("Fail to register yeeloong platform driver.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit yeeloong_exit(void)
+{
+	platform_driver_unregister(&platform_driver);
+
+	pr_info("Unload YeeLoong Platform Specific Driver.\n");
+}
+
+module_init(yeeloong_init);
+module_exit(yeeloong_exit);
+
+MODULE_AUTHOR("Wu Zhangjin <wuzhangjin@gmail.com>");
+MODULE_DESCRIPTION("YeeLoong laptop driver");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-05-23 14:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-23 13:57 [PATCH v12 0/9] Loongson: YeeLoong: add platform specific driver Wu Zhangjin
2010-05-23 13:57 ` [PATCH 1/9] MIPS: add subdirectory for platform extension drivers Wu Zhangjin
2010-05-23 13:57 ` [PATCH 3/9] Loongson: YeeLoong: add backlight driver Wu Zhangjin
2010-05-23 13:57 ` [PATCH 4/9] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
2010-05-23 13:58 ` [PATCH 5/9] Loongson: YeeLoong: add video output driver Wu Zhangjin
2010-05-23 13:58 ` [PATCH 6/9] Loongson: YeeLoong: add suspend support Wu Zhangjin
2010-05-23 13:58 ` [PATCH 7/9] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
2010-05-23 13:58 ` [PATCH 8/9] Loongson: YeeLoong: add power_supply based battery driver Wu Zhangjin
2010-05-23 13:58 ` [PATCH 9/9] Loongson: YeeLoong: Co-operate with the revisions of EC Wu Zhangjin
2010-05-23 13:59 ` [PATCH 2/9] Loongson: YeeLoong: add platform driver Wu Zhangjin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).