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/nvec.c108
-rw-r--r--drivers/staging/nvec/nvec.h35
-rw-r--r--drivers/staging/nvec/nvec_kbd.c18
-rw-r--r--drivers/staging/nvec/nvec_power.c1
-rw-r--r--drivers/staging/nvec/nvec_ps2.c6
6 files changed, 93 insertions, 87 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/nvec.c b/drivers/staging/nvec/nvec.c
index cf159365b0e..90f1c4d7fa8 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -33,11 +33,9 @@
#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 <linux/clk/tegra.h>
#include "nvec.h"
@@ -84,7 +82,7 @@ enum nvec_sleep_subcmds {
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,
@@ -124,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
@@ -185,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);
@@ -352,10 +364,10 @@ static void nvec_toggle_global_events(struct nvec_chip *nvec, bool state)
*/
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;
+ ev[3] = mask >> 16 & 0xff;
+ ev[4] = mask >> 24 & 0xff;
+ ev[5] = mask >> 0 & 0xff;
+ ev[6] = mask >> 8 & 0xff;
}
/**
@@ -666,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;
@@ -720,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);
@@ -737,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
@@ -758,11 +768,31 @@ static void nvec_power_off(void)
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;
@@ -771,6 +801,11 @@ static int tegra_nvec_probe(struct platform_device *pdev)
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) {
dev_err(&pdev->dev, "failed to reserve memory\n");
@@ -779,32 +814,11 @@ 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_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -815,12 +829,18 @@ static int tegra_nvec_probe(struct platform_device *pdev)
return -ENODEV;
}
- i2c_clk = clk_get(&pdev->dev, "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;
@@ -855,9 +875,6 @@ static int tegra_nvec_probe(struct platform_device *pdev)
tegra_init_i2c_slave(nvec);
- clk_prepare_enable(i2c_clk);
-
-
/* enable event reporting */
nvec_toggle_global_events(nvec, true);
@@ -902,8 +919,11 @@ static int tegra_nvec_remove(struct platform_device *pdev)
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;
}
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index b7a14bc0ab9..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>
@@ -103,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
@@ -164,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;
@@ -197,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 7445ce6422b..c17a1c3eb3c 100644
--- a/drivers/staging/nvec/nvec_kbd.c
+++ b/drivers/staging/nvec/nvec_kbd.c
@@ -126,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);
@@ -142,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;
@@ -161,16 +161,17 @@ static int nvec_kbd_probe(struct platform_device *pdev)
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;
}
@@ -188,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 296f7b9a8c8..aacfcd6954a 100644
--- a/drivers/staging/nvec/nvec_power.c
+++ b/drivers/staging/nvec/nvec_power.c
@@ -414,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 aff6b9b9f9a..45b2f1308e0 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -133,6 +133,11 @@ static int nvec_mouse_probe(struct platform_device *pdev)
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;
@@ -179,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");