18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
48c2ecf20Sopenharmony_ci * Copyright (C) 2007		MontaVista Software, Inc. <source@mvista.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/types.h>
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/ide.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/io.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define DRV_NAME "aec62xx"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct chipset_bus_clock_list_entry {
198c2ecf20Sopenharmony_ci	u8 xfer_speed;
208c2ecf20Sopenharmony_ci	u8 chipset_settings;
218c2ecf20Sopenharmony_ci	u8 ultra_settings;
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
258c2ecf20Sopenharmony_ci	{	XFER_UDMA_6,	0x31,	0x07	},
268c2ecf20Sopenharmony_ci	{	XFER_UDMA_5,	0x31,	0x06	},
278c2ecf20Sopenharmony_ci	{	XFER_UDMA_4,	0x31,	0x05	},
288c2ecf20Sopenharmony_ci	{	XFER_UDMA_3,	0x31,	0x04	},
298c2ecf20Sopenharmony_ci	{	XFER_UDMA_2,	0x31,	0x03	},
308c2ecf20Sopenharmony_ci	{	XFER_UDMA_1,	0x31,	0x02	},
318c2ecf20Sopenharmony_ci	{	XFER_UDMA_0,	0x31,	0x01	},
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_2,	0x31,	0x00	},
348c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_1,	0x31,	0x00	},
358c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_0,	0x0a,	0x00	},
368c2ecf20Sopenharmony_ci	{	XFER_PIO_4,	0x31,	0x00	},
378c2ecf20Sopenharmony_ci	{	XFER_PIO_3,	0x33,	0x00	},
388c2ecf20Sopenharmony_ci	{	XFER_PIO_2,	0x08,	0x00	},
398c2ecf20Sopenharmony_ci	{	XFER_PIO_1,	0x0a,	0x00	},
408c2ecf20Sopenharmony_ci	{	XFER_PIO_0,	0x00,	0x00	},
418c2ecf20Sopenharmony_ci	{	0,		0x00,	0x00	}
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
458c2ecf20Sopenharmony_ci	{	XFER_UDMA_6,	0x41,	0x06	},
468c2ecf20Sopenharmony_ci	{	XFER_UDMA_5,	0x41,	0x05	},
478c2ecf20Sopenharmony_ci	{	XFER_UDMA_4,	0x41,	0x04	},
488c2ecf20Sopenharmony_ci	{	XFER_UDMA_3,	0x41,	0x03	},
498c2ecf20Sopenharmony_ci	{	XFER_UDMA_2,	0x41,	0x02	},
508c2ecf20Sopenharmony_ci	{	XFER_UDMA_1,	0x41,	0x01	},
518c2ecf20Sopenharmony_ci	{	XFER_UDMA_0,	0x41,	0x01	},
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_2,	0x41,	0x00	},
548c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_1,	0x42,	0x00	},
558c2ecf20Sopenharmony_ci	{	XFER_MW_DMA_0,	0x7a,	0x00	},
568c2ecf20Sopenharmony_ci	{	XFER_PIO_4,	0x41,	0x00	},
578c2ecf20Sopenharmony_ci	{	XFER_PIO_3,	0x43,	0x00	},
588c2ecf20Sopenharmony_ci	{	XFER_PIO_2,	0x78,	0x00	},
598c2ecf20Sopenharmony_ci	{	XFER_PIO_1,	0x7a,	0x00	},
608c2ecf20Sopenharmony_ci	{	XFER_PIO_0,	0x70,	0x00	},
618c2ecf20Sopenharmony_ci	{	0,		0x00,	0x00	}
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * TO DO: active tuning and correction of cards without a bios.
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	for ( ; chipset_table->xfer_speed ; chipset_table++)
708c2ecf20Sopenharmony_ci		if (chipset_table->xfer_speed == speed) {
718c2ecf20Sopenharmony_ci			return chipset_table->chipset_settings;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci	return chipset_table->chipset_settings;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	for ( ; chipset_table->xfer_speed ; chipset_table++)
798c2ecf20Sopenharmony_ci		if (chipset_table->xfer_speed == speed) {
808c2ecf20Sopenharmony_ci			return chipset_table->ultra_settings;
818c2ecf20Sopenharmony_ci		}
828c2ecf20Sopenharmony_ci	return chipset_table->ultra_settings;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct pci_dev *dev	= to_pci_dev(hwif->dev);
888c2ecf20Sopenharmony_ci	struct ide_host *host	= pci_get_drvdata(dev);
898c2ecf20Sopenharmony_ci	struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
908c2ecf20Sopenharmony_ci	u16 d_conf		= 0;
918c2ecf20Sopenharmony_ci	u8 ultra = 0, ultra_conf = 0;
928c2ecf20Sopenharmony_ci	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
938c2ecf20Sopenharmony_ci	const u8 speed = drive->dma_mode;
948c2ecf20Sopenharmony_ci	unsigned long flags;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	local_irq_save(flags);
978c2ecf20Sopenharmony_ci	/* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */
988c2ecf20Sopenharmony_ci	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
998c2ecf20Sopenharmony_ci	tmp0 = pci_bus_clock_list(speed, bus_clock);
1008c2ecf20Sopenharmony_ci	d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf);
1018c2ecf20Sopenharmony_ci	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	tmp1 = 0x00;
1048c2ecf20Sopenharmony_ci	tmp2 = 0x00;
1058c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, 0x54, &ultra);
1068c2ecf20Sopenharmony_ci	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
1078c2ecf20Sopenharmony_ci	ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
1088c2ecf20Sopenharmony_ci	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
1098c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, 0x54, tmp2);
1108c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct pci_dev *dev	= to_pci_dev(hwif->dev);
1168c2ecf20Sopenharmony_ci	struct ide_host *host	= pci_get_drvdata(dev);
1178c2ecf20Sopenharmony_ci	struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
1188c2ecf20Sopenharmony_ci	u8 unit			= drive->dn & 1;
1198c2ecf20Sopenharmony_ci	u8 tmp1 = 0, tmp2 = 0;
1208c2ecf20Sopenharmony_ci	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
1218c2ecf20Sopenharmony_ci	const u8 speed = drive->dma_mode;
1228c2ecf20Sopenharmony_ci	unsigned long flags;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	local_irq_save(flags);
1258c2ecf20Sopenharmony_ci	/* high 4-bits: Active, low 4-bits: Recovery */
1268c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
1278c2ecf20Sopenharmony_ci	drive_conf = pci_bus_clock_list(speed, bus_clock);
1288c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
1318c2ecf20Sopenharmony_ci	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
1328c2ecf20Sopenharmony_ci	ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
1338c2ecf20Sopenharmony_ci	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
1348c2ecf20Sopenharmony_ci	pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
1358c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	drive->dma_mode = drive->pio_mode;
1418c2ecf20Sopenharmony_ci	hwif->port_ops->set_dma_mode(hwif, drive);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int init_chipset_aec62xx(struct pci_dev *dev)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	/* These are necessary to get AEC6280 Macintosh cards to work */
1478c2ecf20Sopenharmony_ci	if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
1488c2ecf20Sopenharmony_ci	    (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
1498c2ecf20Sopenharmony_ci		u8 reg49h = 0, reg4ah = 0;
1508c2ecf20Sopenharmony_ci		/* Clear reset and test bits.  */
1518c2ecf20Sopenharmony_ci		pci_read_config_byte(dev, 0x49, &reg49h);
1528c2ecf20Sopenharmony_ci		pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
1538c2ecf20Sopenharmony_ci		/* Enable chip interrupt output.  */
1548c2ecf20Sopenharmony_ci		pci_read_config_byte(dev, 0x4a, &reg4ah);
1558c2ecf20Sopenharmony_ci		pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
1568c2ecf20Sopenharmony_ci		/* Enable burst mode. */
1578c2ecf20Sopenharmony_ci		pci_read_config_byte(dev, 0x4a, &reg4ah);
1588c2ecf20Sopenharmony_ci		pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic u8 atp86x_cable_detect(ide_hwif_t *hwif)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct pci_dev *dev = to_pci_dev(hwif->dev);
1678c2ecf20Sopenharmony_ci	u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	pci_read_config_byte(dev, 0x49, &ata66);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic const struct ide_port_ops atp850_port_ops = {
1758c2ecf20Sopenharmony_ci	.set_pio_mode		= aec_set_pio_mode,
1768c2ecf20Sopenharmony_ci	.set_dma_mode		= aec6210_set_mode,
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic const struct ide_port_ops atp86x_port_ops = {
1808c2ecf20Sopenharmony_ci	.set_pio_mode		= aec_set_pio_mode,
1818c2ecf20Sopenharmony_ci	.set_dma_mode		= aec6260_set_mode,
1828c2ecf20Sopenharmony_ci	.cable_detect		= atp86x_cable_detect,
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic const struct ide_port_info aec62xx_chipsets[] = {
1868c2ecf20Sopenharmony_ci	{	/* 0: AEC6210 */
1878c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
1888c2ecf20Sopenharmony_ci		.init_chipset	= init_chipset_aec62xx,
1898c2ecf20Sopenharmony_ci		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
1908c2ecf20Sopenharmony_ci		.port_ops	= &atp850_port_ops,
1918c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_SERIALIZE |
1928c2ecf20Sopenharmony_ci				  IDE_HFLAG_NO_ATAPI_DMA |
1938c2ecf20Sopenharmony_ci				  IDE_HFLAG_NO_DSC |
1948c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
1958c2ecf20Sopenharmony_ci		.pio_mask	= ATA_PIO4,
1968c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
1978c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA2,
1988c2ecf20Sopenharmony_ci	},
1998c2ecf20Sopenharmony_ci	{	/* 1: AEC6260 */
2008c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
2018c2ecf20Sopenharmony_ci		.init_chipset	= init_chipset_aec62xx,
2028c2ecf20Sopenharmony_ci		.port_ops	= &atp86x_port_ops,
2038c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
2048c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
2058c2ecf20Sopenharmony_ci		.pio_mask	= ATA_PIO4,
2068c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
2078c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA4,
2088c2ecf20Sopenharmony_ci	},
2098c2ecf20Sopenharmony_ci	{	/* 2: AEC6260R */
2108c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
2118c2ecf20Sopenharmony_ci		.init_chipset	= init_chipset_aec62xx,
2128c2ecf20Sopenharmony_ci		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
2138c2ecf20Sopenharmony_ci		.port_ops	= &atp86x_port_ops,
2148c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
2158c2ecf20Sopenharmony_ci				  IDE_HFLAG_NON_BOOTABLE,
2168c2ecf20Sopenharmony_ci		.pio_mask	= ATA_PIO4,
2178c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
2188c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA4,
2198c2ecf20Sopenharmony_ci	},
2208c2ecf20Sopenharmony_ci	{	/* 3: AEC6280 */
2218c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
2228c2ecf20Sopenharmony_ci		.init_chipset	= init_chipset_aec62xx,
2238c2ecf20Sopenharmony_ci		.port_ops	= &atp86x_port_ops,
2248c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
2258c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
2268c2ecf20Sopenharmony_ci		.pio_mask	= ATA_PIO4,
2278c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
2288c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA5,
2298c2ecf20Sopenharmony_ci	},
2308c2ecf20Sopenharmony_ci	{	/* 4: AEC6280R */
2318c2ecf20Sopenharmony_ci		.name		= DRV_NAME,
2328c2ecf20Sopenharmony_ci		.init_chipset	= init_chipset_aec62xx,
2338c2ecf20Sopenharmony_ci		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
2348c2ecf20Sopenharmony_ci		.port_ops	= &atp86x_port_ops,
2358c2ecf20Sopenharmony_ci		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
2368c2ecf20Sopenharmony_ci				  IDE_HFLAG_OFF_BOARD,
2378c2ecf20Sopenharmony_ci		.pio_mask	= ATA_PIO4,
2388c2ecf20Sopenharmony_ci		.mwdma_mask	= ATA_MWDMA2,
2398c2ecf20Sopenharmony_ci		.udma_mask	= ATA_UDMA5,
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci};
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/**
2448c2ecf20Sopenharmony_ci *	aec62xx_init_one	-	called when a AEC is found
2458c2ecf20Sopenharmony_ci *	@dev: the aec62xx device
2468c2ecf20Sopenharmony_ci *	@id: the matching pci id
2478c2ecf20Sopenharmony_ci *
2488c2ecf20Sopenharmony_ci *	Called when the PCI registration layer (or the IDE initialization)
2498c2ecf20Sopenharmony_ci *	finds a device matching our IDE device tables.
2508c2ecf20Sopenharmony_ci *
2518c2ecf20Sopenharmony_ci *	NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
2528c2ecf20Sopenharmony_ci *	chips, pass a local copy of 'struct ide_port_info' down the call chain.
2538c2ecf20Sopenharmony_ci */
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	const struct chipset_bus_clock_list_entry *bus_clock;
2588c2ecf20Sopenharmony_ci	struct ide_port_info d;
2598c2ecf20Sopenharmony_ci	u8 idx = id->driver_data;
2608c2ecf20Sopenharmony_ci	int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
2618c2ecf20Sopenharmony_ci	int err;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (bus_speed <= 33)
2648c2ecf20Sopenharmony_ci		bus_clock = aec6xxx_33_base;
2658c2ecf20Sopenharmony_ci	else
2668c2ecf20Sopenharmony_ci		bus_clock = aec6xxx_34_base;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	err = pci_enable_device(dev);
2698c2ecf20Sopenharmony_ci	if (err)
2708c2ecf20Sopenharmony_ci		return err;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	d = aec62xx_chipsets[idx];
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (idx == 3 || idx == 4) {
2758c2ecf20Sopenharmony_ci		unsigned long dma_base = pci_resource_start(dev, 4);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		if (inb(dma_base + 2) & 0x10) {
2788c2ecf20Sopenharmony_ci			printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected"
2798c2ecf20Sopenharmony_ci				"\n", pci_name(dev), (idx == 4) ? "R" : "");
2808c2ecf20Sopenharmony_ci			d.udma_mask = ATA_UDMA6;
2818c2ecf20Sopenharmony_ci		}
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	err = ide_pci_init_one(dev, &d, (void *)bus_clock);
2858c2ecf20Sopenharmony_ci	if (err)
2868c2ecf20Sopenharmony_ci		pci_disable_device(dev);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return err;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic void aec62xx_remove(struct pci_dev *dev)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	ide_pci_remove(dev);
2948c2ecf20Sopenharmony_ci	pci_disable_device(dev);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic const struct pci_device_id aec62xx_pci_tbl[] = {
2988c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
2998c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860),   1 },
3008c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R),  2 },
3018c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865),   3 },
3028c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R),  4 },
3038c2ecf20Sopenharmony_ci	{ 0, },
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic struct pci_driver aec62xx_pci_driver = {
3088c2ecf20Sopenharmony_ci	.name		= "AEC62xx_IDE",
3098c2ecf20Sopenharmony_ci	.id_table	= aec62xx_pci_tbl,
3108c2ecf20Sopenharmony_ci	.probe		= aec62xx_init_one,
3118c2ecf20Sopenharmony_ci	.remove		= aec62xx_remove,
3128c2ecf20Sopenharmony_ci	.suspend	= ide_pci_suspend,
3138c2ecf20Sopenharmony_ci	.resume		= ide_pci_resume,
3148c2ecf20Sopenharmony_ci};
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int __init aec62xx_ide_init(void)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	return ide_pci_register_driver(&aec62xx_pci_driver);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void __exit aec62xx_ide_exit(void)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	pci_unregister_driver(&aec62xx_pci_driver);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cimodule_init(aec62xx_ide_init);
3278c2ecf20Sopenharmony_cimodule_exit(aec62xx_ide_exit);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andre Hedrick");
3308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
3318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
332