aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/nvec
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/nvec')
-rw-r--r--drivers/staging/nvec/Kconfig12
-rw-r--r--drivers/staging/nvec/TODO4
-rw-r--r--drivers/staging/nvec/nvec.c191
-rw-r--r--drivers/staging/nvec/nvec.h40
-rw-r--r--drivers/staging/nvec/nvec_kbd.c60
-rw-r--r--drivers/staging/nvec/nvec_power.c9
-rw-r--r--drivers/staging/nvec/nvec_ps2.c43
7 files changed, 211 insertions, 148 deletions
diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig
index f779fdc3427..9475e20c3d6 100644
--- a/drivers/staging/nvec/Kconfig
+++ b/drivers/staging/nvec/Kconfig
@@ -1,5 +1,5 @@
config MFD_NVEC
- bool "NV Tegra Embedded Controller SMBus Interface"
+ tristate "NV Tegra Embedded Controller SMBus Interface"
depends on I2C && GPIOLIB && ARCH_TEGRA
select MFD_CORE
help
@@ -7,28 +7,28 @@ config MFD_NVEC
controller.
config KEYBOARD_NVEC
- bool "Keyboard on nVidia compliant EC"
+ tristate "Keyboard on nVidia compliant EC"
depends on MFD_NVEC && INPUT
help
- Say Y here to enable support for a keyboard connected to
+ Say Y here to enable support for a keyboard connected to
a nVidia compliant embedded controller.
config SERIO_NVEC_PS2
- bool "PS2 on nVidia EC"
+ tristate "PS2 on nVidia EC"
depends on MFD_NVEC && SERIO
help
Say Y here to enable support for a Touchpad / Mouse connected
to a nVidia compliant embedded controller.
config NVEC_POWER
- bool "NVEC charger and battery"
+ tristate "NVEC charger and battery"
depends on MFD_NVEC && POWER_SUPPLY
help
Say Y to enable support for battery and charger interface for
nVidia compliant embedded controllers.
config NVEC_PAZ00
- bool "Support for OEM specific functions on Compal PAZ00 based devices"
+ tristate "Support for OEM specific functions on Compal PAZ00 based devices"
depends on MFD_NVEC && LEDS_CLASS
help
Say Y to enable control of the yellow side leds on Compal PAZ00 based
diff --git a/drivers/staging/nvec/TODO b/drivers/staging/nvec/TODO
index f950ab890e2..e5ae42a0b44 100644
--- a/drivers/staging/nvec/TODO
+++ b/drivers/staging/nvec/TODO
@@ -1,9 +1,5 @@
ToDo list (incomplete, unordered)
- add compile as module support
- - fix clk usage
- should not be using clk_get_sys(), but clk_get(&pdev->dev, conn)
- where conn is either NULL if the device only has one clock, or
- the device specific name if it has multiple clocks.
- move half of the nvec init stuff to i2c-tegra.c
- move event handling to nvec_events
- finish suspend/resume support
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 2830946860d..90f1c4d7fa8 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -33,13 +33,10 @@
#include <linux/mfd/core.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
-#include <mach/clk.h>
-
#include "nvec.h"
#define I2C_CNFG 0x00
@@ -72,13 +69,20 @@ enum nvec_msg_category {
NVEC_MSG_TX,
};
-static const unsigned char EC_DISABLE_EVENT_REPORTING[3] = "\x04\x00\x00";
-static const unsigned char EC_ENABLE_EVENT_REPORTING[3] = "\x04\x00\x01";
-static const unsigned char EC_GET_FIRMWARE_VERSION[2] = "\x07\x15";
+enum nvec_sleep_subcmds {
+ GLOBAL_EVENTS,
+ AP_PWR_DOWN,
+ AP_SUSPEND,
+};
+
+#define CNF_EVENT_REPORTING 0x01
+#define GET_FIRMWARE_VERSION 0x15
+#define LID_SWITCH BIT(1)
+#define PWR_BUTTON BIT(15)
static struct nvec_chip *nvec_power_handle;
-static struct mfd_cell nvec_devices[] = {
+static const struct mfd_cell nvec_devices[] = {
{
.name = "nvec-kbd",
.id = 1,
@@ -118,6 +122,20 @@ int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
EXPORT_SYMBOL_GPL(nvec_register_notifier);
/**
+ * nvec_unregister_notifier - Unregister a notifier with nvec
+ * @nvec: A &struct nvec_chip
+ * @nb: The notifier block to unregister
+ *
+ * Unregisters a notifier with @nvec. The notifier will be removed from the
+ * atomic notifier chain.
+ */
+int nvec_unregister_notifier(struct nvec_chip *nvec, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&nvec->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(nvec_unregister_notifier);
+
+/**
* nvec_status_notifier - The final notifier
*
* Prints a message about control events not handled in the notifier
@@ -179,7 +197,7 @@ static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec,
*
* Free the given message
*/
-inline void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg)
+void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg)
{
if (msg != &nvec->tx_scratch)
dev_vdbg(nvec->dev, "INFO: Free %ti\n", msg - nvec->msg_pool);
@@ -318,6 +336,41 @@ struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
EXPORT_SYMBOL(nvec_write_sync);
/**
+ * nvec_toggle_global_events - enables or disables global event reporting
+ * @nvec: nvec handle
+ * @state: true for enable, false for disable
+ *
+ * This switches on/off global event reports by the embedded controller.
+ */
+static void nvec_toggle_global_events(struct nvec_chip *nvec, bool state)
+{
+ unsigned char global_events[] = { NVEC_SLEEP, GLOBAL_EVENTS, state };
+
+ nvec_write_async(nvec, global_events, 3);
+}
+
+/**
+ * nvec_event_mask - fill the command string with event bitfield
+ * ev: points to event command string
+ * mask: bit to insert into the event mask
+ *
+ * Configure event command expects a 32 bit bitfield which describes
+ * which events to enable. The bitfield has the following structure
+ * (from highest byte to lowest):
+ * system state bits 7-0
+ * system state bits 15-8
+ * oem system state bits 7-0
+ * oem system state bits 15-8
+ */
+static void nvec_event_mask(char *ev, u32 mask)
+{
+ ev[3] = mask >> 16 & 0xff;
+ ev[4] = mask >> 24 & 0xff;
+ ev[5] = mask >> 0 & 0xff;
+ ev[6] = mask >> 8 & 0xff;
+}
+
+/**
* nvec_request_master - Process outgoing messages
* @work: A &struct work_struct (the tx_worker member of &struct nvec_chip)
*
@@ -625,9 +678,9 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
nvec->rx->data[nvec->rx->pos++] = received;
else
dev_err(nvec->dev,
- "RX buffer overflow on %p: "
- "Trying to write byte %u of %u\n",
- nvec->rx, nvec->rx->pos, NVEC_MSG_SIZE);
+ "RX buffer overflow on %p: Trying to write byte %u of %u\n",
+ nvec->rx, nvec->rx ? nvec->rx->pos : 0,
+ NVEC_MSG_SIZE);
break;
default:
nvec->state = 0;
@@ -679,9 +732,9 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
clk_prepare_enable(nvec->i2c_clk);
- tegra_periph_reset_assert(nvec->i2c_clk);
+ reset_control_assert(nvec->rst);
udelay(2);
- tegra_periph_reset_deassert(nvec->i2c_clk);
+ reset_control_deassert(nvec->rst);
val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
@@ -696,8 +749,6 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
writel(0, nvec->base + I2C_SL_ADDR2);
enable_irq(nvec->irq);
-
- clk_disable_unprepare(nvec->i2c_clk);
}
#ifdef CONFIG_PM_SLEEP
@@ -711,19 +762,49 @@ static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
static void nvec_power_off(void)
{
- nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3);
- nvec_write_async(nvec_power_handle, "\x04\x01", 2);
+ char ap_pwr_down[] = { NVEC_SLEEP, AP_PWR_DOWN };
+
+ nvec_toggle_global_events(nvec_power_handle, false);
+ nvec_write_async(nvec_power_handle, ap_pwr_down, 2);
+}
+
+/*
+ * Parse common device tree data
+ */
+static int nvec_i2c_parse_dt_pdata(struct nvec_chip *nvec)
+{
+ nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0);
+
+ if (nvec->gpio < 0) {
+ dev_err(nvec->dev, "no gpio specified");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(nvec->dev->of_node, "slave-addr",
+ &nvec->i2c_addr)) {
+ dev_err(nvec->dev, "no i2c address specified");
+ return -ENODEV;
+ }
+
+ return 0;
}
static int tegra_nvec_probe(struct platform_device *pdev)
{
int err, ret;
struct clk *i2c_clk;
- struct nvec_platform_data *pdata = pdev->dev.platform_data;
struct nvec_chip *nvec;
struct nvec_msg *msg;
struct resource *res;
void __iomem *base;
+ char get_firmware_version[] = { NVEC_CNTL, GET_FIRMWARE_VERSION },
+ unmute_speakers[] = { NVEC_OEM0, 0x10, 0x59, 0x95 },
+ enable_event[7] = { NVEC_SYS, CNF_EVENT_REPORTING, true };
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "must be instantiated using device tree\n");
+ return -ENODEV;
+ }
nvec = devm_kzalloc(&pdev->dev, sizeof(struct nvec_chip), GFP_KERNEL);
if (nvec == NULL) {
@@ -733,37 +814,14 @@ static int tegra_nvec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nvec);
nvec->dev = &pdev->dev;
- if (pdata) {
- nvec->gpio = pdata->gpio;
- nvec->i2c_addr = pdata->i2c_addr;
- } else if (nvec->dev->of_node) {
- nvec->gpio = of_get_named_gpio(nvec->dev->of_node,
- "request-gpios", 0);
- if (nvec->gpio < 0) {
- dev_err(&pdev->dev, "no gpio specified");
- return -ENODEV;
- }
- if (of_property_read_u32(nvec->dev->of_node,
- "slave-addr", &nvec->i2c_addr)) {
- dev_err(&pdev->dev, "no i2c address specified");
- return -ENODEV;
- }
- } else {
- dev_err(&pdev->dev, "no platform data\n");
- return -ENODEV;
- }
+ err = nvec_i2c_parse_dt_pdata(nvec);
+ if (err < 0)
+ return err;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
- base = devm_request_and_ioremap(&pdev->dev, res);
- if (!base) {
- dev_err(&pdev->dev, "Can't ioremap I2C region\n");
- return -ENOMEM;
- }
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
@@ -771,12 +829,18 @@ static int tegra_nvec_probe(struct platform_device *pdev)
return -ENODEV;
}
- i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk");
+ i2c_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(i2c_clk)) {
dev_err(nvec->dev, "failed to get controller clock\n");
return -ENODEV;
}
+ nvec->rst = devm_reset_control_get(&pdev->dev, "i2c");
+ if (IS_ERR(nvec->rst)) {
+ dev_err(nvec->dev, "failed to get controller reset\n");
+ return PTR_ERR(nvec->rst);
+ }
+
nvec->base = base;
nvec->irq = res->start;
nvec->i2c_clk = i2c_clk;
@@ -811,12 +875,8 @@ static int tegra_nvec_probe(struct platform_device *pdev)
tegra_init_i2c_slave(nvec);
- clk_prepare_enable(i2c_clk);
-
-
/* enable event reporting */
- nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
- sizeof(EC_ENABLE_EVENT_REPORTING));
+ nvec_toggle_global_events(nvec, true);
nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
@@ -825,8 +885,7 @@ static int tegra_nvec_probe(struct platform_device *pdev)
pm_power_off = nvec_power_off;
/* Get Firmware Version */
- msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
- sizeof(EC_GET_FIRMWARE_VERSION));
+ msg = nvec_write_sync(nvec, get_firmware_version, 2);
if (msg) {
dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
@@ -841,13 +900,15 @@ static int tegra_nvec_probe(struct platform_device *pdev)
dev_err(nvec->dev, "error adding subdevices\n");
/* unmute speakers? */
- nvec_write_async(nvec, "\x0d\x10\x59\x95", 4);
+ nvec_write_async(nvec, unmute_speakers, 4);
/* enable lid switch event */
- nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x02\x00", 7);
+ nvec_event_mask(enable_event, LID_SWITCH);
+ nvec_write_async(nvec, enable_event, 7);
/* enable power button event */
- nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7);
+ nvec_event_mask(enable_event, PWR_BUTTON);
+ nvec_write_async(nvec, enable_event, 7);
return 0;
}
@@ -856,10 +917,13 @@ static int tegra_nvec_remove(struct platform_device *pdev)
{
struct nvec_chip *nvec = platform_get_drvdata(pdev);
- nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
+ nvec_toggle_global_events(nvec, false);
mfd_remove_devices(nvec->dev);
+ nvec_unregister_notifier(nvec, &nvec->nvec_status_notifier);
cancel_work_sync(&nvec->rx_work);
cancel_work_sync(&nvec->tx_work);
+ /* FIXME: needs check wether nvec is responsible for power off */
+ pm_power_off = NULL;
return 0;
}
@@ -870,13 +934,14 @@ static int nvec_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct nvec_chip *nvec = platform_get_drvdata(pdev);
struct nvec_msg *msg;
+ char ap_suspend[] = { NVEC_SLEEP, AP_SUSPEND };
dev_dbg(nvec->dev, "suspending\n");
/* keep these sync or you'll break suspend */
- msg = nvec_write_sync(nvec, EC_DISABLE_EVENT_REPORTING, 3);
- nvec_msg_free(nvec, msg);
- msg = nvec_write_sync(nvec, "\x04\x02", 2);
+ nvec_toggle_global_events(nvec, false);
+
+ msg = nvec_write_sync(nvec, ap_suspend, sizeof(ap_suspend));
nvec_msg_free(nvec, msg);
nvec_disable_i2c_slave(nvec);
@@ -891,7 +956,7 @@ static int nvec_resume(struct device *dev)
dev_dbg(nvec->dev, "resuming\n");
tegra_init_i2c_slave(nvec);
- nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);
+ nvec_toggle_global_events(nvec, true);
return 0;
}
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index ba6ed8f4e8a..e271375053f 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -71,9 +72,12 @@ enum nvec_event_size {
enum nvec_msg_type {
NVEC_SYS = 1,
NVEC_BAT,
- NVEC_KBD = 5,
+ NVEC_GPIO,
+ NVEC_SLEEP,
+ NVEC_KBD,
NVEC_PS2,
NVEC_CNTL,
+ NVEC_OEM0 = 0x0d,
NVEC_KB_EVT = 0x80,
NVEC_PS2_EVT,
};
@@ -100,38 +104,14 @@ struct nvec_msg {
};
/**
- * struct nvec_subdev - A subdevice of nvec, such as nvec_kbd
- * @name: The name of the sub device
- * @platform_data: Platform data
- * @id: Identifier of the sub device
- */
-struct nvec_subdev {
- const char *name;
- void *platform_data;
- int id;
-};
-
-/**
- * struct nvec_platform_data - platform data for a tegra slave controller
- * @i2c_addr: number of i2c slave adapter the ec is connected to
- * @gpio: gpio number for the ec request line
- *
- * Platform data, to be used in board definitions. For an example, take a
- * look at the paz00 board in arch/arm/mach-tegra/board-paz00.c
- */
-struct nvec_platform_data {
- int i2c_addr;
- int gpio;
-};
-
-/**
* struct nvec_chip - A single connection to an NVIDIA Embedded controller
* @dev: The device
* @gpio: The same as for &struct nvec_platform_data
* @irq: The IRQ of the I2C device
* @i2c_addr: The address of the I2C slave
* @base: The base of the memory mapped region of the I2C device
- * @clk: The clock of the I2C device
+ * @i2c_clk: The clock of the I2C device
+ * @rst: The reset of the I2C device
* @notifier_list: Notifiers to be called on received messages, see
* nvec_register_notifier()
* @rx_data: Received messages that have to be processed
@@ -161,6 +141,7 @@ struct nvec_chip {
int i2c_addr;
void __iomem *base;
struct clk *i2c_clk;
+ struct reset_control *rst;
struct atomic_notifier_head notifier_list;
struct list_head rx_data, tx_data;
struct notifier_block nvec_status_notifier;
@@ -194,9 +175,8 @@ extern int nvec_register_notifier(struct nvec_chip *nvec,
struct notifier_block *nb,
unsigned int events);
-extern int nvec_unregister_notifier(struct device *dev,
- struct notifier_block *nb,
- unsigned int events);
+extern int nvec_unregister_notifier(struct nvec_chip *dev,
+ struct notifier_block *nb);
extern void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg);
diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c
index 7cb149bf3d3..c17a1c3eb3c 100644
--- a/drivers/staging/nvec/nvec_kbd.c
+++ b/drivers/staging/nvec/nvec_kbd.c
@@ -21,10 +21,14 @@
#include "nvec-keytable.h"
#include "nvec.h"
-#define ACK_KBD_EVENT {'\x05', '\xed', '\x01'}
+enum kbd_subcmds {
+ CNFG_WAKE = 3,
+ CNFG_WAKE_KEY_REPORTING,
+ SET_LEDS = 0xed,
+ ENABLE_KBD = 0xf4,
+ DISABLE_KBD,
+};
-static const char led_on[3] = "\x05\xed\x07";
-static const char led_off[3] = "\x05\xed\x00";
static unsigned char keycodes[ARRAY_SIZE(code_tab_102us)
+ ARRAY_SIZE(extcode_tab_us102)];
@@ -39,12 +43,15 @@ static struct nvec_keys keys_dev;
static void nvec_kbd_toggle_led(void)
{
+ char buf[] = { NVEC_KBD, SET_LEDS, 0 };
+
keys_dev.caps_lock = !keys_dev.caps_lock;
if (keys_dev.caps_lock)
- nvec_write_async(keys_dev.nvec, led_on, sizeof(led_on));
- else
- nvec_write_async(keys_dev.nvec, led_off, sizeof(led_off));
+ /* should be BIT(0) only, firmware bug? */
+ buf[2] = BIT(0) | BIT(1) | BIT(2);
+
+ nvec_write_async(keys_dev.nvec, buf, sizeof(buf));
}
static int nvec_keys_notifier(struct notifier_block *nb,
@@ -82,8 +89,8 @@ static int nvec_keys_notifier(struct notifier_block *nb,
static int nvec_kbd_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
- unsigned char buf[] = ACK_KBD_EVENT;
struct nvec_chip *nvec = keys_dev.nvec;
+ char buf[] = { NVEC_KBD, SET_LEDS, 0 };
if (type == EV_REP)
return 0;
@@ -105,6 +112,11 @@ static int nvec_kbd_probe(struct platform_device *pdev)
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
int i, j, err;
struct input_dev *idev;
+ char clear_leds[] = { NVEC_KBD, SET_LEDS, 0 },
+ enable_kbd[] = { NVEC_KBD, ENABLE_KBD },
+ cnfg_wake[] = { NVEC_KBD, CNFG_WAKE, true, true },
+ cnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING,
+ true };
j = 0;
@@ -114,7 +126,7 @@ static int nvec_kbd_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(extcode_tab_us102); ++i)
keycodes[j++] = extcode_tab_us102[i];
- idev = input_allocate_device();
+ idev = devm_input_allocate_device(&pdev->dev);
idev->name = "nvec keyboard";
idev->phys = "nvec";
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_LED);
@@ -130,7 +142,7 @@ static int nvec_kbd_probe(struct platform_device *pdev)
clear_bit(0, idev->keybit);
err = input_register_device(idev);
if (err)
- goto fail;
+ return err;
keys_dev.input = idev;
keys_dev.notifier.notifier_call = nvec_keys_notifier;
@@ -138,31 +150,28 @@ static int nvec_kbd_probe(struct platform_device *pdev)
nvec_register_notifier(nvec, &keys_dev.notifier, 0);
/* Enable keyboard */
- nvec_write_async(nvec, "\x05\xf4", 2);
+ nvec_write_async(nvec, enable_kbd, 2);
- /* keyboard reset? */
- nvec_write_async(nvec, "\x05\x03\x01\x01", 4);
- nvec_write_async(nvec, "\x05\x04\x01", 3);
- nvec_write_async(nvec, "\x06\x01\xff\x03", 4);
-/* FIXME
- wait until keyboard reset is finished
- or until we have a sync write */
- mdelay(1000);
+ /* configures wake on special keys */
+ nvec_write_async(nvec, cnfg_wake, 4);
+ /* enable wake key reporting */
+ nvec_write_async(nvec, cnfg_wake_key_reporting, 3);
/* Disable caps lock LED */
- nvec_write_async(nvec, led_off, sizeof(led_off));
+ nvec_write_async(nvec, clear_leds, sizeof(clear_leds));
return 0;
-
-fail:
- input_free_device(idev);
- return err;
}
static int nvec_kbd_remove(struct platform_device *pdev)
{
- input_unregister_device(keys_dev.input);
- input_free_device(keys_dev.input);
+ struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+ char disable_kbd[] = { NVEC_KBD, DISABLE_KBD },
+ uncnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING,
+ false };
+ nvec_write_async(nvec, uncnfg_wake_key_reporting, 3);
+ nvec_write_async(nvec, disable_kbd, 2);
+ nvec_unregister_notifier(nvec, &keys_dev.notifier);
return 0;
}
@@ -180,4 +189,5 @@ module_platform_driver(nvec_kbd_driver);
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
MODULE_DESCRIPTION("NVEC keyboard driver");
+MODULE_ALIAS("platform:nvec-kbd");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c
index b7b6d54f58e..aacfcd6954a 100644
--- a/drivers/staging/nvec/nvec_power.c
+++ b/drivers/staging/nvec/nvec_power.c
@@ -22,6 +22,8 @@
#include "nvec.h"
+#define GET_SYSTEM_STATUS 0x00
+
struct nvec_power {
struct notifier_block notifier;
struct delayed_work poller;
@@ -111,7 +113,7 @@ static const int bat_init[] = {
static void get_bat_mfg_data(struct nvec_power *power)
{
int i;
- char buf[] = { '\x02', '\x00' };
+ char buf[] = { NVEC_BAT, SLOT_STATUS };
for (i = 0; i < ARRAY_SIZE(bat_init); i++) {
buf[1] = bat_init[i];
@@ -348,7 +350,7 @@ static int const bat_iter[] = {
static void nvec_power_poll(struct work_struct *work)
{
- char buf[] = { '\x01', '\x00' };
+ char buf[] = { NVEC_SYS, GET_SYSTEM_STATUS };
struct nvec_power *power = container_of(work, struct nvec_power,
poller.work);
@@ -361,7 +363,7 @@ static void nvec_power_poll(struct work_struct *work)
/* select a battery request function via round robin
doing it all at once seems to overload the power supply */
- buf[0] = '\x02'; /* battery */
+ buf[0] = NVEC_BAT;
buf[1] = bat_iter[counter++];
nvec_write_async(power->nvec, buf, 2);
@@ -412,6 +414,7 @@ static int nvec_power_remove(struct platform_device *pdev)
struct nvec_power *power = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&power->poller);
+ nvec_unregister_notifier(power->nvec, &power->notifier);
switch (pdev->id) {
case AC:
power_supply_unregister(&nvec_psy);
diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c
index 88dd288bf3d..45b2f1308e0 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -21,9 +21,11 @@
#include "nvec.h"
-#define START_STREAMING {'\x06', '\x03', '\x06'}
-#define STOP_STREAMING {'\x06', '\x04'}
-#define SEND_COMMAND {'\x06', '\x01', '\xf4', '\x01'}
+#define PACKET_SIZE 6
+
+#define ENABLE_MOUSE 0xf4
+#define DISABLE_MOUSE 0xf5
+#define PSMOUSE_RST 0xff
#ifdef NVEC_PS2_DEBUG
#define NVEC_PHD(str, buf, len) \
@@ -33,7 +35,12 @@
#define NVEC_PHD(str, buf, len)
#endif
-static const unsigned char MOUSE_RESET[] = {'\x06', '\x01', '\xff', '\x03'};
+enum ps2_subcmds {
+ SEND_COMMAND = 1,
+ RECEIVE_N,
+ AUTO_RECEIVE_N,
+ CANCEL_AUTO_RECEIVE,
+};
struct nvec_ps2 {
struct serio *ser_dev;
@@ -45,19 +52,19 @@ static struct nvec_ps2 ps2_dev;
static int ps2_startstreaming(struct serio *ser_dev)
{
- unsigned char buf[] = START_STREAMING;
+ unsigned char buf[] = { NVEC_PS2, AUTO_RECEIVE_N, PACKET_SIZE };
return nvec_write_async(ps2_dev.nvec, buf, sizeof(buf));
}
static void ps2_stopstreaming(struct serio *ser_dev)
{
- unsigned char buf[] = STOP_STREAMING;
+ unsigned char buf[] = { NVEC_PS2, CANCEL_AUTO_RECEIVE };
nvec_write_async(ps2_dev.nvec, buf, sizeof(buf));
}
static int ps2_sendcommand(struct serio *ser_dev, unsigned char cmd)
{
- unsigned char buf[] = SEND_COMMAND;
+ unsigned char buf[] = { NVEC_PS2, SEND_COMMAND, ENABLE_MOUSE, 1 };
buf[2] = cmd & 0xff;
@@ -97,6 +104,7 @@ static int nvec_mouse_probe(struct platform_device *pdev)
{
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
struct serio *ser_dev;
+ char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 };
ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
if (ser_dev == NULL)
@@ -118,13 +126,18 @@ static int nvec_mouse_probe(struct platform_device *pdev)
serio_register_port(ser_dev);
/* mouse reset */
- nvec_write_async(nvec, MOUSE_RESET, 4);
+ nvec_write_async(nvec, mouse_reset, sizeof(mouse_reset));
return 0;
}
static int nvec_mouse_remove(struct platform_device *pdev)
{
+ struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+
+ ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE);
+ ps2_stopstreaming(ps2_dev.ser_dev);
+ nvec_unregister_notifier(nvec, &ps2_dev.notifier);
serio_unregister_port(ps2_dev.ser_dev);
return 0;
@@ -133,27 +146,22 @@ static int nvec_mouse_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int nvec_mouse_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
-
/* disable mouse */
- nvec_write_async(nvec, "\x06\xf4", 2);
+ ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE);
/* send cancel autoreceive */
- nvec_write_async(nvec, "\x06\x04", 2);
+ ps2_stopstreaming(ps2_dev.ser_dev);
return 0;
}
static int nvec_mouse_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
-
+ /* start streaming */
ps2_startstreaming(ps2_dev.ser_dev);
/* enable mouse */
- nvec_write_async(nvec, "\x06\xf5", 2);
+ ps2_sendcommand(ps2_dev.ser_dev, ENABLE_MOUSE);
return 0;
}
@@ -176,4 +184,5 @@ module_platform_driver(nvec_mouse_driver);
MODULE_DESCRIPTION("NVEC mouse driver");
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
+MODULE_ALIAS("platform:nvec-mouse");
MODULE_LICENSE("GPL");