diff options
author | Alan <alan@lxorguk.ukuu.org.uk> | 2006-11-22 12:28:41 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-01 22:46:46 -0500 |
commit | 8550c1637ba7dd96a76353eb52d31088f9c2f5fe (patch) | |
tree | 86b56ff88f5b9f74df07922e4c601cde2e9cd481 | |
parent | ad4a42d287546888349ad24d351673a59f429ee8 (diff) |
[PATCH] pata_sil680 suspend/resume
The SI680 can come back from s2ram with the clocks disabled (crash time)
or wrong (ugly as this can cause CRC errors, and in theory corruption).
On a resume we must put the clock back.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/pata_sil680.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 11942fd03b55..5d3b42ec8e47 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/libata.h> | 33 | #include <linux/libata.h> |
34 | 34 | ||
35 | #define DRV_NAME "pata_sil680" | 35 | #define DRV_NAME "pata_sil680" |
36 | #define DRV_VERSION "0.3.2" | 36 | #define DRV_VERSION "0.4.1" |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * sil680_selreg - return register base | 39 | * sil680_selreg - return register base |
@@ -263,32 +263,20 @@ static struct ata_port_operations sil680_port_ops = { | |||
263 | .host_stop = ata_host_stop | 263 | .host_stop = ata_host_stop |
264 | }; | 264 | }; |
265 | 265 | ||
266 | static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | 266 | /** |
267 | * sil680_init_chip - chip setup | ||
268 | * @pdev: PCI device | ||
269 | * | ||
270 | * Perform all the chip setup which must be done both when the device | ||
271 | * is powered up on boot and when we resume in case we resumed from RAM. | ||
272 | * Returns the final clock settings. | ||
273 | */ | ||
274 | |||
275 | static u8 sil680_init_chip(struct pci_dev *pdev) | ||
267 | { | 276 | { |
268 | static struct ata_port_info info = { | ||
269 | .sht = &sil680_sht, | ||
270 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
271 | .pio_mask = 0x1f, | ||
272 | .mwdma_mask = 0x07, | ||
273 | .udma_mask = 0x7f, | ||
274 | .port_ops = &sil680_port_ops | ||
275 | }; | ||
276 | static struct ata_port_info info_slow = { | ||
277 | .sht = &sil680_sht, | ||
278 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
279 | .pio_mask = 0x1f, | ||
280 | .mwdma_mask = 0x07, | ||
281 | .udma_mask = 0x3f, | ||
282 | .port_ops = &sil680_port_ops | ||
283 | }; | ||
284 | static struct ata_port_info *port_info[2] = {&info, &info}; | ||
285 | static int printed_version; | ||
286 | u32 class_rev = 0; | 277 | u32 class_rev = 0; |
287 | u8 tmpbyte = 0; | 278 | u8 tmpbyte = 0; |
288 | 279 | ||
289 | if (!printed_version++) | ||
290 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | ||
291 | |||
292 | pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); | 280 | pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); |
293 | class_rev &= 0xff; | 281 | class_rev &= 0xff; |
294 | /* FIXME: double check */ | 282 | /* FIXME: double check */ |
@@ -323,8 +311,6 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
323 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); | 311 | pci_read_config_byte(pdev, 0x8A, &tmpbyte); |
324 | printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", | 312 | printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n", |
325 | tmpbyte & 1, tmpbyte & 0x30); | 313 | tmpbyte & 1, tmpbyte & 0x30); |
326 | if ((tmpbyte & 0x30) == 0) | ||
327 | port_info[0] = port_info[1] = &info_slow; | ||
328 | 314 | ||
329 | pci_write_config_byte(pdev, 0xA1, 0x72); | 315 | pci_write_config_byte(pdev, 0xA1, 0x72); |
330 | pci_write_config_word(pdev, 0xA2, 0x328A); | 316 | pci_write_config_word(pdev, 0xA2, 0x328A); |
@@ -343,11 +329,51 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
343 | case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break; | 329 | case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break; |
344 | /* This last case is _NOT_ ok */ | 330 | /* This last case is _NOT_ ok */ |
345 | case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n"); | 331 | case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n"); |
346 | return -EIO; | 332 | } |
333 | return tmpbyte & 0x30; | ||
334 | } | ||
335 | |||
336 | static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | ||
337 | { | ||
338 | static struct ata_port_info info = { | ||
339 | .sht = &sil680_sht, | ||
340 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
341 | .pio_mask = 0x1f, | ||
342 | .mwdma_mask = 0x07, | ||
343 | .udma_mask = 0x7f, | ||
344 | .port_ops = &sil680_port_ops | ||
345 | }; | ||
346 | static struct ata_port_info info_slow = { | ||
347 | .sht = &sil680_sht, | ||
348 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
349 | .pio_mask = 0x1f, | ||
350 | .mwdma_mask = 0x07, | ||
351 | .udma_mask = 0x3f, | ||
352 | .port_ops = &sil680_port_ops | ||
353 | }; | ||
354 | static struct ata_port_info *port_info[2] = {&info, &info}; | ||
355 | static int printed_version; | ||
356 | |||
357 | if (!printed_version++) | ||
358 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | ||
359 | |||
360 | switch(sil680_init_chip(pdev)) | ||
361 | { | ||
362 | case 0: | ||
363 | port_info[0] = port_info[1] = &info_slow; | ||
364 | break; | ||
365 | case 0x30: | ||
366 | return -ENODEV; | ||
347 | } | 367 | } |
348 | return ata_pci_init_one(pdev, port_info, 2); | 368 | return ata_pci_init_one(pdev, port_info, 2); |
349 | } | 369 | } |
350 | 370 | ||
371 | static int sil680_reinit_one(struct pci_dev *pdev) | ||
372 | { | ||
373 | sil680_init_chip(pdev); | ||
374 | return ata_pci_device_resume(pdev); | ||
375 | } | ||
376 | |||
351 | static const struct pci_device_id sil680[] = { | 377 | static const struct pci_device_id sil680[] = { |
352 | { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, | 378 | { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, |
353 | 379 | ||
@@ -358,7 +384,9 @@ static struct pci_driver sil680_pci_driver = { | |||
358 | .name = DRV_NAME, | 384 | .name = DRV_NAME, |
359 | .id_table = sil680, | 385 | .id_table = sil680, |
360 | .probe = sil680_init_one, | 386 | .probe = sil680_init_one, |
361 | .remove = ata_pci_remove_one | 387 | .remove = ata_pci_remove_one, |
388 | .suspend = ata_pci_device_suspend, | ||
389 | .resume = sil680_reinit_one, | ||
362 | }; | 390 | }; |
363 | 391 | ||
364 | static int __init sil680_init(void) | 392 | static int __init sil680_init(void) |