OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * A low-level PATA driver to handle a Compact Flash connected on the |
||
3 | * Mikrotik's RouterBoard 153 board. |
||
4 | * |
||
5 | * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> |
||
6 | * |
||
7 | * This file was based on: drivers/ata/pata_ixp4xx_cf.c |
||
8 | * Copyright (C) 2006-07 Tower Technologies |
||
9 | * Author: Alessandro Zummo <a.zummo@towertech.it> |
||
10 | * |
||
11 | * Also was based on the driver for Linux 2.4.xx published by Mikrotik for |
||
12 | * their RouterBoard 1xx and 5xx series devices. The original Mikrotik code |
||
13 | * seems not to have a license. |
||
14 | * |
||
15 | * This program is free software; you can redistribute it and/or modify it |
||
16 | * under the terms of the GNU General Public License version 2 as published |
||
17 | * by the Free Software Foundation. |
||
18 | * |
||
19 | */ |
||
20 | |||
21 | #include <linux/kernel.h> |
||
22 | #include <linux/module.h> |
||
23 | #include <linux/io.h> |
||
24 | #include <linux/interrupt.h> |
||
25 | #include <linux/irq.h> |
||
26 | #include <linux/gpio.h> |
||
27 | #include <linux/platform_device.h> |
||
28 | |||
29 | #include <linux/libata.h> |
||
30 | #include <scsi/scsi_host.h> |
||
31 | |||
32 | #define DRV_NAME "pata-rb153-cf" |
||
33 | #define DRV_VERSION "0.5.0" |
||
34 | #define DRV_DESC "PATA driver for RouterBOARD 153 Compact Flash" |
||
35 | |||
36 | #define RB153_CF_MAXPORTS 1 |
||
37 | #define RB153_CF_IO_DELAY 100 |
||
38 | |||
39 | #define RB153_CF_REG_CMD 0x0800 |
||
40 | #define RB153_CF_REG_CTRL 0x080E |
||
41 | #define RB153_CF_REG_DATA 0x0C00 |
||
42 | |||
43 | struct rb153_cf_info { |
||
44 | void __iomem *iobase; |
||
45 | unsigned int gpio_line; |
||
46 | int frozen; |
||
47 | unsigned int irq; |
||
48 | }; |
||
49 | |||
50 | static inline void rb153_pata_finish_io(struct ata_port *ap) |
||
51 | { |
||
52 | struct rb153_cf_info *info = ap->host->private_data; |
||
53 | |||
54 | /* FIXME: Keep previous delay. If this is merely a fence then |
||
55 | * ata_sff_sync might be sufficient. */ |
||
56 | ata_sff_dma_pause(ap); |
||
57 | ndelay(RB153_CF_IO_DELAY); |
||
58 | |||
59 | irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); |
||
60 | } |
||
61 | |||
62 | static void rb153_pata_exec_command(struct ata_port *ap, |
||
63 | const struct ata_taskfile *tf) |
||
64 | { |
||
65 | writeb(tf->command, ap->ioaddr.command_addr); |
||
66 | rb153_pata_finish_io(ap); |
||
67 | } |
||
68 | |||
69 | static unsigned int rb153_pata_data_xfer(struct ata_device *adev, |
||
70 | unsigned char *buf, |
||
71 | unsigned int buflen, |
||
72 | int write_data) |
||
73 | { |
||
74 | void __iomem *ioaddr = adev->link->ap->ioaddr.data_addr; |
||
75 | unsigned int t; |
||
76 | |||
77 | t = buflen; |
||
78 | if (write_data) { |
||
79 | for (; t > 0; t--, buf++) |
||
80 | writeb(*buf, ioaddr); |
||
81 | } else { |
||
82 | for (; t > 0; t--, buf++) |
||
83 | *buf = readb(ioaddr); |
||
84 | } |
||
85 | |||
86 | rb153_pata_finish_io(adev->link->ap); |
||
87 | return buflen; |
||
88 | } |
||
89 | |||
90 | static void rb153_pata_freeze(struct ata_port *ap) |
||
91 | { |
||
92 | struct rb153_cf_info *info = ap->host->private_data; |
||
93 | |||
94 | info->frozen = 1; |
||
95 | } |
||
96 | |||
97 | static void rb153_pata_thaw(struct ata_port *ap) |
||
98 | { |
||
99 | struct rb153_cf_info *info = ap->host->private_data; |
||
100 | |||
101 | info->frozen = 0; |
||
102 | } |
||
103 | |||
104 | static irqreturn_t rb153_pata_irq_handler(int irq, void *dev_instance) |
||
105 | { |
||
106 | struct ata_host *ah = dev_instance; |
||
107 | struct rb153_cf_info *info = ah->private_data; |
||
108 | |||
109 | if (gpio_get_value(info->gpio_line)) { |
||
110 | irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); |
||
111 | if (!info->frozen) |
||
112 | ata_sff_interrupt(irq, dev_instance); |
||
113 | } else { |
||
114 | irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); |
||
115 | } |
||
116 | |||
117 | return IRQ_HANDLED; |
||
118 | } |
||
119 | |||
120 | static struct ata_port_operations rb153_pata_port_ops = { |
||
121 | .inherits = &ata_sff_port_ops, |
||
122 | .sff_exec_command = rb153_pata_exec_command, |
||
123 | .sff_data_xfer = rb153_pata_data_xfer, |
||
124 | .freeze = rb153_pata_freeze, |
||
125 | .thaw = rb153_pata_thaw, |
||
126 | }; |
||
127 | |||
128 | static struct scsi_host_template rb153_pata_sht = { |
||
129 | ATA_PIO_SHT(DRV_NAME), |
||
130 | }; |
||
131 | |||
132 | static void rb153_pata_setup_port(struct ata_host *ah) |
||
133 | { |
||
134 | struct rb153_cf_info *info = ah->private_data; |
||
135 | struct ata_port *ap; |
||
136 | |||
137 | ap = ah->ports[0]; |
||
138 | |||
139 | ap->ops = &rb153_pata_port_ops; |
||
140 | ap->pio_mask = 0x1f; /* PIO4 */ |
||
141 | |||
142 | ap->ioaddr.cmd_addr = info->iobase + RB153_CF_REG_CMD; |
||
143 | ap->ioaddr.ctl_addr = info->iobase + RB153_CF_REG_CTRL; |
||
144 | ap->ioaddr.altstatus_addr = info->iobase + RB153_CF_REG_CTRL; |
||
145 | |||
146 | ata_sff_std_ports(&ap->ioaddr); |
||
147 | |||
148 | ap->ioaddr.data_addr = info->iobase + RB153_CF_REG_DATA; |
||
149 | } |
||
150 | |||
151 | static int rb153_pata_driver_probe(struct platform_device *pdev) |
||
152 | { |
||
153 | unsigned int irq; |
||
154 | int gpio; |
||
155 | struct resource *res; |
||
156 | struct ata_host *ah; |
||
157 | struct rb153_cf_info *info; |
||
158 | int ret; |
||
159 | |||
160 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
161 | if (!res) { |
||
162 | dev_err(&pdev->dev, "no IOMEM resource found\n"); |
||
163 | return -EINVAL; |
||
164 | } |
||
165 | |||
166 | irq = platform_get_irq(pdev, 0); |
||
167 | if (irq <= 0) { |
||
168 | dev_err(&pdev->dev, "no IRQ resource found\n"); |
||
169 | return -ENOENT; |
||
170 | } |
||
171 | |||
172 | gpio = irq_to_gpio(irq); |
||
173 | if (gpio < 0) { |
||
174 | dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq); |
||
175 | return -ENOENT; |
||
176 | } |
||
177 | |||
178 | ret = gpio_request(gpio, DRV_NAME); |
||
179 | if (ret) { |
||
180 | dev_err(&pdev->dev, "GPIO request failed\n"); |
||
181 | return ret; |
||
182 | } |
||
183 | |||
184 | ah = ata_host_alloc(&pdev->dev, RB153_CF_MAXPORTS); |
||
185 | if (!ah) |
||
186 | return -ENOMEM; |
||
187 | |||
188 | platform_set_drvdata(pdev, ah); |
||
189 | |||
190 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
||
191 | if (!info) |
||
192 | return -ENOMEM; |
||
193 | |||
194 | ah->private_data = info; |
||
195 | info->gpio_line = gpio; |
||
196 | info->irq = irq; |
||
197 | |||
198 | info->iobase = devm_ioremap_nocache(&pdev->dev, res->start, |
||
199 | res->end - res->start + 1); |
||
200 | if (!info->iobase) |
||
201 | return -ENOMEM; |
||
202 | |||
203 | ret = gpio_direction_input(gpio); |
||
204 | if (ret) { |
||
205 | dev_err(&pdev->dev, "unable to set GPIO direction, err=%d\n", |
||
206 | ret); |
||
207 | goto err_free_gpio; |
||
208 | } |
||
209 | |||
210 | rb153_pata_setup_port(ah); |
||
211 | |||
212 | ret = ata_host_activate(ah, irq, rb153_pata_irq_handler, |
||
213 | IRQF_TRIGGER_LOW, &rb153_pata_sht); |
||
214 | if (ret) |
||
215 | goto err_free_gpio; |
||
216 | |||
217 | return 0; |
||
218 | |||
219 | err_free_gpio: |
||
220 | gpio_free(gpio); |
||
221 | |||
222 | return ret; |
||
223 | } |
||
224 | |||
225 | static int rb153_pata_driver_remove(struct platform_device *pdev) |
||
226 | { |
||
227 | struct ata_host *ah = platform_get_drvdata(pdev); |
||
228 | struct rb153_cf_info *info = ah->private_data; |
||
229 | |||
230 | ata_host_detach(ah); |
||
231 | gpio_free(info->gpio_line); |
||
232 | |||
233 | return 0; |
||
234 | } |
||
235 | |||
236 | static struct platform_driver rb153_pata_platform_driver = { |
||
237 | .probe = rb153_pata_driver_probe, |
||
238 | .remove = rb153_pata_driver_remove, |
||
239 | .driver = { |
||
240 | .name = DRV_NAME, |
||
241 | .owner = THIS_MODULE, |
||
242 | }, |
||
243 | }; |
||
244 | |||
245 | /* ------------------------------------------------------------------------ */ |
||
246 | |||
247 | #define DRV_INFO DRV_DESC " version " DRV_VERSION |
||
248 | |||
249 | static int __init rb153_pata_module_init(void) |
||
250 | { |
||
251 | printk(KERN_INFO DRV_INFO "\n"); |
||
252 | |||
253 | return platform_driver_register(&rb153_pata_platform_driver); |
||
254 | } |
||
255 | |||
256 | static void __exit rb153_pata_module_exit(void) |
||
257 | { |
||
258 | platform_driver_unregister(&rb153_pata_platform_driver); |
||
259 | } |
||
260 | |||
261 | MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); |
||
262 | MODULE_DESCRIPTION(DRV_DESC); |
||
263 | MODULE_VERSION(DRV_VERSION); |
||
264 | MODULE_LICENSE("GPL v2"); |
||
265 | |||
266 | module_init(rb153_pata_module_init); |
||
267 | module_exit(rb153_pata_module_exit); |