OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [ata/] [pata_ixp4xx_cf.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * ixp4xx PATA/Compact Flash driver
3
 * Copyright (C) 2006-07 Tower Technologies
4
 * Author: Alessandro Zummo <a.zummo@towertech.it>
5
 *
6
 * An ATA driver to handle a Compact Flash connected
7
 * to the ixp4xx expansion bus in TrueIDE mode. The CF
8
 * must have it chip selects connected to two CS lines
9
 * on the ixp4xx. In the irq is not available, you might
10
 * want to modify both this driver and libata to run in
11
 * polling mode.
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License version 2 as
15
 * published by the Free Software Foundation.
16
 *
17
 */
18
 
19
#include <linux/kernel.h>
20
#include <linux/module.h>
21
#include <linux/libata.h>
22
#include <linux/irq.h>
23
#include <linux/platform_device.h>
24
#include <scsi/scsi_host.h>
25
 
26
#define DRV_NAME        "pata_ixp4xx_cf"
27
#define DRV_VERSION     "0.2"
28
 
29
static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
30
{
31
        struct ata_device *dev;
32
 
33
        ata_link_for_each_dev(dev, link) {
34
                if (ata_dev_enabled(dev)) {
35
                        ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
36
                        dev->pio_mode = XFER_PIO_0;
37
                        dev->xfer_mode = XFER_PIO_0;
38
                        dev->xfer_shift = ATA_SHIFT_PIO;
39
                        dev->flags |= ATA_DFLAG_PIO;
40
                }
41
        }
42
        return 0;
43
}
44
 
45
static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
46
                                unsigned int buflen, int write_data)
47
{
48
        unsigned int i;
49
        unsigned int words = buflen >> 1;
50
        u16 *buf16 = (u16 *) buf;
51
        struct ata_port *ap = adev->link->ap;
52
        void __iomem *mmio = ap->ioaddr.data_addr;
53
        struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
54
 
55
        /* set the expansion bus in 16bit mode and restore
56
         * 8 bit mode after the transaction.
57
         */
58
        *data->cs0_cfg &= ~(0x01);
59
        udelay(100);
60
 
61
        /* Transfer multiple of 2 bytes */
62
        if (write_data) {
63
                for (i = 0; i < words; i++)
64
                        writew(buf16[i], mmio);
65
        } else {
66
                for (i = 0; i < words; i++)
67
                        buf16[i] = readw(mmio);
68
        }
69
 
70
        /* Transfer trailing 1 byte, if any. */
71
        if (unlikely(buflen & 0x01)) {
72
                u16 align_buf[1] = { 0 };
73
                unsigned char *trailing_buf = buf + buflen - 1;
74
 
75
                if (write_data) {
76
                        memcpy(align_buf, trailing_buf, 1);
77
                        writew(align_buf[0], mmio);
78
                } else {
79
                        align_buf[0] = readw(mmio);
80
                        memcpy(trailing_buf, align_buf, 1);
81
                }
82
        }
83
 
84
        udelay(100);
85
        *data->cs0_cfg |= 0x01;
86
}
87
 
88
static struct scsi_host_template ixp4xx_sht = {
89
        .module                 = THIS_MODULE,
90
        .name                   = DRV_NAME,
91
        .ioctl                  = ata_scsi_ioctl,
92
        .queuecommand           = ata_scsi_queuecmd,
93
        .can_queue              = ATA_DEF_QUEUE,
94
        .this_id                = ATA_SHT_THIS_ID,
95
        .sg_tablesize           = LIBATA_MAX_PRD,
96
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
97
        .emulated               = ATA_SHT_EMULATED,
98
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
99
        .proc_name              = DRV_NAME,
100
        .dma_boundary           = ATA_DMA_BOUNDARY,
101
        .slave_configure        = ata_scsi_slave_config,
102
        .slave_destroy          = ata_scsi_slave_destroy,
103
        .bios_param             = ata_std_bios_param,
104
};
105
 
106
static struct ata_port_operations ixp4xx_port_ops = {
107
        .set_mode               = ixp4xx_set_mode,
108
        .mode_filter            = ata_pci_default_filter,
109
 
110
        .tf_load                = ata_tf_load,
111
        .tf_read                = ata_tf_read,
112
        .exec_command           = ata_exec_command,
113
        .check_status           = ata_check_status,
114
        .dev_select             = ata_std_dev_select,
115
 
116
        .freeze                 = ata_bmdma_freeze,
117
        .thaw                   = ata_bmdma_thaw,
118
        .error_handler          = ata_bmdma_error_handler,
119
        .post_internal_cmd      = ata_bmdma_post_internal_cmd,
120
 
121
        .qc_prep                = ata_qc_prep,
122
        .qc_issue               = ata_qc_issue_prot,
123
        .data_xfer              = ixp4xx_mmio_data_xfer,
124
        .cable_detect           = ata_cable_40wire,
125
 
126
        .irq_handler            = ata_interrupt,
127
        .irq_clear              = ata_bmdma_irq_clear,
128
        .irq_on                 = ata_irq_on,
129
 
130
        .port_start             = ata_port_start,
131
};
132
 
133
static void ixp4xx_setup_port(struct ata_port *ap,
134
                              struct ixp4xx_pata_data *data,
135
                              unsigned long raw_cs0, unsigned long raw_cs1)
136
{
137
        struct ata_ioports *ioaddr = &ap->ioaddr;
138
        unsigned long raw_cmd = raw_cs0;
139
        unsigned long raw_ctl = raw_cs1 + 0x06;
140
 
141
        ioaddr->cmd_addr        = data->cs0;
142
        ioaddr->altstatus_addr  = data->cs1 + 0x06;
143
        ioaddr->ctl_addr        = data->cs1 + 0x06;
144
 
145
        ata_std_ports(ioaddr);
146
 
147
#ifndef __ARMEB__
148
 
149
        /* adjust the addresses to handle the address swizzling of the
150
         * ixp4xx in little endian mode.
151
         */
152
 
153
        *(unsigned long *)&ioaddr->data_addr            ^= 0x02;
154
        *(unsigned long *)&ioaddr->cmd_addr             ^= 0x03;
155
        *(unsigned long *)&ioaddr->altstatus_addr       ^= 0x03;
156
        *(unsigned long *)&ioaddr->ctl_addr             ^= 0x03;
157
        *(unsigned long *)&ioaddr->error_addr           ^= 0x03;
158
        *(unsigned long *)&ioaddr->feature_addr         ^= 0x03;
159
        *(unsigned long *)&ioaddr->nsect_addr           ^= 0x03;
160
        *(unsigned long *)&ioaddr->lbal_addr            ^= 0x03;
161
        *(unsigned long *)&ioaddr->lbam_addr            ^= 0x03;
162
        *(unsigned long *)&ioaddr->lbah_addr            ^= 0x03;
163
        *(unsigned long *)&ioaddr->device_addr          ^= 0x03;
164
        *(unsigned long *)&ioaddr->status_addr          ^= 0x03;
165
        *(unsigned long *)&ioaddr->command_addr         ^= 0x03;
166
 
167
        raw_cmd ^= 0x03;
168
        raw_ctl ^= 0x03;
169
#endif
170
 
171
        ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
172
}
173
 
174
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
175
{
176
        unsigned int irq;
177
        struct resource *cs0, *cs1;
178
        struct ata_host *host;
179
        struct ata_port *ap;
180
        struct ixp4xx_pata_data *data = pdev->dev.platform_data;
181
 
182
        cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183
        cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
184
 
185
        if (!cs0 || !cs1)
186
                return -EINVAL;
187
 
188
        /* allocate host */
189
        host = ata_host_alloc(&pdev->dev, 1);
190
        if (!host)
191
                return -ENOMEM;
192
 
193
        /* acquire resources and fill host */
194
        pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
195
 
196
        data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
197
        data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
198
 
199
        if (!data->cs0 || !data->cs1)
200
                return -ENOMEM;
201
 
202
        irq = platform_get_irq(pdev, 0);
203
        if (irq)
204
                set_irq_type(irq, IRQT_RISING);
205
 
206
        /* Setup expansion bus chip selects */
207
        *data->cs0_cfg = data->cs0_bits;
208
        *data->cs1_cfg = data->cs1_bits;
209
 
210
        ap = host->ports[0];
211
 
212
        ap->ops = &ixp4xx_port_ops;
213
        ap->pio_mask = 0x1f; /* PIO4 */
214
        ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
215
 
216
        ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
217
 
218
        dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
219
 
220
        /* activate host */
221
        return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
222
}
223
 
224
static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
225
{
226
        struct ata_host *host = platform_get_drvdata(dev);
227
 
228
        ata_host_detach(host);
229
 
230
        return 0;
231
}
232
 
233
static struct platform_driver ixp4xx_pata_platform_driver = {
234
        .driver  = {
235
                .name   = DRV_NAME,
236
                .owner  = THIS_MODULE,
237
        },
238
        .probe          = ixp4xx_pata_probe,
239
        .remove         = __devexit_p(ixp4xx_pata_remove),
240
};
241
 
242
static int __init ixp4xx_pata_init(void)
243
{
244
        return platform_driver_register(&ixp4xx_pata_platform_driver);
245
}
246
 
247
static void __exit ixp4xx_pata_exit(void)
248
{
249
        platform_driver_unregister(&ixp4xx_pata_platform_driver);
250
}
251
 
252
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
253
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
254
MODULE_LICENSE("GPL");
255
MODULE_VERSION(DRV_VERSION);
256
 
257
module_init(ixp4xx_pata_init);
258
module_exit(ixp4xx_pata_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.