2 * pata_winbond.c - Winbond VLB ATA controllers
3 * (C) 2006 Red Hat <alan@redhat.com>
5 * Support for the Winbond 83759A when operating in advanced mode.
6 * Multichip mode is not currently supported.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/blkdev.h>
13 #include <linux/delay.h>
14 #include <scsi/scsi_host.h>
15 #include <linux/libata.h>
16 #include <linux/platform_device.h>
18 #define DRV_NAME "pata_winbond"
19 #define DRV_VERSION "0.0.3"
21 #define NR_HOST 4 /* Two winbond controllers, two channels each */
25 struct platform_device
*platform_dev
;
28 static struct ata_host
*winbond_host
[NR_HOST
];
29 static struct winbond_data winbond_data
[NR_HOST
];
30 static int nr_winbond_host
;
33 static int probe_winbond
= 1;
35 static int probe_winbond
;
38 static DEFINE_SPINLOCK(winbond_lock
);
40 static void winbond_writecfg(unsigned long port
, u8 reg
, u8 val
)
43 spin_lock_irqsave(&winbond_lock
, flags
);
44 outb(reg
, port
+ 0x01);
45 outb(val
, port
+ 0x02);
46 spin_unlock_irqrestore(&winbond_lock
, flags
);
49 static u8
winbond_readcfg(unsigned long port
, u8 reg
)
54 spin_lock_irqsave(&winbond_lock
, flags
);
55 outb(reg
, port
+ 0x01);
56 val
= inb(port
+ 0x02);
57 spin_unlock_irqrestore(&winbond_lock
, flags
);
62 static void winbond_set_piomode(struct ata_port
*ap
, struct ata_device
*adev
)
65 struct winbond_data
*winbond
= ap
->host
->private_data
;
68 int timing
= 0x88 + (ap
->port_no
* 4) + (adev
->devno
* 2);
70 reg
= winbond_readcfg(winbond
->config
, 0x81);
72 /* Get the timing data in cycles */
73 if (reg
& 0x40) /* Fast VLB bus, assume 50MHz */
74 ata_timing_compute(adev
, adev
->pio_mode
, &t
, 20000, 1000);
76 ata_timing_compute(adev
, adev
->pio_mode
, &t
, 30303, 1000);
78 active
= (FIT(t
.active
, 3, 17) - 1) & 0x0F;
79 recovery
= (FIT(t
.recover
, 1, 15) + 1) & 0x0F;
80 timing
= (active
<< 4) | recovery
;
81 winbond_writecfg(winbond
->config
, timing
, reg
);
83 /* Load the setup timing */
86 if (adev
->class != ATA_DEV_ATA
)
87 reg
|= 0x08; /* FIFO off */
88 if (!ata_pio_need_iordy(adev
))
89 reg
|= 0x02; /* IORDY off */
90 reg
|= (FIT(t
.setup
, 0, 3) << 6);
91 winbond_writecfg(winbond
->config
, timing
+ 1, reg
);
95 static unsigned int winbond_data_xfer(struct ata_device
*dev
,
96 unsigned char *buf
, unsigned int buflen
, int rw
)
98 struct ata_port
*ap
= dev
->link
->ap
;
99 int slop
= buflen
& 3;
101 if (ata_id_has_dword_io(dev
->id
)) {
103 ioread32_rep(ap
->ioaddr
.data_addr
, buf
, buflen
>> 2);
105 iowrite32_rep(ap
->ioaddr
.data_addr
, buf
, buflen
>> 2);
107 if (unlikely(slop
)) {
110 pad
= cpu_to_le32(ioread32(ap
->ioaddr
.data_addr
));
111 memcpy(buf
+ buflen
- slop
, &pad
, slop
);
113 memcpy(&pad
, buf
+ buflen
- slop
, slop
);
114 iowrite32(le32_to_cpu(pad
), ap
->ioaddr
.data_addr
);
119 buflen
= ata_sff_data_xfer(dev
, buf
, buflen
, rw
);
124 static struct scsi_host_template winbond_sht
= {
125 ATA_PIO_SHT(DRV_NAME
),
128 static struct ata_port_operations winbond_port_ops
= {
129 .inherits
= &ata_sff_port_ops
,
130 .sff_data_xfer
= winbond_data_xfer
,
131 .cable_detect
= ata_cable_40wire
,
132 .set_piomode
= winbond_set_piomode
,
136 * winbond_init_one - attach a winbond interface
137 * @type: Type to display
138 * @io: I/O port start
139 * @irq: interrupt line
140 * @fast: True if on a > 33Mhz VLB
142 * Register a VLB bus IDE interface. Such interfaces are PIO and we
143 * assume do not support IRQ sharing.
146 static __init
int winbond_init_one(unsigned long port
)
148 struct platform_device
*pdev
;
152 reg
= winbond_readcfg(port
, 0x81);
153 reg
|= 0x80; /* jumpered mode off */
154 winbond_writecfg(port
, 0x81, reg
);
155 reg
= winbond_readcfg(port
, 0x83);
156 reg
|= 0xF0; /* local control */
157 winbond_writecfg(port
, 0x83, reg
);
158 reg
= winbond_readcfg(port
, 0x85);
159 reg
|= 0xF0; /* programmable timing */
160 winbond_writecfg(port
, 0x85, reg
);
162 reg
= winbond_readcfg(port
, 0x81);
164 if (!(reg
& 0x03)) /* Disabled */
167 for (i
= 0; i
< 2 ; i
++) {
168 unsigned long cmd_port
= 0x1F0 - (0x80 * i
);
169 unsigned long ctl_port
= cmd_port
+ 0x206;
170 struct ata_host
*host
;
172 void __iomem
*cmd_addr
, *ctl_addr
;
174 if (!(reg
& (1 << i
)))
177 pdev
= platform_device_register_simple(DRV_NAME
, nr_winbond_host
, NULL
, 0);
179 return PTR_ERR(pdev
);
182 host
= ata_host_alloc(&pdev
->dev
, 1);
188 cmd_addr
= devm_ioport_map(&pdev
->dev
, cmd_port
, 8);
189 ctl_addr
= devm_ioport_map(&pdev
->dev
, ctl_port
, 1);
190 if (!cmd_addr
|| !ctl_addr
)
193 ata_port_desc(ap
, "cmd 0x%lx ctl 0x%lx", cmd_port
, ctl_port
);
195 ap
->ops
= &winbond_port_ops
;
197 ap
->flags
|= ATA_FLAG_SLAVE_POSS
;
198 ap
->ioaddr
.cmd_addr
= cmd_addr
;
199 ap
->ioaddr
.altstatus_addr
= ctl_addr
;
200 ap
->ioaddr
.ctl_addr
= ctl_addr
;
201 ata_sff_std_ports(&ap
->ioaddr
);
203 /* hook in a private data structure per channel */
204 host
->private_data
= &winbond_data
[nr_winbond_host
];
205 winbond_data
[nr_winbond_host
].config
= port
;
206 winbond_data
[nr_winbond_host
].platform_dev
= pdev
;
209 rc
= ata_host_activate(host
, 14 + i
, ata_sff_interrupt
, 0,
214 winbond_host
[nr_winbond_host
++] = dev_get_drvdata(&pdev
->dev
);
220 platform_device_unregister(pdev
);
225 * winbond_init - attach winbond interfaces
227 * Attach winbond IDE interfaces by scanning the ports it may occupy.
230 static __init
int winbond_init(void)
232 static const unsigned long config
[2] = { 0x130, 0x1B0 };
237 if (probe_winbond
== 0)
241 * Check both base addresses
244 for (i
= 0; i
< 2; i
++) {
245 if (probe_winbond
& (1<<i
)) {
247 unsigned long port
= config
[i
];
249 if (request_region(port
, 2, "pata_winbond")) {
250 ret
= winbond_init_one(port
);
252 release_region(port
, 2);
262 static __exit
void winbond_exit(void)
266 for (i
= 0; i
< nr_winbond_host
; i
++) {
267 ata_host_detach(winbond_host
[i
]);
268 release_region(winbond_data
[i
].config
, 2);
269 platform_device_unregister(winbond_data
[i
].platform_dev
);
273 MODULE_AUTHOR("Alan Cox");
274 MODULE_DESCRIPTION("low-level driver for Winbond VL ATA");
275 MODULE_LICENSE("GPL");
276 MODULE_VERSION(DRV_VERSION
);
278 module_init(winbond_init
);
279 module_exit(winbond_exit
);
281 module_param(probe_winbond
, int, 0);