]> rtime.felk.cvut.cz Git - shark/motorek-5200.git/blobdiff - motorek.c
Add load command to the boot script required for newer novaboot version.
[shark/motorek-5200.git] / motorek.c
index 6be72fcd92cb1bdce1aa779bd83f9a03045096bd..1ab1bf8a6307af56363cc6061849e2c07b1a430d 100644 (file)
--- a/motorek.c
+++ b/motorek.c
@@ -1,16 +1,33 @@
+/*
+ *     Driver for DC motor connected to MPC5200 based boards.
+ *
+ *     The motor is used for education at Czech Technical University
+ *     in Prague.
+ *
+ *     Authors:
+ *     Michal Sojka            <sojkam1@fel.cvut.cz>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mod_devicetable.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
-#include <asm-powerpc/mpc52xx.h>
+#include <asm/mpc52xx.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 
 struct motorek {
-       struct mpc52xx_gpt *pwmf, *pwmb;
+       struct mpc52xx_gpt *pwmf, *pwmb, *irca, *ircb;
        atomic_t pos;
        int irq;
        int action;
+       int last_irc_state;
 };
 
 static ssize_t show_position(struct device *dev,
@@ -55,7 +72,13 @@ DEVICE_ATTR(action,0644,show_action,store_action);
 #define MPC52xx_GPT_MODE_PWM     3
 #define MPC52xx_GPT_MODE_GPIO    4
 
-#define MPC52xx_GPT_PWM_OP       (1<<8)
+#define MPC52xx_GPT_MODE_GPIO_IN   (0<<4)
+#define MPC52xx_GPT_MODE_GPIO_OUT0 (2<<4)
+#define MPC52xx_GPT_MODE_GPIO_OUT1 (1<<4)
+
+#define MPC52xx_GPT_STATUS_PIN (1<<8)
+
+#define MPC52xx_GPT_PWM_OP       (1<<8) /* PWM polarity */
 
 /* Base clock 132 MHz
  * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
@@ -69,7 +92,7 @@ static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
 
 }
 
-static void __devinit pwm_init(struct mpc52xx_gpt *gpt)
+static void __devinit init_pwn(struct mpc52xx_gpt *gpt)
 {
        //while (((unsigned)gpt & 0xff) != 0x50) gpt++;
        out_be32(&gpt->count, (1<<16) | PWM_PERIOD);
@@ -82,6 +105,13 @@ static void __devinit pwm_init(struct mpc52xx_gpt *gpt)
        //printk("pwm: %p\n", gpt);
 }
 
+static void __devinit init_input(struct mpc52xx_gpt *gpt)
+{
+       out_be32(&gpt->mode,
+                MPC52xx_GPT_MODE_GPIO |
+                MPC52xx_GPT_MODE_GPIO_IN);
+}
+
 static void  pwm_done(struct mpc52xx_gpt *gpt)
 {
        out_be32(&gpt->mode, 0);
@@ -103,9 +133,10 @@ static void motorek_action(struct motorek *m, int action_permile)
 
 static int __devinit motorek_init(struct motorek *m)
 {
-       pwm_init(m->pwmf);
-       pwm_init(m->pwmb);
-       //motorek_action(m, +0);
+       init_pwn(m->pwmf);
+       init_pwn(m->pwmb);
+       init_input(m->irca);
+       init_input(m->ircb);
        return 0;
 }
 
@@ -115,34 +146,64 @@ static int motorek_done(struct motorek *m)
        pwm_done(m->pwmb);
        return 0;
 }
+#define TRANSITION(old, new) (((old) << 2) | new)
+static const int table[16] = {
+       [TRANSITION(0,1)] = +1,
+       [TRANSITION(1,3)] = +1,
+       [TRANSITION(3,2)] = +1,
+       [TRANSITION(2,0)] = +1,
+
+       [TRANSITION(1,0)] = -1,
+       [TRANSITION(3,1)] = -1,
+       [TRANSITION(2,3)] = -1,
+       [TRANSITION(0,2)] = -1,
+};
 
 static irqreturn_t motorek_irq(int irq, void *dev_id)
 {
        struct motorek *m = dev_id;
-       atomic_inc(&m->pos);
+       int irc_state =
+               ((in_be32(&m->irca->status) & MPC52xx_GPT_STATUS_PIN) ? 1 : 0) | \
+               ((in_be32(&m->ircb->status) & MPC52xx_GPT_STATUS_PIN) ? 2 : 0);
+       atomic_add(table[TRANSITION(m->last_irc_state, irc_state)], &m->pos);
+       m->last_irc_state = irc_state;
        return IRQ_HANDLED;
 }
 
-struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle(const phandle *phandle)
+static struct of_device_id mpc5200_gpt_match[] = {
+       { .compatible = "mpc5200-gpt", },
+       { .compatible = "fsl,mpc5200-gpt", },
+       {},
+};
+
+struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle_prop(struct device_node *dn, const char *prop)
 {
        struct device_node *np;
-       struct mpc52xx_gpt __iomem *gpt;
+       struct mpc52xx_gpt __iomem *gpt = NULL;
+       const phandle *phandle;
 
+       phandle = of_get_property(dn, prop, NULL);
        if (!phandle)
                return NULL;
 
        np = of_find_node_by_phandle(*phandle);
        if (!np)
                return NULL;
+
+       if (!of_match_node(mpc5200_gpt_match, np)) {
+               printk(KERN_ERR "property %s doesn't refer to GPT\n", prop);
+               goto out;
+       }
+
        gpt = of_iomap(np, 0);
+out:
        of_node_put(np);
        return gpt;
 }
 
-static int __devinit motorek_probe(struct of_device* dev,
-                                  const struct of_device_id *match)
+static int __devinit motorek_probe(struct platform_device* dev)
 {
-       struct device_node *dn = dev->node;
+       struct device_node *dn = dev->dev.of_node;
        struct motorek *m;
        int err;
 
@@ -151,27 +212,30 @@ static int __devinit motorek_probe(struct of_device* dev,
                return -ENOMEM;
 
        err = -ENODEV;
-       
-       m->pwmf = iomap_gpt_by_phandle(of_get_property(dn, "pwmf", NULL));
+
+       m->pwmf = iomap_gpt_by_phandle_prop(dn, "pwmf");
        if (!m->pwmf)
                goto err_free;
-       
-       m->pwmb = iomap_gpt_by_phandle(of_get_property(dn, "pwmb", NULL));
+       m->pwmb = iomap_gpt_by_phandle_prop(dn, "pwmb");
        if (!m->pwmb)
-               goto err_unmapf;
-       
+               goto err_unmap_pf;
+       m->irca = iomap_gpt_by_phandle_prop(dn, "irca");
+       if (!m->irca)
+               goto err_unmap_pb;
+       m->ircb = iomap_gpt_by_phandle_prop(dn, "ircb");
+       if (!m->ircb)
+               goto err_unmap_ia;
+
        m->irq = irq_of_parse_and_map(dn, 0);
        if (m->irq == NO_IRQ)
-               goto err_unmapb;
-
+               goto err_unmap_ib;
        err = request_irq(m->irq, motorek_irq, 0, "motorek", m);
        if (err)
-               goto err_unmapb;
+               goto err_unmap_ib;
 
        motorek_init(m);
 
        platform_set_drvdata(dev, m);
-
        err = device_create_file(&dev->dev,&dev_attr_position);
        if (err)
                goto err_irq;
@@ -185,16 +249,20 @@ static int __devinit motorek_probe(struct of_device* dev,
 
 err_irq:
        free_irq(m->irq, m);
-err_unmapb:
+err_unmap_ib:
+       iounmap(m->pwmb);
+err_unmap_ia:
+       iounmap(m->pwmf);
+err_unmap_pb:
        iounmap(m->pwmb);
-err_unmapf:
+err_unmap_pf:
        iounmap(m->pwmf);
 err_free:
        kfree(m);
        return err;
 }
 
-static int __devexit motorek_remove(struct of_device* dev)
+static int __devexit motorek_remove(struct platform_device* dev)
 {
        struct motorek *m;
 
@@ -210,19 +278,21 @@ static struct of_device_id motorek_match[] = {
        { .type = "motorek", },
        {},
 };
-static struct of_platform_driver motorek_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "motorek",
-       .match_table    = motorek_match,
+static struct platform_driver motorek_driver = {
        .probe          = motorek_probe,
        .remove         = __devexit_p(motorek_remove),
+       .driver         = {
+               .name           = "motorek",
+               .owner          = THIS_MODULE,
+               .of_match_table = motorek_match,
+       },
 };
 
 
 static int __init motorek_init_module(void)
 {
        int ret;
-       struct of_device *dev;
+       struct platform_device *dev;
        struct device_node *dn;
 
        for_each_node_by_type(dn, "motorek") {
@@ -233,13 +303,13 @@ static int __init motorek_init_module(void)
                }
        };
 
-       ret = of_register_platform_driver(&motorek_driver);
+       ret = platform_driver_register(&motorek_driver);
        return ret;
 }
 
 static void __exit motorek_exit_module(void)
 {
-       struct of_device *dev;
+       struct platform_device *dev;
        struct device_node *dn;
 
        for_each_node_by_type(dn, "motorek") {
@@ -247,7 +317,7 @@ static void __exit motorek_exit_module(void)
                        of_device_unregister(dev);
                }
        }
-       of_unregister_platform_driver(&motorek_driver);
+       platform_driver_unregister(&motorek_driver);
 }
 
 module_init(motorek_init_module);