diff mbox

[RFCv4,06/11] misc: Introduce Nokia CMT driver

Message ID 1387150085-23173-7-git-send-email-sre@debian.org (mailing list archive)
State New, archived
Headers show

Commit Message

Sebastian Reichel Dec. 15, 2013, 11:27 p.m. UTC
Add driver handling GPIO pins of Nokia modems. The
driver provides reset notifications, so that SSI
clients can subscribe to them easily.

Signed-off-by: Sebastian Reichel <sre@debian.org>
---
 drivers/misc/Kconfig      |   7 ++
 drivers/misc/Makefile     |   1 +
 drivers/misc/nokia-cmt.c  | 298 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nokia-cmt.h |  46 +++++++
 4 files changed, 352 insertions(+)
 create mode 100644 drivers/misc/nokia-cmt.c
 create mode 100644 include/linux/nokia-cmt.h

Comments

Linus Walleij Dec. 16, 2013, 9:48 a.m. UTC | #1
On Mon, Dec 16, 2013 at 12:27 AM, Sebastian Reichel <sre@debian.org> wrote:

> Add driver handling GPIO pins of Nokia modems. The
> driver provides reset notifications, so that SSI
> clients can subscribe to them easily.
>
> Signed-off-by: Sebastian Reichel <sre@debian.org>

If the driver provides reset notifications, should it rather be
in drivers/reset?

I'm thinking of a generic GPIO reset driver with a generic
notification mechanism, which seems to be what this is.

I.e. it doesn't look device-specific at all, just like some
generic glue code that could be useful to many such
scenarios.

> +config NOKIA_CMT
> +       tristate "Enable CMT support"
> +       help
> +       If you say Y here, you will enable CMT support.
> +
> +       If unsure, say Y, or else you will not be able to use the CMT.

None of this explains what this driver actually does and what
CMT means, so please rewrite this a bit to be more helpful.
The way it is written it could as well say "enable FOO support".

> +++ b/drivers/misc/nokia-cmt.c
> @@ -0,0 +1,298 @@
> +/*
> + * CMT support.

So CMT = ...?

> +/**
> + * struct cmt_device - CMT device data
> + * @cmt_rst_ind_tasklet: Bottom half for CMT reset line events
> + * @cmt_rst_ind_irq: IRQ number of the CMT reset line
> + * @n_head: List of notifiers registered to get CMT events
> + * @node: Link on the list of available CMTs
> + * @device: Reference to the CMT platform device
> + */
> +struct cmt_device {
> +       struct tasklet_struct           cmt_rst_ind_tasklet;
> +       unsigned int                    cmt_rst_ind_irq;
> +       struct atomic_notifier_head     n_head;
> +       struct list_head                node;
> +       struct device                   *device;
> +       struct cmt_gpio                 *gpios;
> +       int                             gpio_amount;
> +};

The kerneldoc and and the struct are not in sync. Look
this over.

> +static LIST_HEAD(cmt_list);    /* List of CMT devices */
(...)
> +struct cmt_device *cmt_get(const char *name)
> +{
> +       struct cmt_device *p, *cmt = ERR_PTR(-ENODEV);
> +
> +       list_for_each_entry(p, &cmt_list, node)
> +               if (strcmp(name, dev_name(p->device)) == 0) {
> +                       cmt = p;
> +                       break;
> +               }
> +
> +       return cmt;
> +}
> +EXPORT_SYMBOL_GPL(cmt_get);

Is this driver used on non-DT platforms, or can we skip this
struct device * referencing altogether?

I would feel better if this driver looked more like
drivers/mfd/syscon.c

> +static irqreturn_t cmt_rst_ind_isr(int irq, void *cmtdev)
> +{
> +       struct cmt_device *cmt = (struct cmt_device *)cmtdev;
> +
> +       tasklet_schedule(&cmt->cmt_rst_ind_tasklet);
> +
> +       return IRQ_HANDLED;
> +}

Why are you using a tasklet rather than a work
for this?

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sebastian Reichel Dec. 16, 2013, 12:15 p.m. UTC | #2
Hi Linus,

On Mon, Dec 16, 2013 at 10:48:06AM +0100, Linus Walleij wrote:
> On Mon, Dec 16, 2013 at 12:27 AM, Sebastian Reichel <sre@debian.org> wrote:
> > Add driver handling GPIO pins of Nokia modems. The
> > driver provides reset notifications, so that SSI
> > clients can subscribe to them easily.
> >
> > Signed-off-by: Sebastian Reichel <sre@debian.org>
> 
> If the driver provides reset notifications, should it rather be
> in drivers/reset?
> 
> I'm thinking of a generic GPIO reset driver with a generic
> notification mechanism, which seems to be what this is.
> 
> I.e. it doesn't look device-specific at all, just like some
> generic glue code that could be useful to many such
> scenarios.

I like the idea.

Probably the remaining gpio exporting code can be converted into
some generic gpio-sysfs-export driver as well.

What do you think about the following?

/*
 * driver, which provides generic reset notifications
 */
cmt_reset: reset-notifier {
    compatible = "linux,reset-notification";

    interrupts = <gpio>;
};

/*
 * driver, which exports the specified gpios in sysfs with the
 * supplied names. The device will be named according to the
 * label
 */
cmt_gpios: gpio-sysfs-export {
    compatible = "linux,gpio-sysfs-export";
    label = "nokia-cmt";

    gpios = <A>, <B>, ...;
    gpio-names = "A", "B", ...;
};

> > +config NOKIA_CMT
> > +       tristate "Enable CMT support"
> > +       help
> > +       If you say Y here, you will enable CMT support.
> > +
> > +       If unsure, say Y, or else you will not be able to use the CMT.
> 
> None of this explains what this driver actually does and what
> CMT means, so please rewrite this a bit to be more helpful.
> The way it is written it could as well say "enable FOO support".

I probably should have reviewed this better. This is the original
text from Nokia's driver.

> > +++ b/drivers/misc/nokia-cmt.c
> > @@ -0,0 +1,298 @@
> > +/*
> > + * CMT support.
> 
> So CMT = ...?

CMT = Cellular Modem

> > +/**
> > + * struct cmt_device - CMT device data
> > + * @cmt_rst_ind_tasklet: Bottom half for CMT reset line events
> > + * @cmt_rst_ind_irq: IRQ number of the CMT reset line
> > + * @n_head: List of notifiers registered to get CMT events
> > + * @node: Link on the list of available CMTs
> > + * @device: Reference to the CMT platform device
> > + */
> > +struct cmt_device {
> > +       struct tasklet_struct           cmt_rst_ind_tasklet;
> > +       unsigned int                    cmt_rst_ind_irq;
> > +       struct atomic_notifier_head     n_head;
> > +       struct list_head                node;
> > +       struct device                   *device;
> > +       struct cmt_gpio                 *gpios;
> > +       int                             gpio_amount;
> > +};
> 
> The kerneldoc and and the struct are not in sync. Look
> this over.

I will fix this in v5 (in case that its not removed completly).

> > +static LIST_HEAD(cmt_list);    /* List of CMT devices */
> (...)
> > +struct cmt_device *cmt_get(const char *name)
> > +{
> > +       struct cmt_device *p, *cmt = ERR_PTR(-ENODEV);
> > +
> > +       list_for_each_entry(p, &cmt_list, node)
> > +               if (strcmp(name, dev_name(p->device)) == 0) {
> > +                       cmt = p;
> > +                       break;
> > +               }
> > +
> > +       return cmt;
> > +}
> > +EXPORT_SYMBOL_GPL(cmt_get);
> 
> Is this driver used on non-DT platforms, or can we skip this
> struct device * referencing altogether?
>
> I would feel better if this driver looked more like
> drivers/mfd/syscon.c

Will be removed in v5.

> > +static irqreturn_t cmt_rst_ind_isr(int irq, void *cmtdev)
> > +{
> > +       struct cmt_device *cmt = (struct cmt_device *)cmtdev;
> > +
> > +       tasklet_schedule(&cmt->cmt_rst_ind_tasklet);
> > +
> > +       return IRQ_HANDLED;
> > +}
> 
> Why are you using a tasklet rather than a work
> for this?

No particular reason. I just took this over from Nokia's code.

-- Sebastian
Linus Walleij Dec. 16, 2013, 1:31 p.m. UTC | #3
On Mon, Dec 16, 2013 at 1:15 PM, Sebastian Reichel <sre@debian.org> wrote:
> On Mon, Dec 16, 2013 at 10:48:06AM +0100, Linus Walleij wrote:

>> I.e. it doesn't look device-specific at all, just like some
>> generic glue code that could be useful to many such
>> scenarios.
>
> I like the idea.
>
> Probably the remaining gpio exporting code can be converted into
> some generic gpio-sysfs-export driver as well.

I am very reluctant in letting device trees specify exports of GPIOs
to userspace, not so much because it's Linux-specific but for
the fact that people are doing things in userspace that should not
be done in userspace.

Last time it was proposed I asked to the specific usecase,
exactly why userspace needed this handle on a physical
GPIO line, and why it can't use another userspace interface
(example: leds, keys etc.)

> What do you think about the following?
>
> /*
>  * driver, which provides generic reset notifications
>  */
> cmt_reset: reset-notifier {
>     compatible = "linux,reset-notification";
>
>     interrupts = <gpio>;
> };

Looks good to me.

> /*
>  * driver, which exports the specified gpios in sysfs with the
>  * supplied names. The device will be named according to the
>  * label
>  */
> cmt_gpios: gpio-sysfs-export {
>     compatible = "linux,gpio-sysfs-export";
>     label = "nokia-cmt";
>
>     gpios = <A>, <B>, ...;
>     gpio-names = "A", "B", ...;
> };

Please follow the discussion on this topic:
http://marc.info/?l=linux-gpio&m=138201170431416&w=2

>> Why are you using a tasklet rather than a work
>> for this?
>
> No particular reason. I just took this over from Nokia's code.

Can you try to use a work instead?

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sebastian Reichel Dec. 16, 2013, 6:34 p.m. UTC | #4
Hi,

On Mon, Dec 16, 2013 at 02:31:53PM +0100, Linus Walleij wrote:
> I am very reluctant in letting device trees specify exports of GPIOs
> to userspace, not so much because it's Linux-specific but for
> the fact that people are doing things in userspace that should not
> be done in userspace.
> 
> Last time it was proposed I asked to the specific usecase,
> exactly why userspace needed this handle on a physical
> GPIO line, and why it can't use another userspace interface
> (example: leds, keys etc.)

There are a couple of lines ("cmt_apeslpx", "cmt_rst_rq", "cmt_en",
"cmt_rst", "cmt_bsi"), which are handled by ofono to do the correct
power sequence for the modem. The relevant ofono code is here:

https://git.kernel.org/cgit/network/ofono/ofono.git/tree/plugins/nokia-gpio.c

In MeeGo etc. they have a little board specific init script, which
exports the gpio lines and setups some symlinks. IMHO at least the
board specific stuff should be handled by the kernel, thus I added
this code to the driver. I guess you prefer to move the power
sequencing completly to the kernel?

> > What do you think about the following?
> >
> > /*
> >  * driver, which provides generic reset notifications
> >  */
> > cmt_reset: reset-notifier {
> >     compatible = "linux,reset-notification";
> >
> >     interrupts = <gpio>;
> > };
> 
> Looks good to me.

Ok :) I will prepare something for the next patch.

> > /*
> >  * driver, which exports the specified gpios in sysfs with the
> >  * supplied names. The device will be named according to the
> >  * label
> >  */
> > cmt_gpios: gpio-sysfs-export {
> >     compatible = "linux,gpio-sysfs-export";
> >     label = "nokia-cmt";
> >
> >     gpios = <A>, <B>, ...;
> >     gpio-names = "A", "B", ...;
> > };
> 
> Please follow the discussion on this topic:
> http://marc.info/?l=linux-gpio&m=138201170431416&w=2

Ok.

> >> Why are you using a tasklet rather than a work
> >> for this?
> >
> > No particular reason. I just took this over from Nokia's code.
> 
> Can you try to use a work instead?

Yes. I will have a look at this.

-- Sebastian
Ivaylo Dimitrov Dec. 17, 2013, 5:58 p.m. UTC | #5
On 16.12.2013 20:34, Sebastian Reichel wrote:
> Hi,
>
> On Mon, Dec 16, 2013 at 02:31:53PM +0100, Linus Walleij wrote:
>> I am very reluctant in letting device trees specify exports of GPIOs
>> to userspace, not so much because it's Linux-specific but for
>> the fact that people are doing things in userspace that should not
>> be done in userspace.
>>
>> Last time it was proposed I asked to the specific usecase,
>> exactly why userspace needed this handle on a physical
>> GPIO line, and why it can't use another userspace interface
>> (example: leds, keys etc.)
> There are a couple of lines ("cmt_apeslpx", "cmt_rst_rq", "cmt_en",
> "cmt_rst", "cmt_bsi"), which are handled by ofono to do the correct
> power sequence for the modem. The relevant ofono code is here:
>
> https://git.kernel.org/cgit/network/ofono/ofono.git/tree/plugins/nokia-gpio.c
>
> In MeeGo etc. they have a little board specific init script, which
> exports the gpio lines and setups some symlinks. IMHO at least the
> board specific stuff should be handled by the kernel, thus I added
> this code to the driver. I guess you prefer to move the power
> sequencing completly to the kernel?

Don't forget there is not only ofono, but rtcom-call-ui and all the 
telephony stack in Maemo 5 :). However, power sequencing and control is 
specific not only to the modem model, but to the firmware version the 
modem is running as well (afaik). IMO you can't simply move the modem 
power/reset/sleep control to the kernel and hope for the best, I am not 
sure there is enough documentation (if any) for this to be done 
reliably, esp on n900 with its BB5 modem. The point is that those gpios 
are used not only for the initial power-up, but for control of the modem 
state and reset (if needed) during normal usage. The APE reset line is 
an example of stuff that can't be moved to the kernel without providing 
some interface/feedback to/from the userspace IMO - what if she is 
dialing 112 at the moment the modem decides it is too hot and wants a 
device reset (or whatever reason there could be for a modem to request a 
device reset)? The same goes for the APE sleep request line 
(cmt_apeslpx) - based on what should the kernel decide whether to put 
the modem in sleep?

Sure, exporting gpios to userspace might not be the best way to achieve 
the required functionality, but every way could be argued if it is the 
best. And for sure labeling a modem "LED" won't make it such.

Regards,
Ivo
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sebastian Reichel Dec. 17, 2013, 11:25 p.m. UTC | #6
On Tue, Dec 17, 2013 at 07:58:56PM +0200, Ivajlo Dimitrov wrote:
> >On Mon, Dec 16, 2013 at 02:31:53PM +0100, Linus Walleij wrote:
> >>I am very reluctant in letting device trees specify exports of GPIOs
> >>to userspace, not so much because it's Linux-specific but for
> >>the fact that people are doing things in userspace that should not
> >>be done in userspace.
> >>
> >>Last time it was proposed I asked to the specific usecase,
> >>exactly why userspace needed this handle on a physical
> >>GPIO line, and why it can't use another userspace interface
> >>(example: leds, keys etc.)
> >There are a couple of lines ("cmt_apeslpx", "cmt_rst_rq", "cmt_en",
> >"cmt_rst", "cmt_bsi"), which are handled by ofono to do the correct
> >power sequence for the modem. The relevant ofono code is here:
> >
> >https://git.kernel.org/cgit/network/ofono/ofono.git/tree/plugins/nokia-gpio.c
> >
> >In MeeGo etc. they have a little board specific init script, which
> >exports the gpio lines and setups some symlinks. IMHO at least the
> >board specific stuff should be handled by the kernel, thus I added
> >this code to the driver. I guess you prefer to move the power
> >sequencing completly to the kernel?
> 
> Don't forget there is not only ofono, but rtcom-call-ui and all the
> telephony stack in Maemo 5 :). However, power sequencing and control
> is specific not only to the modem model, but to the firmware version
> the modem is running as well (afaik). IMO you can't simply move the
> modem power/reset/sleep control to the kernel and hope for the best,
> I am not sure there is enough documentation (if any) for this to be
> done reliably, esp on n900 with its BB5 modem. The point is that
> those gpios are used not only for the initial power-up, but for
> control of the modem state and reset (if needed) during normal
> usage. The APE reset line is an example of stuff that can't be moved
> to the kernel without providing some interface/feedback to/from the
> userspace IMO - what if she is dialing 112 at the moment the modem
> decides it is too hot and wants a device reset (or whatever reason
> there could be for a modem to request a device reset)? The same goes
> for the APE sleep request line (cmt_apeslpx) - based on what should
> the kernel decide whether to put the modem in sleep?
> 
> Sure, exporting gpios to userspace might not be the best way to
> achieve the required functionality, but every way could be argued if
> it is the best. And for sure labeling a modem "LED" won't make it
> such.

Yes, but as far as I know the kernel design rules are not bended for
nonfree userspace components. Using the nonfree Maemo stuff should
be supported by disabling the CMT driver and exporting the pins from
userspace using some board specific init script (=> this is how its
done until now).

I had a look at both ofono's and freesmartphone.org's implementation
for the GPIO handling and both implementations are very similar. I
think it should be possible to move the state machine described in
[0] into the kernel and provide a simple sysfs/uevent interface.

I was thinking of something like /sys/devices/platform/nokia-cmt/state,
which accepts "enable", "disable" and "reset" as input and outputs the
current state.

[0] https://git.kernel.org/cgit/network/ofono/ofono.git/tree/plugins/nokia-gpio.c

-- Sebastian
Linus Walleij Dec. 22, 2013, 10:22 a.m. UTC | #7
On Wed, Dec 18, 2013 at 12:25 AM, Sebastian Reichel <sre@ring0.de> wrote:

> I had a look at both ofono's and freesmartphone.org's implementation
> for the GPIO handling and both implementations are very similar. I
> think it should be possible to move the state machine described in
> [0] into the kernel and provide a simple sysfs/uevent interface.
>
> I was thinking of something like /sys/devices/platform/nokia-cmt/state,
> which accepts "enable", "disable" and "reset" as input and outputs the
> current state.
>
> [0] https://git.kernel.org/cgit/network/ofono/ofono.git/tree/plugins/nokia-gpio.c

Yes this looks like kernel code shoehorned into userspace. As it
deals with suspending/resuming hardware for example, and that is
something the kernel needs to coordinate and do uniformly across
all devices (IMO).

A while back Arun Murthy was working on creating an embedded
modem subsystem but the development stopped. However such a
subsystem is a generic problem of general interest and this would be
one of the candidates for drivers/modem I think. Sadly creating it
may be a lot of work, I don't know exactly.
http://marc.info/?l=linux-kernel&m=135027904405680&w=2

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a3e291d..74e96cc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,13 @@  config SRAM
 	  the genalloc API. It is supposed to be used for small on-chip SRAM
 	  areas found on many SoCs.
 
+config NOKIA_CMT
+	tristate "Enable CMT support"
+	help
+	If you say Y here, you will enable CMT support.
+
+	If unsure, say Y, or else you will not be able to use the CMT.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f45473e..b109e84 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,3 +53,4 @@  obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
 obj-$(CONFIG_SRAM)		+= sram.o
 obj-y				+= mic/
+obj-$(CONFIG_NOKIA_CMT)		+= nokia-cmt.o
diff --git a/drivers/misc/nokia-cmt.c b/drivers/misc/nokia-cmt.c
new file mode 100644
index 0000000..9c40cf6
--- /dev/null
+++ b/drivers/misc/nokia-cmt.c
@@ -0,0 +1,298 @@ 
+/*
+ * CMT support.
+ *
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2013 Sebastian Reichel <sre@kernel.org>
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/atomic.h>
+#include <linux/nokia-cmt.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+/**
+ * struct cmt_gpio - GPIO with name
+ * @gpio: GPIO number
+ * @name: name for the GPIO
+ */
+struct cmt_gpio {
+	int				gpio;
+	const char			*name;
+};
+
+/**
+ * struct cmt_device - CMT device data
+ * @cmt_rst_ind_tasklet: Bottom half for CMT reset line events
+ * @cmt_rst_ind_irq: IRQ number of the CMT reset line
+ * @n_head: List of notifiers registered to get CMT events
+ * @node: Link on the list of available CMTs
+ * @device: Reference to the CMT platform device
+ */
+struct cmt_device {
+	struct tasklet_struct		cmt_rst_ind_tasklet;
+	unsigned int			cmt_rst_ind_irq;
+	struct atomic_notifier_head	n_head;
+	struct list_head		node;
+	struct device			*device;
+	struct cmt_gpio			*gpios;
+	int				gpio_amount;
+};
+
+static LIST_HEAD(cmt_list);	/* List of CMT devices */
+
+int cmt_notifier_register(struct cmt_device *cmtdev, struct notifier_block *nb)
+{
+	struct cmt_device *cmt;
+	int err = -ENODEV;
+
+	if ((!cmtdev) || (!nb))
+		return -EINVAL;
+
+	list_for_each_entry(cmt, &cmt_list, node)
+		if (cmt == cmtdev) {
+			err = atomic_notifier_chain_register(&cmt->n_head, nb);
+			break;
+		}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(cmt_notifier_register);
+
+int cmt_notifier_unregister(struct cmt_device *cmtdev,
+						struct notifier_block *nb)
+{
+	struct cmt_device *cmt;
+	int err = -ENODEV;
+
+	if ((!cmtdev) || (!nb))
+		return -EINVAL;
+
+	list_for_each_entry(cmt, &cmt_list, node)
+		if (cmt == cmtdev) {
+			err = atomic_notifier_chain_unregister(&cmt->n_head,
+									nb);
+			break;
+		}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(cmt_notifier_unregister);
+
+struct cmt_device *cmt_get(const char *name)
+{
+	struct cmt_device *p, *cmt = ERR_PTR(-ENODEV);
+
+	list_for_each_entry(p, &cmt_list, node)
+		if (strcmp(name, dev_name(p->device)) == 0) {
+			cmt = p;
+			break;
+		}
+
+	return cmt;
+}
+EXPORT_SYMBOL_GPL(cmt_get);
+
+struct cmt_device *cmt_get_by_phandle(struct device_node *np,
+							const char *propname)
+{
+	struct cmt_device *p, *cmt = ERR_PTR(-EPROBE_DEFER);
+	struct device_node *cmt_np = of_parse_phandle(np, propname, 0);
+
+	if (!cmt_np)
+		return ERR_PTR(-ENOENT);
+
+	list_for_each_entry(p, &cmt_list, node)
+		if (p->device->of_node == cmt_np) {
+			cmt = p;
+			break;
+		}
+
+	of_node_put(cmt_np);
+
+	return cmt;
+}
+EXPORT_SYMBOL_GPL(cmt_get_by_phandle);
+
+void cmt_put(struct cmt_device *cmtdev)
+{
+}
+EXPORT_SYMBOL_GPL(cmt_put);
+
+static void do_cmt_rst_ind_tasklet(unsigned long cmtdev)
+{
+	struct cmt_device *cmt = (struct cmt_device *)cmtdev;
+
+	dev_dbg(cmt->device, "*** CMT rst line change detected ***\n");
+	atomic_notifier_call_chain(&cmt->n_head, CMT_RESET, NULL);
+}
+
+static irqreturn_t cmt_rst_ind_isr(int irq, void *cmtdev)
+{
+	struct cmt_device *cmt = (struct cmt_device *)cmtdev;
+
+	tasklet_schedule(&cmt->cmt_rst_ind_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static int cmt_probe(struct platform_device *pd)
+{
+	struct device_node *np = pd->dev.of_node;
+	struct cmt_device *cmt;
+	int irq, pflags, err, gpio_count, gpio_name_count, i;
+
+	if (!np) {
+		dev_err(&pd->dev, "device tree node not found\n");
+		return -ENXIO;
+	}
+
+	cmt = devm_kzalloc(&pd->dev, sizeof(*cmt), GFP_KERNEL);
+	if (!cmt) {
+		dev_err(&pd->dev, "Could not allocate memory for cmtdev\n");
+		return -ENOMEM;
+	}
+
+	cmt->device = &pd->dev;
+
+	irq = platform_get_irq(pd, 0);
+	if (irq < 0) {
+		dev_err(&pd->dev, "Invalid cmt_rst_ind interrupt\n");
+		return irq;
+	}
+
+	pflags = irq_get_trigger_type(irq);
+
+	tasklet_init(&cmt->cmt_rst_ind_tasklet, do_cmt_rst_ind_tasklet,
+							(unsigned long)cmt);
+	err = devm_request_irq(&pd->dev, irq, cmt_rst_ind_isr,
+		IRQF_DISABLED | pflags, "cmt_rst_ind", cmt);
+	if (err < 0) {
+		dev_err(&pd->dev, "Request cmt_rst_ind irq(%d) failed (flags %d)\n",
+			irq, pflags);
+		return err;
+	}
+	enable_irq_wake(irq);
+
+	ATOMIC_INIT_NOTIFIER_HEAD(&cmt->n_head);
+	list_add(&cmt->node, &cmt_list);
+
+	cmt->cmt_rst_ind_irq = irq;
+	platform_set_drvdata(pd, cmt);
+
+	gpio_count = of_gpio_count(np);
+	gpio_name_count = of_property_count_strings(np, "gpio-names");
+
+	if(gpio_count != gpio_name_count) {
+		dev_err(&pd->dev, "number of gpios does not equal number of gpio names\n");
+		return -EINVAL;
+	}
+
+	cmt->gpios = devm_kzalloc(&pd->dev, gpio_count*sizeof(struct cmt_gpio),
+								GFP_KERNEL);
+	if (cmt->gpios == NULL) {
+		dev_err(&pd->dev, "Could not allocate memory for gpios\n");
+		return -ENOMEM;
+	}
+
+	cmt->gpio_amount = gpio_count;
+
+	for (i = 0; i < gpio_count; i++) {
+		cmt->gpios[i].gpio = of_get_gpio(np, i);
+
+		if (cmt->gpios[i].gpio < 0)
+			return cmt->gpios[i].gpio;
+
+		err = of_property_read_string_index(np, "gpio-names", i,
+							&(cmt->gpios[i].name));
+		if (err)
+			return err;
+
+		err = devm_gpio_request_one(&pd->dev, cmt->gpios[i].gpio,
+							GPIOF_OUT_INIT_LOW,
+							cmt->gpios[i].name);
+		if (err)
+			return err;
+
+		err = gpio_export(cmt->gpios[i].gpio, 0);
+		if (err)
+			return err;
+
+		err = gpio_export_link(&pd->dev, cmt->gpios[i].name,
+							cmt->gpios[i].gpio);
+		if (err)
+			return err;
+	}
+
+	dev_info(&pd->dev, "loaded sucessfully\n");
+
+	return 0;
+}
+
+static int cmt_remove(struct platform_device *pd)
+{
+	struct cmt_device *cmt = platform_get_drvdata(pd);
+	int i;
+
+	if (!cmt)
+		return 0;
+	platform_set_drvdata(pd, NULL);
+	list_del(&cmt->node);
+	disable_irq_wake(cmt->cmt_rst_ind_irq);
+	tasklet_kill(&cmt->cmt_rst_ind_tasklet);
+
+	for (i=0; i < cmt->gpio_amount; i++)
+		sysfs_remove_link(&pd->dev.kobj, cmt->gpios[i].name);
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id cmt_of_match[] = {
+	{ .compatible = "nokia,cmt", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cmt_of_match);
+#endif
+
+static struct platform_driver cmt_driver = {
+	.driver = {
+		.name	= "nokia-cmt",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(cmt_of_match),
+	},
+	.probe = cmt_probe,
+	.remove = cmt_remove,
+};
+
+module_platform_driver(cmt_driver);
+MODULE_AUTHOR("Carlos Chinea, Nokia");
+MODULE_DESCRIPTION("CMT related support");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nokia-cmt");
diff --git a/include/linux/nokia-cmt.h b/include/linux/nokia-cmt.h
new file mode 100644
index 0000000..2f19a8b
--- /dev/null
+++ b/include/linux/nokia-cmt.h
@@ -0,0 +1,46 @@ 
+/*
+ * CMT support header
+ *
+ * Copyright (C) 2009 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __NOKIA_CMT_H__
+#define __NOKIA_CMT_H__
+
+#include <linux/notifier.h>
+#include <linux/of.h>
+
+/*
+ * NOKIA CMT notifier events
+ */
+enum {
+	CMT_RESET,
+};
+
+struct cmt_device;
+
+struct cmt_device *cmt_get(const char *name);
+struct cmt_device *cmt_get_by_phandle(struct device_node *np,
+							const char *propname);
+void cmt_put(struct cmt_device *cmt);
+int cmt_notifier_register(struct cmt_device *cmtdev,
+						struct notifier_block *nb);
+int cmt_notifier_unregister(struct cmt_device *cmtdev,
+						struct notifier_block *nb);
+#endif /* __NOKIA_CMT_H__ */