diff options
Diffstat (limited to 'drivers/misc/cs5535-mfgpt.c')
| -rw-r--r-- | drivers/misc/cs5535-mfgpt.c | 120 | 
1 files changed, 61 insertions, 59 deletions
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 6f6218061b0..effd8c6b2b9 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -16,17 +16,19 @@  #include <linux/spinlock.h>  #include <linux/interrupt.h>  #include <linux/module.h> -#include <linux/pci.h> +#include <linux/platform_device.h>  #include <linux/cs5535.h>  #include <linux/slab.h>  #define DRV_NAME "cs5535-mfgpt" -#define MFGPT_BAR 2  static int mfgpt_reset_timers;  module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); -MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; " -		"required by some broken BIOSes (ie, TinyBIOS < 0.99)."); +MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; " +		"required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec " +		"(1 = reset the MFGPT using an undocumented bit, " +		"2 = perform a soft reset by unconfiguring all timers); " +		"use what works best for you.");  struct cs5535_mfgpt_timer {  	struct cs5535_mfgpt_chip *chip; @@ -37,7 +39,7 @@ static struct cs5535_mfgpt_chip {  	DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);  	resource_size_t base; -	struct pci_dev *pdev; +	struct platform_device *pdev;  	spinlock_t lock;  	int initialized;  } cs5535_mfgpt_chip; @@ -175,7 +177,7 @@ struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain)  		timer_nr = t < max ? (int) t : -1;  	} else {  		/* check if the requested timer's available */ -		if (test_bit(timer_nr, mfgpt->avail)) +		if (!test_bit(timer_nr, mfgpt->avail))  			timer_nr = -1;  	} @@ -247,7 +249,7 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_write);   * Jordan tells me that he and Mitch once played w/ it, but it's unclear   * what the results of that were (and they experienced some instability).   */ -static void __init reset_all_timers(void) +static void reset_all_timers(void)  {  	uint32_t val, dummy; @@ -257,13 +259,35 @@ static void __init reset_all_timers(void)  }  /* + * This is another sledgehammer to reset all MFGPT timers. + * Instead of using the undocumented bit method it clears + * IRQ, NMI and RESET settings. + */ +static void soft_reset(void) +{ +	int i; +	struct cs5535_mfgpt_timer t; + +	for (i = 0; i < MFGPT_MAX_TIMERS; i++) { +		t.nr = i; + +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0); +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0); +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0); +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0); +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0); +		cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0); +	} +} + +/*   * Check whether any MFGPTs are available for the kernel to use.  In most   * cases, firmware that uses AMD's VSA code will claim all timers during   * bootup; we certainly don't want to take them if they're already in use.   * In other cases (such as with VSAless OpenFirmware), the system firmware   * leaves timers available for us to use.   */ -static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt) +static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)  {  	struct cs5535_mfgpt_timer timer = { .chip = mfgpt };  	unsigned long flags; @@ -272,15 +296,17 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)  	int i;  	/* bios workaround */ -	if (mfgpt_reset_timers) +	if (mfgpt_reset_timers == 1)  		reset_all_timers(); +	else if (mfgpt_reset_timers == 2) +		soft_reset();  	/* just to be safe, protect this section w/ lock */  	spin_lock_irqsave(&mfgpt->lock, flags);  	for (i = 0; i < MFGPT_MAX_TIMERS; i++) {  		timer.nr = i;  		val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP); -		if (!(val & MFGPT_SETUP_SETUP)) { +		if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {  			__set_bit(i, mfgpt->avail);  			timers++;  		} @@ -290,10 +316,16 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)  	return timers;  } -static int __init cs5535_mfgpt_probe(struct pci_dev *pdev, -		const struct pci_device_id *pci_id) +static int cs5535_mfgpt_probe(struct platform_device *pdev)  { -	int err, t; +	struct resource *res; +	int err = -EIO, t; + +	if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) { +		dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n", +			mfgpt_reset_timers); +		goto done; +	}  	/* There are two ways to get the MFGPT base address; one is by  	 * fetching it from MSR_LBAR_MFGPT, the other is by reading the @@ -302,29 +334,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,  	 * it turns out to be unreliable in the face of crappy BIOSes, we  	 * can always go back to using MSRs.. */ -	err = pci_enable_device_io(pdev); -	if (err) { -		dev_err(&pdev->dev, "can't enable device IO\n"); +	res = platform_get_resource(pdev, IORESOURCE_IO, 0); +	if (!res) { +		dev_err(&pdev->dev, "can't fetch device resource info\n");  		goto done;  	} -	err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME); -	if (err) { -		dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR); +	if (!request_region(res->start, resource_size(res), pdev->name)) { +		dev_err(&pdev->dev, "can't request region\n");  		goto done;  	}  	/* set up the driver-specific struct */ -	cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR); +	cs5535_mfgpt_chip.base = res->start;  	cs5535_mfgpt_chip.pdev = pdev;  	spin_lock_init(&cs5535_mfgpt_chip.lock); -	dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR, -			(unsigned long long) cs5535_mfgpt_chip.base); +	dev_info(&pdev->dev, "reserved resource region %pR\n", res);  	/* detect the available timers */  	t = scan_timers(&cs5535_mfgpt_chip); -	dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t); +	dev_info(&pdev->dev, "%d MFGPT timers available\n", t);  	cs5535_mfgpt_chip.initialized = 1;  	return 0; @@ -332,47 +362,18 @@ done:  	return err;  } -static struct pci_device_id cs5535_mfgpt_pci_tbl[] = { -	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, -	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, -	{ 0, }, +static struct platform_driver cs5535_mfgpt_driver = { +	.driver = { +		.name = DRV_NAME, +		.owner = THIS_MODULE, +	}, +	.probe = cs5535_mfgpt_probe,  }; -MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl); -/* - * Just like with the cs5535-gpio driver, we can't use the standard PCI driver - * registration stuff.  It only allows only one driver to bind to each PCI - * device, and we want the GPIO and MFGPT drivers to be able to share a PCI - * device.  Instead, we manually scan for the PCI device, request a single - * region, and keep track of the devices that we're using. - */ - -static int __init cs5535_mfgpt_scan_pci(void) -{ -	struct pci_dev *pdev; -	int err = -ENODEV; -	int i; - -	for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) { -		pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor, -				cs5535_mfgpt_pci_tbl[i].device, NULL); -		if (pdev) { -			err = cs5535_mfgpt_probe(pdev, -					&cs5535_mfgpt_pci_tbl[i]); -			if (err) -				pci_dev_put(pdev); - -			/* we only support a single CS5535/6 southbridge */ -			break; -		} -	} - -	return err; -}  static int __init cs5535_mfgpt_init(void)  { -	return cs5535_mfgpt_scan_pci(); +	return platform_driver_register(&cs5535_mfgpt_driver);  }  module_init(cs5535_mfgpt_init); @@ -380,3 +381,4 @@ module_init(cs5535_mfgpt_init);  MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");  MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");  MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME);  | 
