]> rtime.felk.cvut.cz Git - shark/motorek-5200.git/commitdiff
Initial commit
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 15 Jan 2009 09:05:49 +0000 (10:05 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 15 Jan 2009 09:05:49 +0000 (10:05 +0100)
Onw PWM is working

Makefile [new file with mode: 0644]
motorek.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..7ba6fa2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(KERNELRELEASE),)
+# kbuild part of makefile
+obj-m  := motorek.o
+
+else
+# Normal Makefile
+
+KERNELDIR := /lib/modules/`uname -r`/build
+all::
+       $(MAKE) -C $(KERNELDIR) M=`pwd` $@
+
+endif
+
diff --git a/motorek.c b/motorek.c
new file mode 100644 (file)
index 0000000..98a2db1
--- /dev/null
+++ b/motorek.c
@@ -0,0 +1,198 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <asm-powerpc/mpc52xx.h>
+#include <linux/interrupt.h>
+
+struct motorek {
+       struct mpc52xx_gpt *pwmf, *pwmb;
+       atomic_t pos;
+       int irq;
+};
+
+static ssize_t show_position(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct platform_device  *pdev = to_platform_device(dev);
+       struct motorek          *m = platform_get_drvdata(pdev);
+
+       int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos));
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+DEVICE_ATTR(position,0444,show_position,NULL);
+
+#define MPC52xx_GPT_MODE_DISABLED 0
+#define MPC52xx_GPT_MODE_INCAPT   1
+#define MPC52xx_GPT_MODE_OUTCMP          2
+#define MPC52xx_GPT_MODE_PWM     3
+#define MPC52xx_GPT_MODE_GPIO    4
+
+#define MPC52xx_GPT_PWM_OP       (1<<8)
+
+/* Base clock 132 MHz
+ * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
+#define PWM_PERIOD 6600                /* = 132 000 kHz / 20 kHz  */
+
+
+static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
+{
+       gpt->pwm = (width<<16) | MPC52xx_GPT_PWM_OP;
+}
+
+static void __devinit pwm_init(struct mpc52xx_gpt *gpt)
+{
+       gpt->count = (1<<16) | PWM_PERIOD;
+       pwm_width(gpt, 0);
+       gpt->mode = MPC52xx_GPT_MODE_PWM;
+}
+
+static void  pwm_done(struct mpc52xx_gpt *gpt)
+{
+       gpt->mode = 0;
+       gpt->count = 0;
+       pwm_width(gpt, 0);
+}
+
+static void motorek_action(struct motorek *m, int action_permile)
+{
+       if (action_permile >= 0) {
+               pwm_width(m->pwmb, 0);
+               pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000);
+       } else {
+               pwm_width(m->pwmf, 0);
+               pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000);
+       }
+}
+
+static int __devinit motorek_init(struct motorek *m)
+{
+       pwm_init(m->pwmf);
+       pwm_init(m->pwmb);
+       motorek_action(m, +45);
+       return 0;
+}
+
+static int motorek_done(struct motorek *m)
+{
+       pwm_done(m->pwmf);
+       pwm_done(m->pwmb);
+       return 0;
+}
+
+static irqreturn_t motorek_irq(int irq, void *dev_id)
+{
+       struct motorek *m = dev_id;
+       atomic_inc(&m->pos);
+       return IRQ_HANDLED;
+}
+
+/* mpc5200 device tree match tables */
+static struct of_device_id mpc5200_gpt_ids[] __initdata = {
+       { .compatible = "fsl,mpc5200-gpt", },
+       { .compatible = "mpc5200-gpt", },
+       {}
+};
+
+static int __devinit motorek_probe(struct platform_device *dev)
+{
+       struct device_node *np;
+       struct motorek *m;
+       int err;
+
+       m = kzalloc(sizeof(*m), GFP_KERNEL);
+       if (!m)
+               return -ENOMEM;
+
+       for_each_matching_node(np, mpc5200_gpt_ids) {
+               const void *prop;
+               int i;
+               
+               prop = of_get_property(np, "cell-index", NULL);
+               if (prop) {
+                       i = *(u32 *)prop;
+                       switch (i) {
+                       case 1:
+                               m->pwmf = of_iomap(np, 0);
+                               break;
+                       case 2:
+                               m->pwmb = of_iomap(np, 0);
+                               break;
+                       }
+               }
+       }
+       if (!m->pwmf || !m->pwmb) {
+               printk(KERN_ERR "%s() mmap failed\n", __func__);
+               return -ENXIO;
+       }
+
+/*     /\* FIXME: This should be specified in device-tree *\/ */
+/*     m->irq = irq_create_of_mapping( */
+
+/*     err = request_irq(m->irq, motorek_irq, 0, "motorek", m); */
+/*     if (err) */
+/*             return err; */
+
+       motorek_init(m);
+
+       platform_set_drvdata(dev, m);
+
+       err = device_create_file(&dev->dev,&dev_attr_position);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int __devexit motorek_remove(struct platform_device *dev)
+{
+       struct motorek *m;
+       m = platform_get_drvdata(dev);
+
+       motorek_done(m);
+       return 0;
+}
+
+
+
+static struct platform_driver motorek_driver = {
+       .probe          = motorek_probe,
+       .remove         = __devexit_p(motorek_remove),
+       .driver         = {
+               .name   = "motorek",
+               .owner  = THIS_MODULE,
+       },
+};
+
+
+static struct platform_device *motorek_pdev;
+
+static int __init motorek_init_module(void)
+{
+       int ret;
+       motorek_pdev = platform_device_alloc("motorek", 0);
+       if (!motorek_pdev)
+               return -ENOMEM;
+       ret = platform_device_add(motorek_pdev);
+       if (ret) {
+               platform_device_put(motorek_pdev);
+               return ret;
+       }
+
+       ret = platform_driver_register(&motorek_driver);
+       return 0;
+}
+module_init(motorek_init_module);
+
+static void __exit motorek_exit_module(void)
+{
+       platform_device_unregister(motorek_pdev);
+       platform_driver_unregister(&motorek_driver);
+}
+module_exit(motorek_exit_module);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");