LynLoong PC is an AllINONE machine made by Lemote, which is basically
compatible to FuLoong2F Mini PC, the only difference is that it has a
size-fixed screen: 1360x768 with sisfb video driver. and also, it has
its own specific suspend support(e.g. suspend/resume the display, the
external clocks.).
This patch adds the backlight subdriver and platform specific suspend
support for LynLoong(ALLINONE) PC. And also, a kernel command line
argument "video=sisfb:1360x768-16@60" is appended for the size-fixed
display.
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
.../mips/include/asm/mach-loongson/cs5536/cs5536.h | 35 ++
.../asm/mach-loongson/cs5536/cs5536_mfgpt.h | 5 +
arch/mips/loongson/Kconfig | 35 ++
arch/mips/loongson/common/cmdline.c | 10 +
arch/mips/loongson/lemote-2f/Makefile | 5 +
arch/mips/loongson/lemote-2f/lynloong_pc.c | 609 ++++++++++++++++++++
6 files changed, 699 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/loongson/lemote-2f/lynloong_pc.c
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
index 021f77c..1cf86f3 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536.h
@@ -301,5 +301,40 @@ extern void _wrmsr(u32 msr, u32 hi, u32 lo);
/* GPIO : I/O SPACE; REG : 32BITS */
#define GPIOL_OUT_VAL 0x00
#define GPIOL_OUT_EN 0x04
+#define GPIOL_OUT_AUX1_SEL 0x10
+/* SMB : I/O SPACE, REG : 8BITS WIDTH */
+#define SMB_SDA 0x00
+#define SMB_STS 0x01
+#define SMB_STS_SLVSTP (1 << 7)
+#define SMB_STS_SDAST (1 << 6)
+#define SMB_STS_BER (1 << 5)
+#define SMB_STS_NEGACK (1 << 4)
+#define SMB_STS_STASTR (1 << 3)
+#define SMB_STS_NMATCH (1 << 2)
+#define SMB_STS_MASTER (1 << 1)
+#define SMB_STS_XMIT (1 << 0)
+#define SMB_CTRL_STS 0x02
+#define SMB_CSTS_TGSTL (1 << 5)
+#define SMB_CSTS_TSDA (1 << 4)
+#define SMB_CSTS_GCMTCH (1 << 3)
+#define SMB_CSTS_MATCH (1 << 2)
+#define SMB_CSTS_BB (1 << 1)
+#define SMB_CSTS_BUSY (1 << 0)
+#define SMB_CTRL1 0x03
+#define SMB_CTRL1_STASTRE (1 << 7)
+#define SMB_CTRL1_NMINTE (1 << 6)
+#define SMB_CTRL1_GCMEN (1 << 5)
+#define SMB_CTRL1_ACK (1 << 4)
+#define SMB_CTRL1_RSVD (1 << 3)
+#define SMB_CTRL1_INTEN (1 << 2)
+#define SMB_CTRL1_STOP (1 << 1)
+#define SMB_CTRL1_START (1 << 0)
+#define SMB_ADDR 0x04
+#define SMB_ADDR_SAEN (1 << 7)
+#define SMB_CONTROLLER_ADDR (0xef << 0)
+#define SMB_CTRL2 0x05
+#define SMB_FREQ (0x20 << 1)
+#define SMB_ENABLE (0x01 << 0)
+#define SMB_CTRL3 0x06
#endif /* _CS5536_H */
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
index 4b493d6..cac04ee 100644
--- a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
@@ -32,4 +32,9 @@ static inline void __maybe_unused enable_mfgpt0_counter(void)
#define MFGPT0_CNT (MFGPT_BASE + 4)
#define MFGPT0_SETUP (MFGPT_BASE + 6)
+#define MFGPT2_CMP1 (MFGPT_BASE + 0x10)
+#define MFGPT2_CMP2 (MFGPT_BASE + 0x12)
+#define MFGPT2_CNT (MFGPT_BASE + 0x14)
+#define MFGPT2_SETUP (MFGPT_BASE + 0x16)
+
#endif /*!_CS5536_MFGPT_H */
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 7a86987..1041336 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -78,3 +78,38 @@ config LOONGSON_SUSPEND
bool
default y
depends on CPU_SUPPORTS_CPUFREQ && SUSPEND
+
+#
+# Loongson Platform Specific Drivers
+#
+
+comment "Loongson Platform Specific Drivers"
+
+menuconfig LOONGSON_PLATFORM_DEVICES
+ bool "Loongson Platform Specific Drivers"
+ default y
+ ---help---
+ Say Y here to get to see options for device drivers for various
+ loongson platforms, including vendor-specific 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 LOONGSON_PLATFORM_DEVICES
+
+config LEMOTE_LYNLOONG2F_PDEV
+ tristate "Lemote LynLoong(Allinone) Platform Specific Driver"
+ depends on LEMOTE_MACH2F
+ select THERMAL
+ select BACKLIGHT_CLASS_DEVICE
+ default m
+ help
+ LynLoong PC is an AllINONE machine made by Lemote, which is basically
+ compatible to FuLoong2F Mini PC, the only difference is that it has a
+ size-fixed screen: 1360x768 with sisfb video driver. and also, it has
+ its own specific suspend support.
+
+ This driver adds the lynloong specific backlight driver and platform
+ driver(mainly the suspend support).
+
+endif # LOONGSON_PLATFORM_DEVICES
diff --git a/arch/mips/loongson/common/cmdline.c
b/arch/mips/loongson/common/cmdline.c
index 7ad47f2..13ce9b1 100644
--- a/arch/mips/loongson/common/cmdline.c
+++ b/arch/mips/loongson/common/cmdline.c
@@ -51,4 +51,14 @@ void __init prom_init_cmdline(void)
strcat(arcs_cmdline, " root=/dev/hda1");
prom_init_machtype();
+
+ /* append machine specific command line */
+ switch (mips_machtype) {
+ case MACH_LEMOTE_LL2F:
+ if ((strstr(arcs_cmdline, "video=")) == NULL)
+ strcat(arcs_cmdline, " video=sisfb:1360x768-16@60");
+ break;
+ default:
+ break;
+ }
}
diff --git a/arch/mips/loongson/lemote-2f/Makefile
b/arch/mips/loongson/lemote-2f/Makefile
index 5add7b2..ad9e287 100644
--- a/arch/mips/loongson/lemote-2f/Makefile
+++ b/arch/mips/loongson/lemote-2f/Makefile
@@ -9,3 +9,8 @@ obj-y += irq.o reset.o
#
obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
+
+#
+# Platform Drivers
+#
+obj-$(CONFIG_LEMOTE_LYNLOONG2F_PDEV) += lynloong_pc.o
diff --git a/arch/mips/loongson/lemote-2f/lynloong_pc.c
b/arch/mips/loongson/lemote-2f/lynloong_pc.c
new file mode 100644
index 0000000..5e84288
--- /dev/null
+++ b/arch/mips/loongson/lemote-2f/lynloong_pc.c
@@ -0,0 +1,609 @@
+/*
+ * Driver for LynLoong pc extras
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Xiang Yu <xiangy@lemote.com>
+ * Wu Zhangjin <wuzj@lemote.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/thermal.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+#include <cs5536/cs5536_mfgpt.h>
+
+static u32 gpio_base, smb_base, mfgpt_base;
+
+/* gpio operations */
+static void set_gpio_reg_high(int gpio, int reg)
+{
+ u32 val;
+
+ val = inl(gpio_base + reg);
+ val |= (1 << gpio);
+ val &= ~(1 << (16 + gpio));
+ outl(val, gpio_base + reg);
+ mmiowb();
+}
+
+static void set_gpio_reg_low(int gpio, int reg)
+{
+ u32 val;
+
+ val = inl(gpio_base + reg);
+ val |= (1 << (16 + gpio));
+ val &= ~(1 << gpio);
+ outl(val, gpio_base + reg);
+ mmiowb();
+}
+
+static void set_gpio_output_low(int gpio)
+{
+ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
+ set_gpio_reg_low(gpio, GPIOL_OUT_VAL);
+}
+
+static void set_gpio_output_high(int gpio)
+{
+ set_gpio_reg_high(gpio, GPIOL_OUT_EN);
+ set_gpio_reg_high(gpio, GPIOL_OUT_VAL);
+}
+
+/* backlight subdriver */
+
+#define MAX_BRIGHTNESS 100
+#define DEFAULT_BRIGHTNESS 50
+#define MIN_BRIGHTNESS 0
+static uint level;
+
+/* tune the brightness */
+static void setup_mfgpt2(void)
+{
+ /* set MFGPT2 comparator 1,2 */
+ outw(MAX_BRIGHTNESS-level, MFGPT2_CMP1);
+ outw(MAX_BRIGHTNESS, MFGPT2_CMP2);
+ /* clear MFGPT2 UP COUNTER */
+ outw(0, MFGPT2_CNT);
+ /* enable counter, compare mode, 32k */
+ outw(0x8280, MFGPT2_SETUP);
+}
+
+static int lynloong_set_brightness(struct backlight_device *bd)
+{
+ uint i;
+
+ 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 < MIN_BRIGHTNESS)
+ level = MIN_BRIGHTNESS;
+
+ if (level == 0) {
+ /* turn off the backlight */
+ set_gpio_output_low(11);
+ for (i = 0; i < 0x500; i++)
+ delay();
+ /* turn off the LCD */
+ set_gpio_output_high(8);
+ } else {
+ /* turn on the LCD */
+ set_gpio_output_low(8);
+ for (i = 0; i < 0x500; i++)
+ delay();
+ /* turn on the backlight */
+ set_gpio_output_high(11);
+ }
+
+ setup_mfgpt2();
+
+ return 0;
+}
+
+static int lynloong_get_brightness(struct backlight_device *bd)
+{
+ return level;
+}
+
+static struct backlight_ops backlight_ops = {
+ .get_brightness = lynloong_get_brightness,
+ .update_status = lynloong_set_brightness,
+};
+
+static struct backlight_device *lynloong_backlight_dev;
+
+static void lynloong_backlight_exit(void)
+{
+ if (lynloong_backlight_dev) {
+ backlight_device_unregister(lynloong_backlight_dev);
+ lynloong_backlight_dev = NULL;
+ }
+ /* disable brightness controlling */
+ set_gpio_output_low(7);
+
+ printk(KERN_INFO "exit from LingLoong Backlight Driver");
+}
+
+static int __init lynloong_backlight_init(struct device *dev)
+{
+ int ret;
+
+ /* select for mfgpt */
+ set_gpio_reg_high(7, GPIOL_OUT_AUX1_SEL);
+ /* enable brightness controlling */
+ set_gpio_output_high(7);
+
+ lynloong_backlight_dev =
+ backlight_device_register("backlight0", dev, NULL,
+ &backlight_ops);
+
+ if (IS_ERR(lynloong_backlight_dev)) {
+ ret = PTR_ERR(lynloong_backlight_dev);
+ return ret;
+ }
+
+ lynloong_backlight_dev->props.max_brightness = MAX_BRIGHTNESS;
+ lynloong_backlight_dev->props.brightness = DEFAULT_BRIGHTNESS;
+ backlight_update_status(lynloong_backlight_dev);
+
+ return 0;
+}
+
+/* Thermal cooling devices subdriver */
+
+static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
+{
+ *state = MAX_BRIGHTNESS;
+ return 0;
+}
+
+static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
+{
+ static struct backlight_device *bd;
+
+ bd = (struct backlight_device *)cdev->devdata;
+
+ *state = lynloong_get_brightness(bd);
+
+ return 0;
+}
+
+static int video_set_cur_state(struct thermal_cooling_device *cdev, unsigned
+ long state)
+{
+ static struct backlight_device *bd;
+
+ bd = (struct backlight_device *)cdev->devdata;
+
+ lynloong_backlight_dev->props.brightness = state;
+ backlight_update_status(bd);
+
+ return 0;
+}
+
+static struct thermal_cooling_device_ops video_cooling_ops = {
+ .get_max_state = video_get_max_state,
+ .get_cur_state = video_get_cur_state,
+ .set_cur_state = video_set_cur_state,
+};
+
+static struct thermal_cooling_device *lynloong_thermal_cdev;
+
+/* TODO: register cpu as the cooling devices */
+static int lynloong_thermal_init(struct device *dev)
+{
+ int ret;
+
+ if (!dev)
+ return -1;
+
+ lynloong_thermal_cdev = thermal_cooling_device_register("LCD", dev,
+ &video_cooling_ops);
+
+ if (IS_ERR(lynloong_thermal_cdev)) {
+ ret = PTR_ERR(lynloong_thermal_cdev);
+ return ret;
+ }
+
+ ret = sysfs_create_link(&dev->kobj,
+ &lynloong_thermal_cdev->device.kobj,
+ "thermal_cooling");
+ if (ret) {
+ printk(KERN_ERR "Create sysfs link\n");
+ return ret;
+ }
+ ret = sysfs_create_link(&lynloong_thermal_cdev->device.kobj,
+ &dev->kobj, "device");
+ if (ret) {
+ printk(KERN_ERR "Create sysfs link\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void lynloong_thermal_exit(struct device *dev)
+{
+ if (lynloong_thermal_cdev) {
+ if (dev)
+ sysfs_remove_link(&dev->kobj, "thermal_cooling");
+ sysfs_remove_link(&lynloong_thermal_cdev->device.kobj,
+ "device");
+ thermal_cooling_device_unregister(lynloong_thermal_cdev);
+ lynloong_thermal_cdev = NULL;
+ }
+}
+
+/* platform subdriver */
+
+/* I2C operations */
+
+static int i2c_wait(void)
+{
+ char c;
+ int i;
+
+ udelay(1000);
+ for (i = 0; i < 20; i++) {
+ c = inb(smb_base | SMB_STS);
+ if (c & (SMB_STS_BER | SMB_STS_NEGACK))
+ return -1;
+ if (c & SMB_STS_SDAST)
+ return 0;
+ udelay(100);
+ }
+ return -2;
+}
+
+static void i2c_read_single(int addr, int regNo, char *value)
+{
+ unsigned char c;
+
+ /* Start condition */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
+ i2c_wait();
+
+ /* Send slave address */
+ outb(addr & 0xfe, smb_base | SMB_SDA);
+ i2c_wait();
+
+ /* Acknowledge smbus */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
+
+ /* Send register index */
+ outb(regNo, smb_base | SMB_SDA);
+ i2c_wait();
+
+ /* Acknowledge smbus */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
+
+ /* Start condition again */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
+ i2c_wait();
+
+ /* Send salve address again */
+ outb(1 | addr, smb_base | SMB_SDA);
+ i2c_wait();
+
+ /* Acknowledge smbus */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_ACK, smb_base | SMB_CTRL1);
+
+ /* Read data */
+ *value = inb(smb_base | SMB_SDA);
+
+ /* Stop condition */
+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
+ i2c_wait();
+}
+
+static void i2c_write_single(int addr, int regNo, char value)
+{
+ unsigned char c;
+
+ /* Start condition */
+ c = inb(smb_base | SMB_CTRL1);
+ outb(c | SMB_CTRL1_START, smb_base | SMB_CTRL1);
+ i2c_wait();
+ /* Send slave address */
+ outb(addr & 0xfe, smb_base | SMB_SDA);
+ i2c_wait();;
+
+ /* Send register index */
+ outb(regNo, smb_base | SMB_SDA);
+ i2c_wait();
+
+ /* Write data */
+ outb(value, smb_base | SMB_SDA);
+ i2c_wait();
+ /* Stop condition */
+ outb(SMB_CTRL1_STOP, smb_base | SMB_CTRL1);
+ i2c_wait();
+}
+
+static void stop_clock(int clk_reg, int clk_sel)
+{
+ u8 value;
+
+ i2c_read_single(0xd3, clk_reg, &value);
+ value &= ~(1 << clk_sel);
+ i2c_write_single(0xd2, clk_reg, value);
+}
+
+static void enable_clock(int clk_reg, int clk_sel)
+{
+ u8 value;
+
+ i2c_read_single(0xd3, clk_reg, &value);
+ value |= (1 << clk_sel);
+ i2c_write_single(0xd2, clk_reg, value);
+}
+
+static char cached_clk_freq;
+static char cached_pci_fixed_freq;
+
+static void decrease_clk_freq(void)
+{
+ char value;
+
+ i2c_read_single(0xd3, 1, &value);
+ cached_clk_freq = value;
+
+ /* select frequency by software */
+ value |= (1 << 1);
+ /* CPU, 3V66, PCI : 100, 66, 33(1) */
+ value |= (1 << 2);
+ i2c_write_single(0xd2, 1, value);
+
+ /* cache the pci frequency */
+ i2c_read_single(0xd3, 14, &value);
+ cached_pci_fixed_freq = value;
+
+ /* enable PCI fix mode */
+ value |= (1 << 5);
+ /* 3V66, PCI : 64MHz, 32MHz */
+ value |= (1 << 3);
+ i2c_write_single(0xd2, 14, value);
+
+}
+
+static void resume_clk_freq(void)
+{
+ i2c_write_single(0xd2, 1, cached_clk_freq);
+ i2c_write_single(0xd2, 14, cached_pci_fixed_freq);
+}
+
+static void stop_clocks(void)
+{
+ /* CPU Clock Register */
+ stop_clock(2, 5); /* not used */
+ stop_clock(2, 6); /* not used */
+ stop_clock(2, 7); /* not used */
+
+ /* PCI Clock Register */
+ stop_clock(3, 1); /* 8100 */
+ stop_clock(3, 5); /* SIS */
+ stop_clock(3, 0); /* not used */
+ stop_clock(3, 6); /* not used */
+
+ /* PCI 48M Clock Register */
+ stop_clock(4, 6); /* USB grounding */
+ stop_clock(4, 5); /* REF(5536_14M) */
+
+ /* 3V66 Control Register */
+ stop_clock(5, 0); /* VCH_CLK..., grounding */
+}
+static void enable_clocks(void)
+{
+ enable_clock(3, 1); /* 8100 */
+ enable_clock(3, 5); /* SIS */
+
+ enable_clock(4, 6);
+ enable_clock(4, 5); /* REF(5536_14M) */
+
+ enable_clock(5, 0); /* VCH_CLOCK, grounding */
+}
+
+static struct platform_device *lynloong_pdev;
+
+static int __maybe_unused lynloong_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int i;
+
+ printk(KERN_INFO "lynloong specific suspend\n");
+
+ /* disable AMP */
+ set_gpio_output_high(6);
+ /* disable the brightness control */
+ set_gpio_output_low(7);
+ /* disable the backlight output */
+ set_gpio_output_low(11);
+
+ /* stop the clocks of some devices */
+ stop_clocks();
+
+ /* decrease the external clock frequency */
+ decrease_clk_freq();
+
+ /* turn off the LCD */
+ for (i = 0; i < 0x600; i++)
+ delay();
+ set_gpio_output_high(8);
+
+ return 0;
+}
+
+static int __maybe_unused lynloong_resume(struct platform_device *pdev)
+{
+ int i;
+
+ printk(KERN_INFO "lynloong specific resume\n");
+
+ /* turn on the LCD */
+ set_gpio_output_low(8);
+ for (i = 0; i < 0x1000; i++)
+ delay();
+
+ /* resume clock frequency, enable the relative clocks */
+ resume_clk_freq();
+ enable_clocks();
+
+ /* enable the backlight output */
+ set_gpio_output_high(11);
+ /* enable the brightness control */
+ set_gpio_output_high(7);
+ /* enable AMP */
+ set_gpio_output_low(6);
+
+ return 0;
+}
+
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = "lynloong-pc",
+ .owner = THIS_MODULE,
+ },
+#ifdef CONFIG_PM
+ .suspend = lynloong_suspend,
+ .resume = lynloong_resume,
+#endif
+};
+
+static ssize_t lynloong_pdev_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "lynloong pc\n");
+}
+
+static struct device_attribute dev_attr_lynloong_pdev_name =
+__ATTR(name, S_IRUGO, lynloong_pdev_name_show, NULL);
+
+static int lynloong_pdev_init(void)
+{
+ int ret;
+
+ /* Register platform stuff */
+ ret = platform_driver_register(&platform_driver);
+ if (ret)
+ return ret;
+
+ lynloong_pdev = platform_device_alloc("lynloong-laptop", -1);
+ if (!lynloong_pdev) {
+ ret = -ENOMEM;
+ platform_driver_unregister(&platform_driver);
+ return ret;
+ }
+
+ ret = platform_device_add(lynloong_pdev);
+ if (ret) {
+ platform_device_put(lynloong_pdev);
+ return ret;
+ }
+
+ if (IS_ERR(lynloong_pdev)) {
+ ret = PTR_ERR(lynloong_pdev);
+ lynloong_pdev = NULL;
+ printk(KERN_INFO "unable to register platform device\n");
+ return ret;
+ }
+
+ ret = device_create_file(&lynloong_pdev->dev,
+ &dev_attr_lynloong_pdev_name);
+ if (ret) {
+ printk(KERN_INFO "unable to create sysfs device attributes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void lynloong_pdev_exit(void)
+{
+ if (lynloong_pdev) {
+ platform_device_unregister(lynloong_pdev);
+ lynloong_pdev = NULL;
+ platform_driver_unregister(&platform_driver);
+ }
+}
+
+static int __init lynloong_init(void)
+{
+ int ret;
+ u32 hi;
+
+ if (mips_machtype != MACH_LEMOTE_LL2F) {
+ printk(KERN_INFO "This Driver is for LynLoong(Allinone) PC, You"
+ "can not use it on the other Machines\n");
+ return -EFAULT;
+ }
+
+ /* get mfgpt_base */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &hi, &mfgpt_base);
+ /* get gpio_base */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &gpio_base);
+ /* get smb base */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &smb_base);
+
+ ret = lynloong_pdev_init();
+ if (ret) {
+ lynloong_pdev_exit();
+ printk(KERN_INFO "init lynloong platform driver failure\n");
+ return ret;
+ }
+
+ ret = lynloong_backlight_init(&lynloong_pdev->dev);
+ if (ret) {
+ lynloong_backlight_exit();
+ printk(KERN_INFO "init lynloong backlight driver failure\n");
+ return ret;
+ }
+ ret = lynloong_thermal_init(&lynloong_backlight_dev->dev);
+ if (ret) {
+ lynloong_thermal_exit(&lynloong_backlight_dev->dev);
+ printk(KERN_INFO
+ "init lynloong thermal cooling device failure\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit lynloong_exit(void)
+{
+ lynloong_pdev_exit();
+ lynloong_thermal_exit(&lynloong_backlight_dev->dev);
+ lynloong_backlight_exit();
+}
+
+module_init(lynloong_init);
+module_exit(lynloong_exit);
+
+MODULE_AUTHOR("Xiang Yu <xiangy@lemote.com>; Wu Zhangjin <wuzj@lemote.com>");
+MODULE_DESCRIPTION("LynLoong Platform Specific Driver");
+MODULE_LICENSE("GPL");
--
1.6.2.1
|