]> rtime.felk.cvut.cz Git - shark/motorek-5200.git/blob - motorek.c
Both directions work; added action attribute
[shark/motorek-5200.git] / motorek.c
1 #include <linux/module.h>
2 #include <linux/platform_device.h>
3 #include <linux/mod_devicetable.h>
4 #include <linux/of.h>
5 #include <asm-powerpc/mpc52xx.h>
6 #include <linux/interrupt.h>
7
8 struct motorek {
9         struct mpc52xx_gpt *pwmf, *pwmb;
10         atomic_t pos;
11         int irq;
12         int action;
13 };
14
15 static ssize_t show_position(struct device *dev,
16                             struct device_attribute *attr, char *buf)
17 {
18         struct platform_device  *pdev = to_platform_device(dev);
19         struct motorek          *m = platform_get_drvdata(pdev);
20
21         int len = snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&m->pos));
22         return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
23 }
24
25 static ssize_t show_action(struct device *dev,
26                            struct device_attribute *attr, char *buf)
27 {
28         struct platform_device  *pdev = to_platform_device(dev);
29         struct motorek          *m = platform_get_drvdata(pdev);
30
31         int len = snprintf(buf, PAGE_SIZE, "%d\n", m->action);
32         return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
33 }
34
35 static void motorek_action(struct motorek *m, int action_permile);
36 static ssize_t store_action(struct device *dev, struct device_attribute *attr,
37                             const char *buf, size_t count)
38 {
39         struct platform_device  *pdev = to_platform_device(dev);
40         struct motorek          *m = platform_get_drvdata(pdev);
41
42         int a;
43         sscanf(buf, "%d", &a);
44         motorek_action(m, a);
45         return strnlen(buf, PAGE_SIZE);
46 }
47
48 DEVICE_ATTR(position,0444,show_position,NULL);
49 DEVICE_ATTR(action,0644,show_action,store_action);
50
51 #define MPC52xx_GPT_MODE_DISABLED 0
52 #define MPC52xx_GPT_MODE_INCAPT   1
53 #define MPC52xx_GPT_MODE_OUTCMP   2
54 #define MPC52xx_GPT_MODE_PWM      3
55 #define MPC52xx_GPT_MODE_GPIO     4
56
57 #define MPC52xx_GPT_PWM_OP        (1<<8)
58
59 /* Base clock 132 MHz
60  * (/proc/device-tree/cpus/PowerPC,5200@0/bus-frequency) */
61 #define PWM_PERIOD 6600         /* = 132 000 kHz / 20 kHz  */
62
63
64 static void pwm_width(struct mpc52xx_gpt *gpt, u16 width)
65 {
66         out_be32(&gpt->pwm, (width<<16) | MPC52xx_GPT_PWM_OP);
67 }
68
69 static void __devinit pwm_init(struct mpc52xx_gpt *gpt)
70 {
71         out_be32(&gpt->count, (1<<16) | PWM_PERIOD);
72         pwm_width(gpt, 0);
73         out_be32(&gpt->mode, MPC52xx_GPT_MODE_PWM);
74 }
75
76 static void  pwm_done(struct mpc52xx_gpt *gpt)
77 {
78         out_be32(&gpt->mode, 0);
79         out_be32(&gpt->count, 0);
80         pwm_width(gpt, 0);
81 }
82
83 static void motorek_action(struct motorek *m, int action_permile)
84 {
85         m->action = action_permile;
86         if (action_permile >= 0) {
87                 pwm_width(m->pwmb, 0);
88                 pwm_width(m->pwmf, +action_permile*PWM_PERIOD/1000);
89         } else {
90                 pwm_width(m->pwmf, 0);
91                 pwm_width(m->pwmb, -action_permile*PWM_PERIOD/1000);
92         }
93 }
94
95 static int __devinit motorek_init(struct motorek *m)
96 {
97         pwm_init(m->pwmf);
98         pwm_init(m->pwmb);
99         //motorek_action(m, +0);
100         return 0;
101 }
102
103 static int motorek_done(struct motorek *m)
104 {
105         pwm_done(m->pwmf);
106         pwm_done(m->pwmb);
107         return 0;
108 }
109
110 static irqreturn_t motorek_irq(int irq, void *dev_id)
111 {
112         struct motorek *m = dev_id;
113         atomic_inc(&m->pos);
114         return IRQ_HANDLED;
115 }
116
117 /* mpc5200 device tree match tables */
118 static struct of_device_id mpc5200_gpt_ids[] __initdata = {
119         { .compatible = "fsl,mpc5200-gpt", },
120         { .compatible = "mpc5200-gpt", },
121         {}
122 };
123
124 static int __devinit motorek_probe(struct platform_device *dev)
125 {
126         struct device_node *np;
127         struct motorek *m;
128         int err;
129
130         m = kzalloc(sizeof(*m), GFP_KERNEL);
131         if (!m)
132                 return -ENOMEM;
133
134         for_each_matching_node(np, mpc5200_gpt_ids) {
135                 const void *prop;
136                 int i;
137                 
138                 prop = of_get_property(np, "cell-index", NULL);
139                 if (prop) {
140                         i = *(u32 *)prop;
141                         switch (i) {
142                         case 2:
143                                 m->pwmf = of_iomap(np, 0);
144                                 break;
145                         case 3:
146                                 m->pwmb = of_iomap(np, 0);
147                                 break;
148                         }
149                 }
150         }
151         if (!m->pwmf || !m->pwmb) {
152                 printk(KERN_ERR "%s() mmap failed\n", __func__);
153                 return -ENXIO;
154         }
155
156 /*      /\* FIXME: This should be specified in device-tree *\/ */
157 /*      m->irq = irq_create_of_mapping( */
158
159 /*      err = request_irq(m->irq, motorek_irq, 0, "motorek", m); */
160 /*      if (err) */
161 /*              return err; */
162
163         motorek_init(m);
164
165         platform_set_drvdata(dev, m);
166
167         err = device_create_file(&dev->dev,&dev_attr_position);
168         if (err)
169                 return err;
170         err = device_create_file(&dev->dev,&dev_attr_action);
171         if (err)
172                 return err;
173
174         printk(KERN_NOTICE "Motorek initialized\n");
175
176         return 0;
177 }
178
179 static int __devexit motorek_remove(struct platform_device *dev)
180 {
181         struct motorek *m;
182         m = platform_get_drvdata(dev);
183
184         printk(KERN_NOTICE "Removing motorek\n");
185
186         motorek_done(m);
187         return 0;
188 }
189
190
191
192 static struct platform_driver motorek_driver = {
193         .probe          = motorek_probe,
194         .remove         = __devexit_p(motorek_remove),
195         .driver         = {
196                 .name   = "motorek",
197                 .owner  = THIS_MODULE,
198         },
199 };
200
201
202 static struct platform_device *motorek_pdev;
203
204 static int __init motorek_init_module(void)
205 {
206         int ret;
207         motorek_pdev = platform_device_alloc("motorek", 0);
208         if (!motorek_pdev)
209                 return -ENOMEM;
210         ret = platform_device_add(motorek_pdev);
211         if (ret) {
212                 platform_device_put(motorek_pdev);
213                 return ret;
214         }
215
216         ret = platform_driver_register(&motorek_driver);
217         return 0;
218 }
219 module_init(motorek_init_module);
220
221 static void __exit motorek_exit_module(void)
222 {
223         platform_device_unregister(motorek_pdev);
224         platform_driver_unregister(&motorek_driver);
225 }
226 module_exit(motorek_exit_module);
227
228
229 MODULE_LICENSE("GPL v2");
230 MODULE_VERSION("0.1");
231 MODULE_AUTHOR("Michal Sojka <sojkam1@fel.cvut.cz>");