2 * Driver for DC motor connected to MPC5200 based boards.
4 * The motor is used for education at Czech Technical University
8 * Michal Sojka <sojkam1@fel.cvut.cz>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/mod_devicetable.h>
20 #include <linux/of_platform.h>
21 #include <asm/mpc52xx.h>
22 #include <linux/interrupt.h>
25 struct mpc52xx_gpt *pwmf, *pwmb, *irca, *ircb;
32 static ssize_t show_position(struct device *dev,
33 struct device_attribute *attr, char *buf)
35 struct platform_device *pdev = to_platform_device(dev);
36 struct motorek *m = platform_get_drvdata(pdev);
38 int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos));
39 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
42 static ssize_t show_action(struct device *dev,
43 struct device_attribute *attr, char *buf)
45 struct platform_device *pdev = to_platform_device(dev);
46 struct motorek *m = platform_get_drvdata(pdev);
48 int len = snprintf(buf, PAGE_SIZE, "%d\n", m->action);
49 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
52 static void motorek_action(struct motorek *m, int action_permile);
53 static ssize_t store_action(struct device *dev, struct device_attribute *attr,
54 const char *buf, size_t count)
56 struct platform_device *pdev = to_platform_device(dev);
57 struct motorek *m = platform_get_drvdata(pdev);
60 sscanf(buf, "%d", &a);
62 return strnlen(buf, PAGE_SIZE);
65 DEVICE_ATTR(position,0444,show_position,NULL);
66 DEVICE_ATTR(action,0644,show_action,store_action);
68 #define MPC52xx_GPT_MODE_DISABLED 0
69 #define MPC52xx_GPT_MODE_INCAPT 1
70 #define MPC52xx_GPT_MODE_OUTCMP 2
71 #define MPC52xx_GPT_MODE_PWM 3
72 #define MPC52xx_GPT_MODE_GPIO 4
74 #define MPC52xx_GPT_MODE_GPIO_IN (0<<4)
75 #define MPC52xx_GPT_MODE_GPIO_OUT0 (2<<4)
76 #define MPC52xx_GPT_MODE_GPIO_OUT1 (1<<4)
78 #define MPC52xx_GPT_STATUS_PIN (1<<8)
80 #define MPC52xx_GPT_PWM_OP (1<<8) /* PWM polarity */
83 * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
84 #define PWM_PERIOD 6600 /* = 132 000 kHz / 20 kHz */
87 static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
89 out_be32(&gpt->pwm, (width<<16) | MPC52xx_GPT_PWM_OP);
90 //printk("pwm: %p=0x%x\n", gpt, width);
94 static void __devinit init_pwn(struct mpc52xx_gpt *gpt)
96 //while (((unsigned)gpt & 0xff) != 0x50) gpt++;
97 out_be32(&gpt->count, (1<<16) | PWM_PERIOD);
99 out_be32(&gpt->mode, MPC52xx_GPT_MODE_PWM);
101 //out_be32(&gpt->pwm, (500<<16) | MPC52xx_GPT_PWM_OP); /* REMOVE ME */
103 //out_be32(&gpt->mode, MPC52xx_GPT_MODE_GPIO | (2<<4));
104 //printk("pwm: %p\n", gpt);
107 static void __devinit init_input(struct mpc52xx_gpt *gpt)
110 MPC52xx_GPT_MODE_GPIO |
111 MPC52xx_GPT_MODE_GPIO_IN);
114 static void pwm_done(struct mpc52xx_gpt *gpt)
116 out_be32(&gpt->mode, 0);
117 out_be32(&gpt->count, 0);
121 static void motorek_action(struct motorek *m, int action_permile)
123 m->action = action_permile;
124 if (action_permile >= 0) {
125 pwm_width(m->pwmb, 0);
126 pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000);
128 pwm_width(m->pwmf, 0);
129 pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000);
133 static int __devinit motorek_init(struct motorek *m)
142 static int motorek_done(struct motorek *m)
148 #define TRANSITION(old, new) (((old) << 2) | new)
149 static const int table[16] = {
150 [TRANSITION(0,1)] = +1,
151 [TRANSITION(1,3)] = +1,
152 [TRANSITION(3,2)] = +1,
153 [TRANSITION(2,0)] = +1,
155 [TRANSITION(1,0)] = -1,
156 [TRANSITION(3,1)] = -1,
157 [TRANSITION(2,3)] = -1,
158 [TRANSITION(0,2)] = -1,
161 static irqreturn_t motorek_irq(int irq, void *dev_id)
163 struct motorek *m = dev_id;
165 ((in_be32(&m->irca->status) & MPC52xx_GPT_STATUS_PIN) ? 1 : 0) | \
166 ((in_be32(&m->ircb->status) & MPC52xx_GPT_STATUS_PIN) ? 2 : 0);
167 atomic_add(table[TRANSITION(m->last_irc_state, irc_state)], &m->pos);
168 m->last_irc_state = irc_state;
172 static struct of_device_id mpc5200_gpt_match[] = {
173 { .compatible = "mpc5200-gpt", },
174 { .compatible = "fsl,mpc5200-gpt", },
178 struct mpc52xx_gpt __iomem *iomap_gpt_by_phandle_prop(struct device_node *dn, const char *prop)
180 struct device_node *np;
181 struct mpc52xx_gpt __iomem *gpt = NULL;
182 const phandle *phandle;
184 phandle = of_get_property(dn, prop, NULL);
188 np = of_find_node_by_phandle(*phandle);
192 if (!of_match_node(mpc5200_gpt_match, np)) {
193 printk(KERN_ERR "property %s doesn't refer to GPT\n", prop);
197 gpt = of_iomap(np, 0);
203 static int __devinit motorek_probe(struct of_device* dev,
204 const struct of_device_id *match)
206 struct device_node *dn = dev->node;
210 m = kzalloc(sizeof(*m), GFP_KERNEL);
216 m->pwmf = iomap_gpt_by_phandle_prop(dn, "pwmf");
219 m->pwmb = iomap_gpt_by_phandle_prop(dn, "pwmb");
222 m->irca = iomap_gpt_by_phandle_prop(dn, "irca");
225 m->ircb = iomap_gpt_by_phandle_prop(dn, "ircb");
229 m->irq = irq_of_parse_and_map(dn, 0);
230 if (m->irq == NO_IRQ)
232 err = request_irq(m->irq, motorek_irq, 0, "motorek", m);
238 platform_set_drvdata(dev, m);
239 err = device_create_file(&dev->dev,&dev_attr_position);
242 err = device_create_file(&dev->dev,&dev_attr_action);
246 printk(KERN_NOTICE "Motorek initialized\n");
265 static int __devexit motorek_remove(struct of_device* dev)
269 printk(KERN_NOTICE "Removing motorek\n");
270 m = platform_get_drvdata(dev);
277 static struct of_device_id motorek_match[] = {
278 { .type = "motorek", },
281 static struct of_platform_driver motorek_driver = {
282 .owner = THIS_MODULE,
284 .match_table = motorek_match,
285 .probe = motorek_probe,
286 .remove = __devexit_p(motorek_remove),
290 static int __init motorek_init_module(void)
293 struct of_device *dev;
294 struct device_node *dn;
296 for_each_node_by_type(dn, "motorek") {
297 if (!of_find_device_by_node(dn)) {
298 dev = of_platform_device_create(dn, NULL, NULL);
304 ret = of_register_platform_driver(&motorek_driver);
308 static void __exit motorek_exit_module(void)
310 struct of_device *dev;
311 struct device_node *dn;
313 for_each_node_by_type(dn, "motorek") {
314 while ((dev = of_find_device_by_node(dn))) {
315 of_device_unregister(dev);
318 of_unregister_platform_driver(&motorek_driver);
321 module_init(motorek_init_module);
322 module_exit(motorek_exit_module);
325 MODULE_LICENSE("GPL v2");
326 MODULE_VERSION("0.1");
327 MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");