Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80cd3a87 authored by Jordan Crouse's avatar Jordan Crouse Committed by Greg Kroah-Hartman
Browse files

[PATCH] scx200_acb: Use PCI I/O resource when appropriate



On the CS5535 and CS5536, the I/O resource is allocated through PCI,
so use that instead of using the MSR backdoor.

Signed-off-by: default avatarJordan Crouse <jordan.crouse@amd.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 46f5ed75
Loading
Loading
Loading
Loading
+147 −53
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/msr.h>

#include <linux/scx200.h>

@@ -85,6 +84,10 @@ struct scx200_acb_iface {
	u8 *ptr;
	char needs_reset;
	unsigned len;

	/* PCI device info */
	struct pci_dev *pdev;
	int bar;
};

/* Register Definitions */
@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface)
	return 0;
}

static int  __init scx200_acb_create(const char *text, int base, int index)
static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
		int index)
{
	struct scx200_acb_iface *iface;
	struct i2c_adapter *adapter;
	int rc;

	iface = kzalloc(sizeof(*iface), GFP_KERNEL);
	if (!iface) {
		printk(KERN_ERR NAME ": can't allocate memory\n");
		rc = -ENOMEM;
		goto errout;
		return NULL;
	}

	adapter = &iface->adapter;
@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index)

	mutex_init(&iface->mutex);

	if (!request_region(base, 8, adapter->name)) {
		printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n",
			base, base + 8-1);
		rc = -EBUSY;
		goto errout_free;
	return iface;
}
	iface->base = base;

static int __init scx200_acb_create(struct scx200_acb_iface *iface)
{
	struct i2c_adapter *adapter;
	int rc;

	adapter = &iface->adapter;

	rc = scx200_acb_probe(iface);
	if (rc) {
		printk(KERN_WARNING NAME ": probe failed\n");
		goto errout_release;
		return rc;
	}

	scx200_acb_reset(iface);

	if (i2c_add_adapter(adapter) < 0) {
		printk(KERN_ERR NAME ": failed to register\n");
		rc = -ENODEV;
		goto errout_release;
		return -ENODEV;
	}

	down(&scx200_acb_list_mutex);
@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index)
	up(&scx200_acb_list_mutex);

	return 0;
}

 errout_release:
	release_region(iface->base, 8);
static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
		int bar)
{
	struct scx200_acb_iface *iface;
	int rc;

	iface = scx200_create_iface(text, 0);

	if (iface == NULL)
		return -ENOMEM;

	iface->pdev = pdev;
	iface->bar = bar;

	pci_enable_device_bars(iface->pdev, 1 << iface->bar);

	rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);

	if (rc != 0) {
		printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
				iface->bar);
		goto errout_free;
	}

	iface->base = pci_resource_start(iface->pdev, iface->bar);
	rc = scx200_acb_create(iface);

	if (rc == 0)
		return 0;

	pci_release_region(iface->pdev, iface->bar);
	pci_dev_put(iface->pdev);
 errout_free:
	kfree(iface);
 errout:
	return rc;
}

static struct pci_device_id scx200[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
	{ },
};
static int __init scx200_create_isa(const char *text, unsigned long base,
		int index)
{
	struct scx200_acb_iface *iface;
	int rc;

	iface = scx200_create_iface(text, index);

	if (iface == NULL)
		return -ENOMEM;

	if (request_region(base, 8, iface->adapter.name) == 0) {
		printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
		       base, base + 8 - 1);
		rc = -EBUSY;
		goto errout_free;
	}

	iface->base = base;
	rc = scx200_acb_create(iface);

	if (rc == 0)
		return 0;

static struct pci_device_id divil_pci[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_NS,  PCI_DEVICE_ID_NS_CS5535_ISA) },
	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
	{ } /* NULL entry */
	release_region(base, 8);
 errout_free:
	kfree(iface);
	return rc;
}

/* Driver data is an index into the scx200_data array that indicates
 * the name and the BAR where the I/O address resource is located.  ISA
 * devices are flagged with a bar value of -1 */

static struct pci_device_id scx200_pci[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
	  .driver_data = 0 },
	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
	  .driver_data = 0 },
	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
	  .driver_data = 1 },
	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
	  .driver_data = 2 }
};

#define MSR_LBAR_SMB		0x5140000B
static struct {
	const char *name;
	int bar;
} scx200_data[] = {
	{ "SCx200", -1 },
	{ "CS5535",  0 },
	{ "CS5536",  0 }
};

static __init int scx200_add_cs553x(void)
static __init int scx200_scan_pci(void)
{
	u32	low, hi;
	u32	smb_base;
	int data, dev;
	int rc = -ENODEV;
	struct pci_dev *pdev;

	/* Grab & reserve the SMB I/O range */
	rdmsr(MSR_LBAR_SMB, low, hi);
	for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
		pdev = pci_get_device(scx200_pci[dev].vendor,
				scx200_pci[dev].device, NULL);

	/* Check the IO mask and whether SMB is enabled */
	if (hi != 0x0000F001) {
		printk(KERN_WARNING NAME ": SMBus not enabled\n");
		return -ENODEV;
		if (pdev == NULL)
			continue;

		data = scx200_pci[dev].driver_data;

		/* if .bar is greater or equal to zero, this is a
		 * PCI device - otherwise, we assume
		   that the ports are ISA based
		*/

		if (scx200_data[data].bar >= 0)
			rc = scx200_create_pci(scx200_data[data].name, pdev,
					scx200_data[data].bar);
		else {
			int i;

			for (i = 0; i < MAX_DEVICES; ++i) {
				if (base[i] == 0)
					continue;

				rc = scx200_create_isa(scx200_data[data].name,
						base[i],
						i);
			}
		}

	/* SMBus IO size is 8 bytes */
	smb_base = low & 0x0000FFF8;
		break;
	}

	return scx200_acb_create("CS5535", smb_base, 0);
	return rc;
}

static int __init scx200_acb_init(void)
{
	int i;
	int	rc = -ENODEV;
	int rc;

	pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");

	/* Verify that this really is a SCx200 processor */
	if (pci_dev_present(scx200)) {
		for (i = 0; i < MAX_DEVICES; ++i) {
			if (base[i] > 0)
				rc = scx200_acb_create("SCx200", base[i], i);
		}
	} else if (pci_dev_present(divil_pci))
		rc = scx200_add_cs553x();
	rc = scx200_scan_pci();

	/* If at least one bus was created, init must succeed */
	if (scx200_acb_list)
@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void)
		up(&scx200_acb_list_mutex);

		i2c_del_adapter(&iface->adapter);

		if (iface->pdev) {
			pci_release_region(iface->pdev, iface->bar);
			pci_dev_put(iface->pdev);
		}
		else
			release_region(iface->base, 8);

		kfree(iface);
		down(&scx200_acb_list_mutex);
	}