* Re: [PATCH v7 4/8] Loongson: YeeLoong: add battery driver
2009-12-04 13:34 ` [PATCH v7 4/8] Loongson: YeeLoong: add battery driver Wu Zhangjin
@ 2009-12-04 8:04 ` Pavel Machek
2009-12-04 14:56 ` Wu Zhangjin
2009-12-08 6:57 ` Wu Zhangjin
1 sibling, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2009-12-04 8:04 UTC (permalink / raw)
To: Wu Zhangjin
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, Stephen Rothwell, linux-laptop
On Fri 2009-12-04 21:34:17, Wu Zhangjin wrote:
> From: Wu Zhangjin <wuzhangjin@gmail.com>
>
> This patch adds APM emulated Battery Driver, it provides standard
> interface(/proc/apm) for user-space applications(e.g. kpowersave,
> gnome-power-manager) to manage the battery.
It would be nicer if this went to drivers/power, and used its
interface -- providing not only percentage but also other values.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver
2009-12-04 13:35 ` [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
@ 2009-12-04 8:08 ` Pavel Machek
2009-12-04 16:29 ` Wu Zhangjin
0 siblings, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2009-12-04 8:08 UTC (permalink / raw)
To: Wu Zhangjin
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop
Hi!
> +static int get_cpu_temp(void)
> +{
> + int value;
> +
> + value = ec_read(REG_TEMPERATURE_VALUE);
> +
> + if (value & (1 << 7))
> + value = (value & 0x7f) - 128;
> + else
> + value = value & 0xff;
wtf?
Maybe value should be 's8'?
> +static int get_battery_current(void)
> +{
> + int value;
> +
> + value = (ec_read(REG_BAT_CURRENT_HIGH) << 8) |
> + (ec_read(REG_BAT_CURRENT_LOW));
> +
> + if (value & 0x8000)
> + value = 0xffff - value;
Another version of pair-complement conversion; this one is broken --
off by 1.
> +static int parse_arg(const char *buf, unsigned long count, int *val)
> +{
> + if (!count)
> + return 0;
> + if (sscanf(buf, "%i", val) != 1)
> + return -EINVAL;
> + return count;
> +}
We have strict_strtoul for a reason...
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 6/8] Loongson: YeeLoong: add video output driver
2009-12-04 13:36 ` [PATCH v7 6/8] Loongson: YeeLoong: add video output driver Wu Zhangjin
@ 2009-12-04 8:11 ` Pavel Machek
2009-12-04 15:04 ` Wu Zhangjin
2009-12-08 6:54 ` Wu Zhangjin
1 sibling, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2009-12-04 8:11 UTC (permalink / raw)
To: Wu Zhangjin
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop, luming.yu
On Fri 2009-12-04 21:36:43, Wu Zhangjin wrote:
> From: Wu Zhangjin <wuzhangjin@gmail.com>
>
> This patch adds Video Output Driver, it provides standard
> interface(/sys/class/video_output) to turn on/off the video output of
> LCD, CRT.
>
> diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
> index 9c8385c..4a89c01 100644
> --- a/drivers/platform/mips/Kconfig
> +++ b/drivers/platform/mips/Kconfig
> @@ -21,6 +21,7 @@ config LEMOTE_YEELOONG2F
> select SYS_SUPPORTS_APM_EMULATION
> select APM_EMULATION
> select HWMON
> + select VIDEO_OUTPUT_CONTROL
> default m
> help
> YeeLoong netbook is a mini laptop made by Lemote, which is basically
default m is evil.
> + if (status == BIT_DISPLAY_LCD_ON) {
> + /* Turn on LCD */
> + outb(0x31, 0x3c4);
> + value = inb(0x3c5);
> + value = (value & 0xf8) | 0x03;
> + outb(0x31, 0x3c4);
> + outb(value, 0x3c5);
> + /* Turn on backlight */
> + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_ON);
> + } else {
> + /* Turn off backlight */
> + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_OFF);
> + /* Turn off LCD */
> + outb(0x31, 0x3c4);
> + value = inb(0x3c5);
> + value = (value & 0xf8) | 0x02;
> + outb(0x31, 0x3c4);
> + outb(value, 0x3c5);
> + }
IIRC this is opencoded in suspend support; should that get common
helpers?
> + if (status == BIT_CRT_DETECT_PLUG) {
> + if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) {
> + /* Turn on CRT */
> + outb(0x21, 0x3c4);
> + value = inb(0x3c5);
> + value &= ~(1 << 7);
> + outb(0x21, 0x3c4);
> + outb(value, 0x3c5);
> + }
> + } else {
> + /* Turn off CRT */
> + outb(0x21, 0x3c4);
> + value = inb(0x3c5);
> + value |= (1 << 7);
> + outb(0x21, 0x3c4);
> + outb(value, 0x3c5);
> + }
This looks suspiciously similar to one another and to code
above. Perhaps some more helpers?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver
2009-12-04 13:39 ` [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
@ 2009-12-04 8:14 ` Pavel Machek
2009-12-04 14:57 ` Wu Zhangjin
0 siblings, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2009-12-04 8:14 UTC (permalink / raw)
To: Wu Zhangjin
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop, linux-input
Hi!
> +#define NO_REG 0
> +#define NO_HANDLER NULL
Don't obfuscate code like that.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v7 4/8] Loongson: YeeLoong: add battery driver
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
@ 2009-12-04 13:34 ` Wu Zhangjin
2009-12-04 8:04 ` Pavel Machek
2009-12-08 6:57 ` Wu Zhangjin
2009-12-04 13:35 ` [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
` (3 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 13:34 UTC (permalink / raw)
To: Ralf Baechle, akpm, linux-mips, linux-kernel
Cc: Dmitry Torokhov, Pavel Machek, Rafael J. Wysocki, zhangfx,
Stephen Rothwell, linux-laptop, Wu Zhangjin
From: Wu Zhangjin <wuzhangjin@gmail.com>
This patch adds APM emulated Battery Driver, it provides standard
interface(/proc/apm) for user-space applications(e.g. kpowersave,
gnome-power-manager) to manage the battery.
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
drivers/platform/mips/Kconfig | 2 +
drivers/platform/mips/yeeloong_laptop.c | 104 +++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index f7a3705..0c6b5ad 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -18,6 +18,8 @@ config LEMOTE_YEELOONG2F
tristate "Lemote YeeLoong Laptop"
depends on LEMOTE_MACH2F
select BACKLIGHT_CLASS_DEVICE
+ select SYS_SUPPORTS_APM_EMULATION
+ select APM_EMULATION
default m
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 fbc4ebb..729e368 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/backlight.h> /* for backlight subdriver */
#include <linux/fb.h>
+#include <linux/apm-emulation.h>/* for battery subdriver */
#include <ec_kb3310b.h>
@@ -83,6 +84,106 @@ static void yeeloong_backlight_exit(void)
}
}
+/* battery subdriver */
+
+static void get_fixed_battery_info(void)
+{
+ int design_cap, full_charged_cap, design_vol, vendor, cell_count;
+
+ design_cap = (ec_read(REG_BAT_DESIGN_CAP_HIGH) << 8)
+ | ec_read(REG_BAT_DESIGN_CAP_LOW);
+ full_charged_cap = (ec_read(REG_BAT_FULLCHG_CAP_HIGH) << 8)
+ | ec_read(REG_BAT_FULLCHG_CAP_LOW);
+ design_vol = (ec_read(REG_BAT_DESIGN_VOL_HIGH) << 8)
+ | ec_read(REG_BAT_DESIGN_VOL_LOW);
+ vendor = ec_read(REG_BAT_VENDOR);
+ cell_count = ec_read(REG_BAT_CELL_COUNT);
+
+ if (vendor != 0) {
+ pr_info("battery vendor(%s), cells count(%d), "
+ "with designed capacity(%d),designed voltage(%d),"
+ " full charged capacity(%d)\n",
+ (vendor ==
+ FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO",
+ (cell_count == FLAG_BAT_CELL_3S1P) ? 3 : 6,
+ design_cap, design_vol,
+ full_charged_cap);
+ }
+}
+
+#define APM_CRITICAL 5
+
+static void get_power_status(struct apm_power_info *info)
+{
+ unsigned char bat_status;
+
+ info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
+ info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
+ info->units = APM_UNITS_MINS;
+
+ info->battery_life = (ec_read(REG_BAT_RELATIVE_CAP_HIGH) << 8) |
+ (ec_read(REG_BAT_RELATIVE_CAP_LOW));
+
+ info->ac_line_status = (ec_read(REG_BAT_POWER) & BIT_BAT_POWER_ACIN) ?
+ APM_AC_ONLINE : APM_AC_OFFLINE;
+
+ bat_status = ec_read(REG_BAT_STATUS);
+
+ if (!(bat_status & BIT_BAT_STATUS_IN)) {
+ /* no battery inserted */
+ info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
+ info->battery_flag = APM_BATTERY_FLAG_NOT_PRESENT;
+ info->time = 0x00;
+ return;
+ }
+
+ /* adapter inserted */
+ if (info->ac_line_status == APM_AC_ONLINE) {
+ if (!(bat_status & BIT_BAT_STATUS_FULL)) {
+ /* battery is not fully charged */
+ info->battery_status = APM_BATTERY_STATUS_CHARGING;
+ info->battery_flag = APM_BATTERY_FLAG_CHARGING;
+ } else {
+ /* battery is fully charged */
+ info->battery_status = APM_BATTERY_STATUS_HIGH;
+ info->battery_flag = APM_BATTERY_FLAG_HIGH;
+ info->battery_life = 100;
+ }
+ } else {
+ /* battery is too low */
+ if (bat_status & BIT_BAT_STATUS_LOW) {
+ info->battery_status = APM_BATTERY_STATUS_LOW;
+ info->battery_flag = APM_BATTERY_FLAG_LOW;
+ if (info->battery_life <= APM_CRITICAL) {
+ /* we should power off the system now */
+ info->battery_status =
+ APM_BATTERY_STATUS_CRITICAL;
+ info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
+ }
+ } else {
+ /* assume the battery is high enough. */
+ info->battery_status = APM_BATTERY_STATUS_HIGH;
+ info->battery_flag = APM_BATTERY_FLAG_HIGH;
+ }
+ }
+ info->time = ((info->battery_life - 3) * 54 + 142) / 60;
+}
+
+static int yeeloong_battery_init(void)
+{
+ get_fixed_battery_info();
+
+ apm_get_power_status = get_power_status;
+
+ return 0;
+}
+
+static void yeeloong_battery_exit(void)
+{
+ if (apm_get_power_status == get_power_status)
+ apm_get_power_status = NULL;
+}
+
static struct platform_device_id platform_device_ids[] = {
{
.name = "yeeloong_laptop",
@@ -120,11 +221,14 @@ static int __init yeeloong_init(void)
return ret;
}
+ yeeloong_battery_init();
+
return 0;
}
static void __exit yeeloong_exit(void)
{
+ yeeloong_battery_exit();
yeeloong_backlight_exit();
platform_driver_unregister(&platform_driver);
--
1.6.2.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
2009-12-04 13:34 ` [PATCH v7 4/8] Loongson: YeeLoong: add battery driver Wu Zhangjin
@ 2009-12-04 13:35 ` Wu Zhangjin
2009-12-04 8:08 ` Pavel Machek
2009-12-04 13:36 ` [PATCH v7 6/8] Loongson: YeeLoong: add video output driver Wu Zhangjin
` (2 subsequent siblings)
4 siblings, 1 reply; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 13:35 UTC (permalink / raw)
To: Ralf Baechle, akpm, linux-mips, linux-kernel
Cc: Dmitry Torokhov, Pavel Machek, Rafael J. Wysocki, zhangfx,
linux-laptop, Wu Zhangjin
From: Wu Zhangjin <wuzhangjin@gmail.com>
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.
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
drivers/platform/mips/Kconfig | 1 +
drivers/platform/mips/yeeloong_laptop.c | 221 +++++++++++++++++++++++++++++++
2 files changed, 222 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 0c6b5ad..9c8385c 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -20,6 +20,7 @@ config LEMOTE_YEELOONG2F
select BACKLIGHT_CLASS_DEVICE
select SYS_SUPPORTS_APM_EMULATION
select APM_EMULATION
+ select HWMON
default m
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 729e368..644aaa7 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -14,6 +14,8 @@
#include <linux/backlight.h> /* for backlight subdriver */
#include <linux/fb.h>
#include <linux/apm-emulation.h>/* for battery subdriver */
+#include <linux/hwmon.h> /* for hwmon subdriver */
+#include <linux/hwmon-sysfs.h>
#include <ec_kb3310b.h>
@@ -184,6 +186,217 @@ static void yeeloong_battery_exit(void)
apm_get_power_status = NULL;
}
+/* hwmon subdriver */
+
+/* pwm(auto/manual) enable or not */
+static int get_fan_pwm_enable(void)
+{
+ return ec_read(REG_FAN_AUTO_MAN_SWITCH);
+}
+
+static void set_fan_pwm_enable(int manual)
+{
+ ec_write(REG_FAN_AUTO_MAN_SWITCH, !!manual);
+}
+
+static int get_fan_pwm(void)
+{
+ return ec_read(REG_FAN_SPEED_LEVEL);
+}
+
+static void set_fan_pwm(int value)
+{
+ int status;
+
+ value = SENSORS_LIMIT(value, 0, 3);
+
+ /* If value is not ZERO, We should ensure it is on */
+ if (value != 0) {
+ status = ec_read(REG_FAN_STATUS);
+ if (status == 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)
+{
+ int value;
+
+ value = ec_read(REG_TEMPERATURE_VALUE);
+
+ if (value & (1 << 7))
+ value = (value & 0x7f) - 128;
+ else
+ value = value & 0xff;
+
+ return value * 1000;
+}
+
+static int get_battery_temp(void)
+{
+ int value;
+
+ value = (ec_read(REG_BAT_TEMPERATURE_HIGH) << 8) |
+ (ec_read(REG_BAT_TEMPERATURE_LOW));
+
+ 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)
+{
+ int value;
+
+ value = (ec_read(REG_BAT_CURRENT_HIGH) << 8) |
+ (ec_read(REG_BAT_CURRENT_LOW));
+
+ if (value & 0x8000)
+ value = 0xffff - value;
+
+ return value;
+}
+
+static int get_battery_voltage(void)
+{
+ int value;
+
+ value = (ec_read(REG_BAT_VOLTAGE_HIGH) << 8) |
+ (ec_read(REG_BAT_VOLTAGE_LOW));
+
+ return value;
+}
+
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_sys_hwmon(void (*set) (int), const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set(value);
+ return rv;
+}
+
+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(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_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(BIT_FAN_AUTO);
+
+ 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",
@@ -223,11 +436,19 @@ static int __init yeeloong_init(void)
yeeloong_battery_init();
+ 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_battery_exit();
yeeloong_backlight_exit();
platform_driver_unregister(&platform_driver);
--
1.6.2.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7 6/8] Loongson: YeeLoong: add video output driver
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
2009-12-04 13:34 ` [PATCH v7 4/8] Loongson: YeeLoong: add battery driver Wu Zhangjin
2009-12-04 13:35 ` [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
@ 2009-12-04 13:36 ` Wu Zhangjin
2009-12-04 8:11 ` Pavel Machek
2009-12-08 6:54 ` Wu Zhangjin
2009-12-04 13:37 ` [PATCH v7 7/8] Loongson: YeeLoong: add suspend support Wu Zhangjin
2009-12-04 13:39 ` [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
4 siblings, 2 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 13:36 UTC (permalink / raw)
To: Ralf Baechle, akpm, linux-mips, linux-kernel
Cc: Dmitry Torokhov, Pavel Machek, Rafael J. Wysocki, zhangfx,
linux-laptop, luming.yu, Wu Zhangjin
From: Wu Zhangjin <wuzhangjin@gmail.com>
This patch adds Video Output Driver, it provides standard
interface(/sys/class/video_output) to turn on/off the video output of
LCD, CRT.
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
drivers/platform/mips/Kconfig | 1 +
drivers/platform/mips/yeeloong_laptop.c | 147 +++++++++++++++++++++++++++++++
2 files changed, 148 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
index 9c8385c..4a89c01 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -21,6 +21,7 @@ config LEMOTE_YEELOONG2F
select SYS_SUPPORTS_APM_EMULATION
select APM_EMULATION
select HWMON
+ select VIDEO_OUTPUT_CONTROL
default m
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 644aaa7..8378926 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -16,6 +16,7 @@
#include <linux/apm-emulation.h>/* for battery subdriver */
#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>
@@ -397,6 +398,144 @@ 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);
+}
+
+static int lcd_video_output_set(struct output_device *od)
+{
+ int value;
+ unsigned long status;
+
+ status = !!od->request_state;
+
+ if (status == BIT_DISPLAY_LCD_ON) {
+ /* Turn on LCD */
+ outb(0x31, 0x3c4);
+ value = inb(0x3c5);
+ value = (value & 0xf8) | 0x03;
+ outb(0x31, 0x3c4);
+ outb(value, 0x3c5);
+ /* Turn on backlight */
+ ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_ON);
+ } else {
+ /* Turn off backlight */
+ ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_OFF);
+ /* Turn off LCD */
+ outb(0x31, 0x3c4);
+ value = inb(0x3c5);
+ value = (value & 0xf8) | 0x02;
+ outb(0x31, 0x3c4);
+ outb(value, 0x3c5);
+ }
+
+ 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)
+{
+ int value;
+ unsigned long status;
+
+ status = !!od->request_state;
+
+ if (status == BIT_CRT_DETECT_PLUG) {
+ if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) {
+ /* Turn on CRT */
+ outb(0x21, 0x3c4);
+ value = inb(0x3c5);
+ value &= ~(1 << 7);
+ outb(0x21, 0x3c4);
+ outb(value, 0x3c5);
+ }
+ } else {
+ /* Turn off CRT */
+ outb(0x21, 0x3c4);
+ value = inb(0x3c5);
+ value |= (1 << 7);
+ outb(0x21, 0x3c4);
+ outb(value, 0x3c5);
+ }
+
+ 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",
@@ -443,11 +582,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_battery_exit();
yeeloong_backlight_exit();
--
1.6.2.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7 7/8] Loongson: YeeLoong: add suspend support
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
` (2 preceding siblings ...)
2009-12-04 13:36 ` [PATCH v7 6/8] Loongson: YeeLoong: add video output driver Wu Zhangjin
@ 2009-12-04 13:37 ` Wu Zhangjin
2009-12-04 13:39 ` [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
4 siblings, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 13:37 UTC (permalink / raw)
To: Ralf Baechle, akpm, linux-mips, linux-kernel
Cc: Dmitry Torokhov, Pavel Machek, Rafael J. Wysocki, zhangfx,
linux-laptop, Wu Zhangjin
From: Wu Zhangjin <wuzhangjin@gmail.com>
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, 41 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c
index 8378926..d31824b 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -536,6 +536,45 @@ static void yeeloong_vo_exit(void)
}
}
+#ifdef CONFIG_LOONGSON_SUSPEND
+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 platform_device *dev, pm_message_t state)
+
+{
+ /* Turn off LCD */
+ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_OFF);
+ /* Turn off CRT */
+ yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG);
+ /* Poweroff three usb ports */
+ usb_ports_set(BIT_USB_FLAG_OFF);
+
+ return 0;
+}
+
+static int yeeloong_resume(struct platform_device *pdev)
+{
+ /* Resume the status of lcd & crt */
+ yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON);
+ yeeloong_crt_vo_set(BIT_CRT_DETECT_PLUG);
+
+ /* Poweron three usb ports */
+ usb_ports_set(BIT_USB_FLAG_ON);
+
+ return 0;
+}
+#else /* !CONFIG_LOONGSON_SUSPEND */
+#define yeeloong_suspend NULL
+#define yeeloong_resume NULL
+#endif
+
static struct platform_device_id platform_device_ids[] = {
{
.name = "yeeloong_laptop",
@@ -551,6 +590,8 @@ static struct platform_driver platform_driver = {
.owner = THIS_MODULE,
},
.id_table = platform_device_ids,
+ .suspend = yeeloong_suspend,
+ .resume = yeeloong_resume,
};
static int __init yeeloong_init(void)
--
1.6.2.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
` (3 preceding siblings ...)
2009-12-04 13:37 ` [PATCH v7 7/8] Loongson: YeeLoong: add suspend support Wu Zhangjin
@ 2009-12-04 13:39 ` Wu Zhangjin
2009-12-04 8:14 ` Pavel Machek
4 siblings, 1 reply; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 13:39 UTC (permalink / raw)
To: Ralf Baechle, akpm, linux-mips, linux-kernel
Cc: Dmitry Torokhov, Pavel Machek, Rafael J. Wysocki, zhangfx,
linux-laptop, linux-input, Wu Zhangjin
From: Wu Zhangjin <wuzhangjin@gmail.com>
This patch adds Hotkey Driver, which will do relative actions for The
hotkey event(/sys/class/input) and report the corresponding input keys
to the user-space applications.
Changes from the old revision:
- Rebase on the sparse keymap library from Dmitry Torokhov.
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/Kconfig | 1 +
drivers/platform/mips/yeeloong_laptop.c | 415 ++++++++++++++++++++++++
4 files changed, 430 insertions(+), 0 deletions(-)
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index ee8bc83..13e208e 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -43,6 +43,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 7ad47f2..617faee 100644
--- a/arch/mips/loongson/common/cmdline.c
+++ b/arch/mips/loongson/common/cmdline.c
@@ -17,6 +17,7 @@
* 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>
@@ -25,6 +26,10 @@ int prom_argc;
/* pmon passes arguments in 32bit pointers */
int *_prom_argv;
+/* 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 i;
@@ -51,4 +56,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/Kconfig b/drivers/platform/mips/Kconfig
index 4a89c01..7c81c4c 100644
--- a/drivers/platform/mips/Kconfig
+++ b/drivers/platform/mips/Kconfig
@@ -22,6 +22,7 @@ config LEMOTE_YEELOONG2F
select APM_EMULATION
select HWMON
select VIDEO_OUTPUT_CONTROL
+ select INPUT_SPARSEKMAP
default m
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 d31824b..d8cd94b 100644
--- a/drivers/platform/mips/yeeloong_laptop.c
+++ b/drivers/platform/mips/yeeloong_laptop.c
@@ -17,7 +17,14 @@
#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 <loongson.h> /* for loongson_cmdline */
#include <ec_kb3310b.h>
/* backlight subdriver */
@@ -536,6 +543,406 @@ 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_DISPLAY_TOGGLE, { 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 == BIT_CRT_DETECT_PLUG) {
+ 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;
+}
+
+#define EC_VER_LEN 64
+
+static int black_screen_handler(int status)
+{
+ 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';
+ }
+
+ /* Seems EC(>=PQ1D26) does this job for us, we can not do it again,
+ * otherwise, the brightness will not resume to the normal level! */
+ if (strncasecmp(ec_ver, "EC_VER=PQ1D26", 64) < 0)
+ yeeloong_lcd_vo_set(status);
+
+ return status;
+}
+
+static int display_toggle_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;
+}
+
+/* yeeloong_wifi_handler may be implemented in the wifi driver */
+sci_handler yeeloong_wifi_handler;
+EXPORT_SYMBOL(yeeloong_wifi_handler);
+
+#define NO_REG 0
+#define NO_HANDLER NULL
+/* 2 maybe used to indicate the key as a switch button, such as EVENT_WLAN */
+#define NO_STATUS 2
+
+static void do_event_action(int event)
+{
+ sci_handler handler;
+ int reg, status;
+ struct key_entry *ke;
+
+ reg = NO_REG;
+ handler = NO_HANDLER;
+ status = NO_STATUS;
+
+ switch (event) {
+ case EVENT_LID:
+ reg = REG_LID_DETECT;
+ break;
+ case EVENT_DISPLAY_TOGGLE:
+ handler = display_toggle_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_BLACK_SCREEN:
+ reg = REG_DISPLAY_LCD;
+ handler = black_screen_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;
+ case EVENT_WLAN:
+ handler = yeeloong_wifi_handler;
+ break;
+ default:
+ break;
+ }
+
+ if (reg != NO_REG)
+ status = ec_read(reg);
+
+ if (handler != NO_HANDLER)
+ 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_LOONGSON_SUSPEND
static void usb_ports_set(int status)
{
@@ -630,11 +1037,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_battery_exit();
--
1.6.2.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v7 4/8] Loongson: YeeLoong: add battery driver
2009-12-04 8:04 ` Pavel Machek
@ 2009-12-04 14:56 ` Wu Zhangjin
0 siblings, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 14:56 UTC (permalink / raw)
To: Pavel Machek
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, Stephen Rothwell, linux-laptop,
Hongbing Hu
On Fri, 2009-12-04 at 09:04 +0100, Pavel Machek wrote:
> On Fri 2009-12-04 21:34:17, Wu Zhangjin wrote:
> > From: Wu Zhangjin <wuzhangjin@gmail.com>
> >
> > This patch adds APM emulated Battery Driver, it provides standard
> > interface(/proc/apm) for user-space applications(e.g. kpowersave,
> > gnome-power-manager) to manage the battery.
>
> It would be nicer if this went to drivers/power, and used its
> interface -- providing not only percentage but also other values.
There is a version basic on the power supply interface, but it is buggy.
Regards,
Wu Zhangjin
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver
2009-12-04 8:14 ` Pavel Machek
@ 2009-12-04 14:57 ` Wu Zhangjin
0 siblings, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 14:57 UTC (permalink / raw)
To: Pavel Machek
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop, linux-input
On Fri, 2009-12-04 at 09:14 +0100, Pavel Machek wrote:
> Hi!
>
>
> > +#define NO_REG 0
> > +#define NO_HANDLER NULL
>
> Don't obfuscate code like that.
Will remove it later, thanks!
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 6/8] Loongson: YeeLoong: add video output driver
2009-12-04 8:11 ` Pavel Machek
@ 2009-12-04 15:04 ` Wu Zhangjin
0 siblings, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 15:04 UTC (permalink / raw)
To: Pavel Machek
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop, luming.yu
On Fri, 2009-12-04 at 09:11 +0100, Pavel Machek wrote:
> On Fri 2009-12-04 21:36:43, Wu Zhangjin wrote:
> > From: Wu Zhangjin <wuzhangjin@gmail.com>
> >
> > This patch adds Video Output Driver, it provides standard
> > interface(/sys/class/video_output) to turn on/off the video output of
> > LCD, CRT.
> >
>
> > diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
> > index 9c8385c..4a89c01 100644
> > --- a/drivers/platform/mips/Kconfig
> > +++ b/drivers/platform/mips/Kconfig
> > @@ -21,6 +21,7 @@ config LEMOTE_YEELOONG2F
> > select SYS_SUPPORTS_APM_EMULATION
> > select APM_EMULATION
> > select HWMON
> > + select VIDEO_OUTPUT_CONTROL
> > default m
> > help
> > YeeLoong netbook is a mini laptop made by Lemote, which is basically
>
> default m is evil.
>
why? this module can be loaded automatically, so, I let it be a module
by default.
> > + if (status == BIT_DISPLAY_LCD_ON) {
> > + /* Turn on LCD */
> > + outb(0x31, 0x3c4);
> > + value = inb(0x3c5);
> > + value = (value & 0xf8) | 0x03;
> > + outb(0x31, 0x3c4);
> > + outb(value, 0x3c5);
> > + /* Turn on backlight */
> > + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_ON);
> > + } else {
> > + /* Turn off backlight */
> > + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_OFF);
> > + /* Turn off LCD */
> > + outb(0x31, 0x3c4);
> > + value = inb(0x3c5);
> > + value = (value & 0xf8) | 0x02;
> > + outb(0x31, 0x3c4);
> > + outb(value, 0x3c5);
> > + }
>
> IIRC this is opencoded in suspend support; should that get common
> helpers?
>
> > + if (status == BIT_CRT_DETECT_PLUG) {
> > + if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) {
> > + /* Turn on CRT */
> > + outb(0x21, 0x3c4);
> > + value = inb(0x3c5);
> > + value &= ~(1 << 7);
> > + outb(0x21, 0x3c4);
> > + outb(value, 0x3c5);
> > + }
> > + } else {
> > + /* Turn off CRT */
> > + outb(0x21, 0x3c4);
> > + value = inb(0x3c5);
> > + value |= (1 << 7);
> > + outb(0x21, 0x3c4);
> > + outb(value, 0x3c5);
> > + }
>
> This looks suspiciously similar to one another and to code
> above. Perhaps some more helpers?
>
Yes, lots of duplicated source code above, thanks!
Regards,
Wu Zhangjin
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver
2009-12-04 8:08 ` Pavel Machek
@ 2009-12-04 16:29 ` Wu Zhangjin
0 siblings, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-04 16:29 UTC (permalink / raw)
To: Pavel Machek
Cc: Ralf Baechle, akpm, linux-mips, linux-kernel, Dmitry Torokhov,
Rafael J. Wysocki, zhangfx, linux-laptop
On Fri, 2009-12-04 at 09:08 +0100, Pavel Machek wrote:
> Hi!
>
> > +static int get_cpu_temp(void)
> > +{
> > + int value;
> > +
> > + value = ec_read(REG_TEMPERATURE_VALUE);
> > +
> > + if (value & (1 << 7))
> > + value = (value & 0x7f) - 128;
> > + else
> > + value = value & 0xff;
>
> wtf?
>
> Maybe value should be 's8'?
>
> > +static int get_battery_current(void)
> > +{
> > + int value;
> > +
> > + value = (ec_read(REG_BAT_CURRENT_HIGH) << 8) |
> > + (ec_read(REG_BAT_CURRENT_LOW));
> > +
> > + if (value & 0x8000)
> > + value = 0xffff - value;
>
> Another version of pair-complement conversion; this one is broken --
> off by 1.
>
> > +static int parse_arg(const char *buf, unsigned long count, int *val)
> > +{
> > + if (!count)
> > + return 0;
> > + if (sscanf(buf, "%i", val) != 1)
> > + return -EINVAL;
> > + return count;
> > +}
>
> We have strict_strtoul for a reason...
>
Done, thanks!
Regards,
Wu Zhangjin
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 6/8] Loongson: YeeLoong: add video output driver
2009-12-04 13:36 ` [PATCH v7 6/8] Loongson: YeeLoong: add video output driver Wu Zhangjin
2009-12-04 8:11 ` Pavel Machek
@ 2009-12-08 6:54 ` Wu Zhangjin
1 sibling, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-08 6:54 UTC (permalink / raw)
To: Ralf Baechle
Cc: akpm, linux-mips, linux-kernel, Dmitry Torokhov, Pavel Machek,
Rafael J. Wysocki, zhangfx, linux-laptop, luming.yu
Hi, Pavel
Can I get your Acked-by: for this patch?
Thanks!
Wu Zhangjin
On Fri, 2009-12-04 at 21:36 +0800, Wu Zhangjin wrote:
> From: Wu Zhangjin <wuzhangjin@gmail.com>
>
> This patch adds Video Output Driver, it provides standard
> interface(/sys/class/video_output) to turn on/off the video output of
> LCD, CRT.
>
> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> ---
> drivers/platform/mips/Kconfig | 1 +
> drivers/platform/mips/yeeloong_laptop.c | 147 +++++++++++++++++++++++++++++++
> 2 files changed, 148 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
> index 9c8385c..4a89c01 100644
> --- a/drivers/platform/mips/Kconfig
> +++ b/drivers/platform/mips/Kconfig
> @@ -21,6 +21,7 @@ config LEMOTE_YEELOONG2F
> select SYS_SUPPORTS_APM_EMULATION
> select APM_EMULATION
> select HWMON
> + select VIDEO_OUTPUT_CONTROL
> default m
> 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 644aaa7..8378926 100644
> --- a/drivers/platform/mips/yeeloong_laptop.c
> +++ b/drivers/platform/mips/yeeloong_laptop.c
> @@ -16,6 +16,7 @@
> #include <linux/apm-emulation.h>/* for battery subdriver */
> #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>
>
> @@ -397,6 +398,144 @@ 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);
> +}
> +
> +static int lcd_video_output_set(struct output_device *od)
> +{
> + int value;
> + unsigned long status;
> +
> + status = !!od->request_state;
> +
> + if (status == BIT_DISPLAY_LCD_ON) {
> + /* Turn on LCD */
> + outb(0x31, 0x3c4);
> + value = inb(0x3c5);
> + value = (value & 0xf8) | 0x03;
> + outb(0x31, 0x3c4);
> + outb(value, 0x3c5);
> + /* Turn on backlight */
> + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_ON);
> + } else {
> + /* Turn off backlight */
> + ec_write(REG_BACKLIGHT_CTRL, BIT_BACKLIGHT_OFF);
> + /* Turn off LCD */
> + outb(0x31, 0x3c4);
> + value = inb(0x3c5);
> + value = (value & 0xf8) | 0x02;
> + outb(0x31, 0x3c4);
> + outb(value, 0x3c5);
> + }
> +
> + 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)
> +{
> + int value;
> + unsigned long status;
> +
> + status = !!od->request_state;
> +
> + if (status == BIT_CRT_DETECT_PLUG) {
> + if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) {
> + /* Turn on CRT */
> + outb(0x21, 0x3c4);
> + value = inb(0x3c5);
> + value &= ~(1 << 7);
> + outb(0x21, 0x3c4);
> + outb(value, 0x3c5);
> + }
> + } else {
> + /* Turn off CRT */
> + outb(0x21, 0x3c4);
> + value = inb(0x3c5);
> + value |= (1 << 7);
> + outb(0x21, 0x3c4);
> + outb(value, 0x3c5);
> + }
> +
> + 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",
> @@ -443,11 +582,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_battery_exit();
> yeeloong_backlight_exit();
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v7 4/8] Loongson: YeeLoong: add battery driver
2009-12-04 13:34 ` [PATCH v7 4/8] Loongson: YeeLoong: add battery driver Wu Zhangjin
2009-12-04 8:04 ` Pavel Machek
@ 2009-12-08 6:57 ` Wu Zhangjin
1 sibling, 0 replies; 15+ messages in thread
From: Wu Zhangjin @ 2009-12-08 6:57 UTC (permalink / raw)
To: Pavel Machek
Cc: akpm, linux-mips, linux-kernel, Dmitry Torokhov, Pavel Machek,
Rafael J. Wysocki, zhangfx, Stephen Rothwell, linux-laptop,
Ralf Baechle
Hi, Pavel
Seems you have reviewed this patch, can I get your Acked-by:?
Thanks!
Wu Zhangjin
On Fri, 2009-12-04 at 21:34 +0800, Wu Zhangjin wrote:
> From: Wu Zhangjin <wuzhangjin@gmail.com>
>
> This patch adds APM emulated Battery Driver, it provides standard
> interface(/proc/apm) for user-space applications(e.g. kpowersave,
> gnome-power-manager) to manage the battery.
>
> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> ---
> drivers/platform/mips/Kconfig | 2 +
> drivers/platform/mips/yeeloong_laptop.c | 104 +++++++++++++++++++++++++++++++
> 2 files changed, 106 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig
> index f7a3705..0c6b5ad 100644
> --- a/drivers/platform/mips/Kconfig
> +++ b/drivers/platform/mips/Kconfig
> @@ -18,6 +18,8 @@ config LEMOTE_YEELOONG2F
> tristate "Lemote YeeLoong Laptop"
> depends on LEMOTE_MACH2F
> select BACKLIGHT_CLASS_DEVICE
> + select SYS_SUPPORTS_APM_EMULATION
> + select APM_EMULATION
> default m
> 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 fbc4ebb..729e368 100644
> --- a/drivers/platform/mips/yeeloong_laptop.c
> +++ b/drivers/platform/mips/yeeloong_laptop.c
> @@ -13,6 +13,7 @@
> #include <linux/platform_device.h>
> #include <linux/backlight.h> /* for backlight subdriver */
> #include <linux/fb.h>
> +#include <linux/apm-emulation.h>/* for battery subdriver */
>
> #include <ec_kb3310b.h>
>
> @@ -83,6 +84,106 @@ static void yeeloong_backlight_exit(void)
> }
> }
>
> +/* battery subdriver */
> +
> +static void get_fixed_battery_info(void)
> +{
> + int design_cap, full_charged_cap, design_vol, vendor, cell_count;
> +
> + design_cap = (ec_read(REG_BAT_DESIGN_CAP_HIGH) << 8)
> + | ec_read(REG_BAT_DESIGN_CAP_LOW);
> + full_charged_cap = (ec_read(REG_BAT_FULLCHG_CAP_HIGH) << 8)
> + | ec_read(REG_BAT_FULLCHG_CAP_LOW);
> + design_vol = (ec_read(REG_BAT_DESIGN_VOL_HIGH) << 8)
> + | ec_read(REG_BAT_DESIGN_VOL_LOW);
> + vendor = ec_read(REG_BAT_VENDOR);
> + cell_count = ec_read(REG_BAT_CELL_COUNT);
> +
> + if (vendor != 0) {
> + pr_info("battery vendor(%s), cells count(%d), "
> + "with designed capacity(%d),designed voltage(%d),"
> + " full charged capacity(%d)\n",
> + (vendor ==
> + FLAG_BAT_VENDOR_SANYO) ? "SANYO" : "SIMPLO",
> + (cell_count == FLAG_BAT_CELL_3S1P) ? 3 : 6,
> + design_cap, design_vol,
> + full_charged_cap);
> + }
> +}
> +
> +#define APM_CRITICAL 5
> +
> +static void get_power_status(struct apm_power_info *info)
> +{
> + unsigned char bat_status;
> +
> + info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
> + info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
> + info->units = APM_UNITS_MINS;
> +
> + info->battery_life = (ec_read(REG_BAT_RELATIVE_CAP_HIGH) << 8) |
> + (ec_read(REG_BAT_RELATIVE_CAP_LOW));
> +
> + info->ac_line_status = (ec_read(REG_BAT_POWER) & BIT_BAT_POWER_ACIN) ?
> + APM_AC_ONLINE : APM_AC_OFFLINE;
> +
> + bat_status = ec_read(REG_BAT_STATUS);
> +
> + if (!(bat_status & BIT_BAT_STATUS_IN)) {
> + /* no battery inserted */
> + info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
> + info->battery_flag = APM_BATTERY_FLAG_NOT_PRESENT;
> + info->time = 0x00;
> + return;
> + }
> +
> + /* adapter inserted */
> + if (info->ac_line_status == APM_AC_ONLINE) {
> + if (!(bat_status & BIT_BAT_STATUS_FULL)) {
> + /* battery is not fully charged */
> + info->battery_status = APM_BATTERY_STATUS_CHARGING;
> + info->battery_flag = APM_BATTERY_FLAG_CHARGING;
> + } else {
> + /* battery is fully charged */
> + info->battery_status = APM_BATTERY_STATUS_HIGH;
> + info->battery_flag = APM_BATTERY_FLAG_HIGH;
> + info->battery_life = 100;
> + }
> + } else {
> + /* battery is too low */
> + if (bat_status & BIT_BAT_STATUS_LOW) {
> + info->battery_status = APM_BATTERY_STATUS_LOW;
> + info->battery_flag = APM_BATTERY_FLAG_LOW;
> + if (info->battery_life <= APM_CRITICAL) {
> + /* we should power off the system now */
> + info->battery_status =
> + APM_BATTERY_STATUS_CRITICAL;
> + info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
> + }
> + } else {
> + /* assume the battery is high enough. */
> + info->battery_status = APM_BATTERY_STATUS_HIGH;
> + info->battery_flag = APM_BATTERY_FLAG_HIGH;
> + }
> + }
> + info->time = ((info->battery_life - 3) * 54 + 142) / 60;
> +}
> +
> +static int yeeloong_battery_init(void)
> +{
> + get_fixed_battery_info();
> +
> + apm_get_power_status = get_power_status;
> +
> + return 0;
> +}
> +
> +static void yeeloong_battery_exit(void)
> +{
> + if (apm_get_power_status == get_power_status)
> + apm_get_power_status = NULL;
> +}
> +
> static struct platform_device_id platform_device_ids[] = {
> {
> .name = "yeeloong_laptop",
> @@ -120,11 +221,14 @@ static int __init yeeloong_init(void)
> return ret;
> }
>
> + yeeloong_battery_init();
> +
> return 0;
> }
>
> static void __exit yeeloong_exit(void)
> {
> + yeeloong_battery_exit();
> yeeloong_backlight_exit();
> platform_driver_unregister(&platform_driver);
>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2009-12-08 6:57 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <cover.1259932036.git.wuzhangjin@gmail.com>
2009-12-04 13:34 ` [PATCH v7 4/8] Loongson: YeeLoong: add battery driver Wu Zhangjin
2009-12-04 8:04 ` Pavel Machek
2009-12-04 14:56 ` Wu Zhangjin
2009-12-08 6:57 ` Wu Zhangjin
2009-12-04 13:35 ` [PATCH v7 5/8] Loongson: YeeLoong: add hardware monitoring driver Wu Zhangjin
2009-12-04 8:08 ` Pavel Machek
2009-12-04 16:29 ` Wu Zhangjin
2009-12-04 13:36 ` [PATCH v7 6/8] Loongson: YeeLoong: add video output driver Wu Zhangjin
2009-12-04 8:11 ` Pavel Machek
2009-12-04 15:04 ` Wu Zhangjin
2009-12-08 6:54 ` Wu Zhangjin
2009-12-04 13:37 ` [PATCH v7 7/8] Loongson: YeeLoong: add suspend support Wu Zhangjin
2009-12-04 13:39 ` [PATCH v7 8/8] Loongson: YeeLoong: add input/hotkey driver Wu Zhangjin
2009-12-04 8:14 ` Pavel Machek
2009-12-04 14:57 ` Wu Zhangjin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox