mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (59 commits) mfd: ab8500-core chip version cut 2.0 support mfd: Flag WM831x /IRQ as a wake source mfd: Convert WM831x away from legacy I2C PM operations regulator: Support MAX8998/LP3974 DVS-GPIO mfd: Support LP3974 RTC i2c: Convert SCx200 driver from using raw PCI to platform device x86: OLPC: convert olpc-xo1 driver from pci device to platform device mfd: MAX8998/LP3974 hibernation support mfd/ab8500: remove spi support mfd: Remove ARCH_U8500 dependency from AB8500 misc: Make AB8500_PWM driver depend on U8500 due to PWM breakage mfd: Add __devexit annotation for vx855_remove mfd: twl6030 irq_data conversion. gpio: Fix cs5535 printk warnings misc: Fix cs5535 printk warnings mfd: Convert Wolfson MFD drivers to use irq_data accessor function mfd: Convert TWL4030 to new irq_ APIs mfd: Convert tps6586x driver to new irq_ API mfd: Convert tc6393xb driver to new irq_ APIs mfd: Convert t7166xb driver to new irq_ API ...
This commit is contained in:
commit
822e5215f9
@ -2068,7 +2068,7 @@ config OLPC
|
||||
|
||||
config OLPC_XO1
|
||||
tristate "OLPC XO-1 support"
|
||||
depends on OLPC && PCI
|
||||
depends on OLPC && MFD_CS5535
|
||||
---help---
|
||||
Add support for non-essential features of the OLPC XO-1 laptop.
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Support for features of the OLPC XO-1 laptop
|
||||
*
|
||||
* Copyright (C) 2010 Andres Salomon <dilinger@queued.net>
|
||||
* Copyright (C) 2010 One Laptop per Child
|
||||
* Copyright (C) 2006 Red Hat, Inc.
|
||||
* Copyright (C) 2006 Advanced Micro Devices, Inc.
|
||||
@ -12,8 +13,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
@ -22,9 +21,6 @@
|
||||
|
||||
#define DRV_NAME "olpc-xo1"
|
||||
|
||||
#define PMS_BAR 4
|
||||
#define ACPI_BAR 5
|
||||
|
||||
/* PMC registers (PMS block) */
|
||||
#define PM_SCLK 0x10
|
||||
#define PM_IN_SLPCTL 0x20
|
||||
@ -57,65 +53,67 @@ static void xo1_power_off(void)
|
||||
outl(0x00002000, acpi_base + PM1_CNT);
|
||||
}
|
||||
|
||||
/* Read the base addresses from the PCI BAR info */
|
||||
static int __devinit setup_bases(struct pci_dev *pdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = pci_enable_device_io(pdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "can't enable device IO\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
|
||||
pci_release_region(pdev, ACPI_BAR);
|
||||
return r;
|
||||
}
|
||||
|
||||
acpi_base = pci_resource_start(pdev, ACPI_BAR);
|
||||
pms_base = pci_resource_start(pdev, PMS_BAR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit olpc_xo1_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_dev *pcidev;
|
||||
int r;
|
||||
struct resource *res;
|
||||
|
||||
pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
|
||||
NULL);
|
||||
if (!pdev)
|
||||
/* don't run on non-XOs */
|
||||
if (!machine_is_olpc())
|
||||
return -ENODEV;
|
||||
|
||||
r = setup_bases(pcidev);
|
||||
if (r)
|
||||
return r;
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't fetch device resource info\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pm_power_off = xo1_power_off;
|
||||
if (!request_region(res->start, resource_size(res), DRV_NAME)) {
|
||||
dev_err(&pdev->dev, "can't request region\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (strcmp(pdev->name, "cs5535-pms") == 0)
|
||||
pms_base = res->start;
|
||||
else if (strcmp(pdev->name, "cs5535-acpi") == 0)
|
||||
acpi_base = res->start;
|
||||
|
||||
/* If we have both addresses, we can override the poweroff hook */
|
||||
if (pms_base && acpi_base) {
|
||||
pm_power_off = xo1_power_off;
|
||||
printk(KERN_INFO "OLPC XO-1 support registered\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "OLPC XO-1 support registered\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit olpc_xo1_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(r->start, resource_size(r));
|
||||
|
||||
if (strcmp(pdev->name, "cs5535-pms") == 0)
|
||||
pms_base = 0;
|
||||
else if (strcmp(pdev->name, "cs5535-acpi") == 0)
|
||||
acpi_base = 0;
|
||||
|
||||
pm_power_off = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver olpc_xo1_driver = {
|
||||
static struct platform_driver cs5535_pms_drv = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.name = "cs5535-pms",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = olpc_xo1_probe,
|
||||
.remove = __devexit_p(olpc_xo1_remove),
|
||||
};
|
||||
|
||||
static struct platform_driver cs5535_acpi_drv = {
|
||||
.driver = {
|
||||
.name = "cs5535-acpi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = olpc_xo1_probe,
|
||||
@ -124,12 +122,23 @@ static struct platform_driver olpc_xo1_driver = {
|
||||
|
||||
static int __init olpc_xo1_init(void)
|
||||
{
|
||||
return platform_driver_register(&olpc_xo1_driver);
|
||||
int r;
|
||||
|
||||
r = platform_driver_register(&cs5535_pms_drv);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = platform_driver_register(&cs5535_acpi_drv);
|
||||
if (r)
|
||||
platform_driver_unregister(&cs5535_pms_drv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit olpc_xo1_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&olpc_xo1_driver);
|
||||
platform_driver_unregister(&cs5535_acpi_drv);
|
||||
platform_driver_unregister(&cs5535_pms_drv);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
|
||||
|
@ -11,14 +11,13 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cs5535.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
#define DRV_NAME "cs5535-gpio"
|
||||
#define GPIO_BAR 1
|
||||
|
||||
/*
|
||||
* Some GPIO pins
|
||||
@ -47,7 +46,7 @@ static struct cs5535_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
resource_size_t base;
|
||||
|
||||
struct pci_dev *pdev;
|
||||
struct platform_device *pdev;
|
||||
spinlock_t lock;
|
||||
} cs5535_gpio_chip;
|
||||
|
||||
@ -301,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init cs5535_gpio_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *pci_id)
|
||||
static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct resource *res;
|
||||
int err = -EIO;
|
||||
ulong mask_orig = mask;
|
||||
|
||||
/* There are two ways to get the GPIO base address; one is by
|
||||
@ -314,25 +313,23 @@ static int __init cs5535_gpio_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, GPIO_BAR, DRV_NAME);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_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_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
|
||||
cs5535_gpio_chip.base = res->start;
|
||||
cs5535_gpio_chip.pdev = pdev;
|
||||
spin_lock_init(&cs5535_gpio_chip.lock);
|
||||
|
||||
dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
|
||||
(unsigned long long) cs5535_gpio_chip.base);
|
||||
dev_info(&pdev->dev, "reserved resource region %pR\n", res);
|
||||
|
||||
/* mask out reserved pins */
|
||||
mask &= 0x1F7FFFFF;
|
||||
@ -350,78 +347,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
|
||||
if (err)
|
||||
goto release_region;
|
||||
|
||||
dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
|
||||
dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
|
||||
return 0;
|
||||
|
||||
release_region:
|
||||
pci_release_region(pdev, GPIO_BAR);
|
||||
release_region(res->start, resource_size(res));
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
|
||||
static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&cs5535_gpio_chip.chip);
|
||||
if (err) {
|
||||
/* uhh? */
|
||||
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
|
||||
return err;
|
||||
}
|
||||
pci_release_region(pdev, GPIO_BAR);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(r->start, resource_size(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_device_id cs5535_gpio_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_gpio_drv = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cs5535_gpio_probe,
|
||||
.remove = __devexit_p(cs5535_gpio_remove),
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
|
||||
|
||||
/*
|
||||
* We can't use the standard PCI driver registration stuff here, since
|
||||
* that allows only one driver to bind to each PCI device (and we want
|
||||
* multiple drivers to be able to bind to the device). Instead, manually
|
||||
* scan for the PCI device, request a single region, and keep track of the
|
||||
* devices that we're using.
|
||||
*/
|
||||
|
||||
static int __init cs5535_gpio_scan_pci(void)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
int err = -ENODEV;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
|
||||
pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
|
||||
cs5535_gpio_pci_tbl[i].device, NULL);
|
||||
if (pdev) {
|
||||
err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
|
||||
if (err)
|
||||
pci_dev_put(pdev);
|
||||
|
||||
/* we only support a single CS5535/6 southbridge */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit cs5535_gpio_free_pci(void)
|
||||
{
|
||||
cs5535_gpio_remove(cs5535_gpio_chip.pdev);
|
||||
pci_dev_put(cs5535_gpio_chip.pdev);
|
||||
}
|
||||
|
||||
static int __init cs5535_gpio_init(void)
|
||||
{
|
||||
return cs5535_gpio_scan_pci();
|
||||
return platform_driver_register(&cs5535_gpio_drv);
|
||||
}
|
||||
|
||||
static void __exit cs5535_gpio_exit(void)
|
||||
{
|
||||
cs5535_gpio_free_pci();
|
||||
platform_driver_unregister(&cs5535_gpio_drv);
|
||||
}
|
||||
|
||||
module_init(cs5535_gpio_init);
|
||||
@ -430,3 +398,4 @@ module_exit(cs5535_gpio_exit);
|
||||
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
|
||||
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
@ -40,6 +41,7 @@
|
||||
|
||||
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
|
||||
MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
|
||||
MODULE_ALIAS("platform:cs5535-smb");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define MAX_DEVICES 4
|
||||
@ -84,10 +86,6 @@ struct scx200_acb_iface {
|
||||
u8 *ptr;
|
||||
char needs_reset;
|
||||
unsigned len;
|
||||
|
||||
/* PCI device info */
|
||||
struct pci_dev *pdev;
|
||||
int bar;
|
||||
};
|
||||
|
||||
/* Register Definitions */
|
||||
@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
|
||||
static struct scx200_acb_iface *scx200_acb_list;
|
||||
static DEFINE_MUTEX(scx200_acb_list_mutex);
|
||||
|
||||
static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
|
||||
static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
|
||||
static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
|
||||
struct device *dev, int index)
|
||||
{
|
||||
struct scx200_acb_iface *iface;
|
||||
@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
|
||||
return iface;
|
||||
}
|
||||
|
||||
static int __init scx200_acb_create(struct scx200_acb_iface *iface)
|
||||
static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
int rc;
|
||||
@ -472,67 +470,31 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&scx200_acb_list_mutex);
|
||||
iface->next = scx200_acb_list;
|
||||
scx200_acb_list = iface;
|
||||
mutex_unlock(&scx200_acb_list_mutex);
|
||||
if (!adapter->dev.parent) {
|
||||
/* If there's no dev, we're tracking (ISA) ifaces manually */
|
||||
mutex_lock(&scx200_acb_list_mutex);
|
||||
iface->next = scx200_acb_list;
|
||||
scx200_acb_list = iface;
|
||||
mutex_unlock(&scx200_acb_list_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
|
||||
int bar)
|
||||
static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
|
||||
unsigned long base, int index, struct device *dev)
|
||||
{
|
||||
struct scx200_acb_iface *iface;
|
||||
int rc;
|
||||
|
||||
iface = scx200_create_iface(text, &pdev->dev, 0);
|
||||
iface = scx200_create_iface(text, dev, index);
|
||||
|
||||
if (iface == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
iface->pdev = pdev;
|
||||
iface->bar = bar;
|
||||
|
||||
rc = pci_enable_device_io(iface->pdev);
|
||||
if (rc)
|
||||
goto errout_free;
|
||||
|
||||
rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
|
||||
if (rc) {
|
||||
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);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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, NULL, index);
|
||||
|
||||
if (iface == NULL)
|
||||
return -ENOMEM;
|
||||
return NULL;
|
||||
|
||||
if (!request_region(base, 8, iface->adapter.name)) {
|
||||
printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
|
||||
base, base + 8 - 1);
|
||||
rc = -EBUSY;
|
||||
goto errout_free;
|
||||
}
|
||||
|
||||
@ -540,115 +502,113 @@ static int __init scx200_create_isa(const char *text, unsigned long base,
|
||||
rc = scx200_acb_create(iface);
|
||||
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
return iface;
|
||||
|
||||
release_region(base, 8);
|
||||
errout_free:
|
||||
kfree(iface);
|
||||
return rc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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 int __devinit scx200_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct scx200_acb_iface *iface;
|
||||
struct resource *res;
|
||||
|
||||
static const struct pci_device_id scx200_pci[] __initconst = {
|
||||
{ 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 },
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't fetch device resource info\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
|
||||
if (!iface)
|
||||
return -EIO;
|
||||
|
||||
dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
|
||||
iface->adapter.name);
|
||||
platform_set_drvdata(pdev, iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
|
||||
{
|
||||
i2c_del_adapter(&iface->adapter);
|
||||
release_region(iface->base, 8);
|
||||
kfree(iface);
|
||||
}
|
||||
|
||||
static int __devexit scx200_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct scx200_acb_iface *iface;
|
||||
|
||||
iface = platform_get_drvdata(pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
scx200_cleanup_iface(iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver scx200_pci_drv = {
|
||||
.driver = {
|
||||
.name = "cs5535-smb",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = scx200_probe,
|
||||
.remove = __devexit_p(scx200_remove),
|
||||
};
|
||||
|
||||
static const struct pci_device_id scx200_isa[] __initconst = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int bar;
|
||||
} scx200_data[] = {
|
||||
{ "SCx200", -1 },
|
||||
{ "CS5535", 0 },
|
||||
{ "CS5536", 0 }
|
||||
};
|
||||
|
||||
static __init int scx200_scan_pci(void)
|
||||
static __init void scx200_scan_isa(void)
|
||||
{
|
||||
int data, dev;
|
||||
int rc = -ENODEV;
|
||||
struct pci_dev *pdev;
|
||||
int i;
|
||||
|
||||
for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
|
||||
pdev = pci_get_device(scx200_pci[dev].vendor,
|
||||
scx200_pci[dev].device, NULL);
|
||||
if (!pci_dev_present(scx200_isa))
|
||||
return;
|
||||
|
||||
if (pdev == NULL)
|
||||
for (i = 0; i < MAX_DEVICES; ++i) {
|
||||
if (base[i] == 0)
|
||||
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;
|
||||
|
||||
pci_dev_put(pdev);
|
||||
for (i = 0; i < MAX_DEVICES; ++i) {
|
||||
if (base[i] == 0)
|
||||
continue;
|
||||
|
||||
rc = scx200_create_isa(scx200_data[data].name,
|
||||
base[i],
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
/* XXX: should we care about failures? */
|
||||
scx200_create_dev("SCx200", base[i], i, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __init scx200_acb_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
|
||||
|
||||
rc = scx200_scan_pci();
|
||||
/* First scan for ISA-based devices */
|
||||
scx200_scan_isa(); /* XXX: should we care about errors? */
|
||||
|
||||
/* If at least one bus was created, init must succeed */
|
||||
if (scx200_acb_list)
|
||||
return 0;
|
||||
return rc;
|
||||
|
||||
/* No ISA devices; register the platform driver for PCI-based devices */
|
||||
return platform_driver_register(&scx200_pci_drv);
|
||||
}
|
||||
|
||||
static void __exit scx200_acb_cleanup(void)
|
||||
{
|
||||
struct scx200_acb_iface *iface;
|
||||
|
||||
platform_driver_unregister(&scx200_pci_drv);
|
||||
|
||||
mutex_lock(&scx200_acb_list_mutex);
|
||||
while ((iface = scx200_acb_list) != NULL) {
|
||||
scx200_acb_list = iface->next;
|
||||
mutex_unlock(&scx200_acb_list_mutex);
|
||||
|
||||
i2c_del_adapter(&iface->adapter);
|
||||
scx200_cleanup_iface(iface);
|
||||
|
||||
if (iface->pdev) {
|
||||
pci_release_region(iface->pdev, iface->bar);
|
||||
pci_dev_put(iface->pdev);
|
||||
}
|
||||
else
|
||||
release_region(iface->base, 8);
|
||||
|
||||
kfree(iface);
|
||||
mutex_lock(&scx200_acb_list_mutex);
|
||||
}
|
||||
mutex_unlock(&scx200_acb_list_mutex);
|
||||
|
@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
|
||||
int irq)
|
||||
{
|
||||
return &pm860x_irqs[irq - chip->irq_base];
|
||||
}
|
||||
|
||||
static irqreturn_t pm860x_irq(int irq, void *data)
|
||||
{
|
||||
struct pm860x_chip *chip = data;
|
||||
@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void pm860x_irq_lock(unsigned int irq)
|
||||
static void pm860x_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = get_irq_chip_data(irq);
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&chip->irq_lock);
|
||||
}
|
||||
|
||||
static void pm860x_irq_sync_unlock(unsigned int irq)
|
||||
static void pm860x_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = get_irq_chip_data(irq);
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct pm860x_irq_data *irq_data;
|
||||
struct i2c_client *i2c;
|
||||
static unsigned char cached[3] = {0x0, 0x0, 0x0};
|
||||
@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&chip->irq_lock);
|
||||
}
|
||||
|
||||
static void pm860x_irq_enable(unsigned int irq)
|
||||
static void pm860x_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = get_irq_chip_data(irq);
|
||||
pm860x_irqs[irq - chip->irq_base].enable
|
||||
= pm860x_irqs[irq - chip->irq_base].offs;
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
pm860x_irqs[data->irq - chip->irq_base].enable
|
||||
= pm860x_irqs[data->irq - chip->irq_base].offs;
|
||||
}
|
||||
|
||||
static void pm860x_irq_disable(unsigned int irq)
|
||||
static void pm860x_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct pm860x_chip *chip = get_irq_chip_data(irq);
|
||||
pm860x_irqs[irq - chip->irq_base].enable = 0;
|
||||
struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
pm860x_irqs[data->irq - chip->irq_base].enable = 0;
|
||||
}
|
||||
|
||||
static struct irq_chip pm860x_irq_chip = {
|
||||
.name = "88pm860x",
|
||||
.bus_lock = pm860x_irq_lock,
|
||||
.bus_sync_unlock = pm860x_irq_sync_unlock,
|
||||
.enable = pm860x_irq_enable,
|
||||
.disable = pm860x_irq_disable,
|
||||
.irq_bus_lock = pm860x_irq_lock,
|
||||
.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
|
||||
.irq_enable = pm860x_irq_enable,
|
||||
.irq_disable = pm860x_irq_disable,
|
||||
};
|
||||
|
||||
static int __devinit device_gpadc_init(struct pm860x_chip *chip,
|
||||
|
@ -496,13 +496,13 @@ config EZX_PCAP
|
||||
|
||||
config AB8500_CORE
|
||||
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
|
||||
depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
|
||||
depends on GENERIC_HARDIRQS && ABX500_CORE
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this option to enable access to AB8500 power management
|
||||
chip. This connects to U8500 either on the SSP/SPI bus
|
||||
or the I2C bus via PRCMU. It also adds the irq_chip
|
||||
parts for handling the Mixed Signal chip events.
|
||||
chip. This connects to U8500 either on the SSP/SPI bus (deprecated
|
||||
since hardware version v1.0) or the I2C bus via PRCMU. It also adds
|
||||
the irq_chip parts for handling the Mixed Signal chip events.
|
||||
This chip embeds various other multimedia funtionalities as well.
|
||||
|
||||
config AB8500_I2C_CORE
|
||||
@ -537,6 +537,14 @@ config AB3550_CORE
|
||||
LEDs, vibrator, system power and temperature, power management
|
||||
and ALSA sound.
|
||||
|
||||
config MFD_CS5535
|
||||
tristate "Support for CS5535 and CS5536 southbridge core functions"
|
||||
select MFD_CORE
|
||||
depends on PCI
|
||||
---help---
|
||||
This is the core driver for CS5535/CS5536 MFD functions. This is
|
||||
necessary for using the board's GPIO and MFGPT functionality.
|
||||
|
||||
config MFD_TIMBERDALE
|
||||
tristate "Support for the Timberdale FPGA"
|
||||
select MFD_CORE
|
||||
|
@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
|
||||
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
|
||||
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
|
||||
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
|
||||
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
|
||||
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o
|
||||
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
|
||||
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
|
||||
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
|
||||
@ -82,3 +82,4 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
|
||||
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
|
||||
obj-$(CONFIG_MFD_VX855) += vx855.o
|
||||
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
|
||||
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
|
||||
|
@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static void ab3550_mask(unsigned int irq)
|
||||
static void ab3550_mask(struct irq_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ab3550 *ab;
|
||||
struct ab3550_platform_data *plf_data;
|
||||
int irq;
|
||||
|
||||
ab = get_irq_chip_data(irq);
|
||||
ab = irq_data_get_irq_chip_data(data);
|
||||
plf_data = ab->i2c_client[0]->dev.platform_data;
|
||||
irq -= plf_data->irq.base;
|
||||
irq = data->irq - plf_data->irq.base;
|
||||
|
||||
spin_lock_irqsave(&ab->event_lock, flags);
|
||||
ab->event_mask[irq / 8] |= BIT(irq % 8);
|
||||
@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq)
|
||||
schedule_work(&ab->mask_work);
|
||||
}
|
||||
|
||||
static void ab3550_unmask(unsigned int irq)
|
||||
static void ab3550_unmask(struct irq_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ab3550 *ab;
|
||||
struct ab3550_platform_data *plf_data;
|
||||
int irq;
|
||||
|
||||
ab = get_irq_chip_data(irq);
|
||||
ab = irq_data_get_irq_chip_data(data);
|
||||
plf_data = ab->i2c_client[0]->dev.platform_data;
|
||||
irq -= plf_data->irq.base;
|
||||
irq = data->irq - plf_data->irq.base;
|
||||
|
||||
spin_lock_irqsave(&ab->event_lock, flags);
|
||||
ab->event_mask[irq / 8] &= ~BIT(irq % 8);
|
||||
@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq)
|
||||
schedule_work(&ab->mask_work);
|
||||
}
|
||||
|
||||
static void noop(unsigned int irq)
|
||||
static void noop(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static struct irq_chip ab3550_irq_chip = {
|
||||
.name = "ab3550-core", /* Keep the same name as the request */
|
||||
.startup = NULL, /* defaults to enable */
|
||||
.shutdown = NULL, /* defaults to disable */
|
||||
.enable = NULL, /* defaults to unmask */
|
||||
.disable = ab3550_mask, /* No default to mask in chip.c */
|
||||
.ack = noop,
|
||||
.mask = ab3550_mask,
|
||||
.unmask = ab3550_unmask,
|
||||
.end = NULL,
|
||||
.irq_disable = ab3550_mask, /* No default to mask in chip.c */
|
||||
.irq_ack = noop,
|
||||
.irq_mask = ab3550_mask,
|
||||
.irq_unmask = ab3550_unmask,
|
||||
};
|
||||
|
||||
struct ab_family_id {
|
||||
|
@ -52,6 +52,7 @@
|
||||
#define AB8500_IT_LATCH8_REG 0x27
|
||||
#define AB8500_IT_LATCH9_REG 0x28
|
||||
#define AB8500_IT_LATCH10_REG 0x29
|
||||
#define AB8500_IT_LATCH12_REG 0x2B
|
||||
#define AB8500_IT_LATCH19_REG 0x32
|
||||
#define AB8500_IT_LATCH20_REG 0x33
|
||||
#define AB8500_IT_LATCH21_REG 0x34
|
||||
@ -98,13 +99,17 @@
|
||||
* offset 0.
|
||||
*/
|
||||
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
|
||||
0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
|
||||
0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
|
||||
};
|
||||
|
||||
static int ab8500_get_chip_id(struct device *dev)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
|
||||
return (int)ab8500->chip_id;
|
||||
struct ab8500 *ab8500;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
ab8500 = dev_get_drvdata(dev->parent);
|
||||
return ab8500 ? (int)ab8500->chip_id : -EINVAL;
|
||||
}
|
||||
|
||||
static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
|
||||
@ -228,16 +233,16 @@ static struct abx500_ops ab8500_ops = {
|
||||
.startup_irq_enabled = NULL,
|
||||
};
|
||||
|
||||
static void ab8500_irq_lock(unsigned int irq)
|
||||
static void ab8500_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct ab8500 *ab8500 = get_irq_chip_data(irq);
|
||||
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&ab8500->irq_lock);
|
||||
}
|
||||
|
||||
static void ab8500_irq_sync_unlock(unsigned int irq)
|
||||
static void ab8500_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct ab8500 *ab8500 = get_irq_chip_data(irq);
|
||||
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
|
||||
@ -248,6 +253,10 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
|
||||
if (new == old)
|
||||
continue;
|
||||
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
|
||||
continue;
|
||||
|
||||
ab8500->oldmask[i] = new;
|
||||
|
||||
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
|
||||
@ -257,20 +266,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&ab8500->irq_lock);
|
||||
}
|
||||
|
||||
static void ab8500_irq_mask(unsigned int irq)
|
||||
static void ab8500_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct ab8500 *ab8500 = get_irq_chip_data(irq);
|
||||
int offset = irq - ab8500->irq_base;
|
||||
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
|
||||
int offset = data->irq - ab8500->irq_base;
|
||||
int index = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
ab8500->mask[index] |= mask;
|
||||
}
|
||||
|
||||
static void ab8500_irq_unmask(unsigned int irq)
|
||||
static void ab8500_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct ab8500 *ab8500 = get_irq_chip_data(irq);
|
||||
int offset = irq - ab8500->irq_base;
|
||||
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
|
||||
int offset = data->irq - ab8500->irq_base;
|
||||
int index = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
@ -279,10 +288,10 @@ static void ab8500_irq_unmask(unsigned int irq)
|
||||
|
||||
static struct irq_chip ab8500_irq_chip = {
|
||||
.name = "ab8500",
|
||||
.bus_lock = ab8500_irq_lock,
|
||||
.bus_sync_unlock = ab8500_irq_sync_unlock,
|
||||
.mask = ab8500_irq_mask,
|
||||
.unmask = ab8500_irq_unmask,
|
||||
.irq_bus_lock = ab8500_irq_lock,
|
||||
.irq_bus_sync_unlock = ab8500_irq_sync_unlock,
|
||||
.irq_mask = ab8500_irq_mask,
|
||||
.irq_unmask = ab8500_irq_unmask,
|
||||
};
|
||||
|
||||
static irqreturn_t ab8500_irq(int irq, void *dev)
|
||||
@ -297,6 +306,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
|
||||
int status;
|
||||
u8 value;
|
||||
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (regoffset == 11 && ab8500->chip_id < 0x20)
|
||||
continue;
|
||||
|
||||
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
AB8500_IT_LATCH1_REG + regoffset, &value);
|
||||
if (status < 0 || value == 0)
|
||||
@ -393,12 +406,194 @@ static struct resource ab8500_poweronkey_db_resources[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ab8500_bm_resources[] = {
|
||||
{
|
||||
.name = "MAIN_EXT_CH_NOT_OK",
|
||||
.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
|
||||
.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "BATT_OVV",
|
||||
.start = AB8500_INT_BATT_OVV,
|
||||
.end = AB8500_INT_BATT_OVV,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "MAIN_CH_UNPLUG_DET",
|
||||
.start = AB8500_INT_MAIN_CH_UNPLUG_DET,
|
||||
.end = AB8500_INT_MAIN_CH_UNPLUG_DET,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "MAIN_CHARGE_PLUG_DET",
|
||||
.start = AB8500_INT_MAIN_CH_PLUG_DET,
|
||||
.end = AB8500_INT_MAIN_CH_PLUG_DET,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_DET_F",
|
||||
.start = AB8500_INT_VBUS_DET_F,
|
||||
.end = AB8500_INT_VBUS_DET_F,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_DET_R",
|
||||
.start = AB8500_INT_VBUS_DET_R,
|
||||
.end = AB8500_INT_VBUS_DET_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "BAT_CTRL_INDB",
|
||||
.start = AB8500_INT_BAT_CTRL_INDB,
|
||||
.end = AB8500_INT_BAT_CTRL_INDB,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "CH_WD_EXP",
|
||||
.start = AB8500_INT_CH_WD_EXP,
|
||||
.end = AB8500_INT_CH_WD_EXP,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_OVV",
|
||||
.start = AB8500_INT_VBUS_OVV,
|
||||
.end = AB8500_INT_VBUS_OVV,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "NCONV_ACCU",
|
||||
.start = AB8500_INT_CCN_CONV_ACC,
|
||||
.end = AB8500_INT_CCN_CONV_ACC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "LOW_BAT_F",
|
||||
.start = AB8500_INT_LOW_BAT_F,
|
||||
.end = AB8500_INT_LOW_BAT_F,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "LOW_BAT_R",
|
||||
.start = AB8500_INT_LOW_BAT_R,
|
||||
.end = AB8500_INT_LOW_BAT_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "BTEMP_LOW",
|
||||
.start = AB8500_INT_BTEMP_LOW,
|
||||
.end = AB8500_INT_BTEMP_LOW,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "BTEMP_HIGH",
|
||||
.start = AB8500_INT_BTEMP_HIGH,
|
||||
.end = AB8500_INT_BTEMP_HIGH,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "USB_CHARGER_NOT_OKR",
|
||||
.start = AB8500_INT_USB_CHARGER_NOT_OK,
|
||||
.end = AB8500_INT_USB_CHARGER_NOT_OK,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "USB_CHARGE_DET_DONE",
|
||||
.start = AB8500_INT_USB_CHG_DET_DONE,
|
||||
.end = AB8500_INT_USB_CHG_DET_DONE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "USB_CH_TH_PROT_R",
|
||||
.start = AB8500_INT_USB_CH_TH_PROT_R,
|
||||
.end = AB8500_INT_USB_CH_TH_PROT_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "MAIN_CH_TH_PROT_R",
|
||||
.start = AB8500_INT_MAIN_CH_TH_PROT_R,
|
||||
.end = AB8500_INT_MAIN_CH_TH_PROT_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "USB_CHARGER_NOT_OKF",
|
||||
.start = AB8500_INT_USB_CHARGER_NOT_OKF,
|
||||
.end = AB8500_INT_USB_CHARGER_NOT_OKF,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ab8500_debug_resources[] = {
|
||||
{
|
||||
.name = "IRQ_FIRST",
|
||||
.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
|
||||
.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "IRQ_LAST",
|
||||
.start = AB8500_INT_USB_CHARGER_NOT_OKF,
|
||||
.end = AB8500_INT_USB_CHARGER_NOT_OKF,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ab8500_usb_resources[] = {
|
||||
{
|
||||
.name = "ID_WAKEUP_R",
|
||||
.start = AB8500_INT_ID_WAKEUP_R,
|
||||
.end = AB8500_INT_ID_WAKEUP_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "ID_WAKEUP_F",
|
||||
.start = AB8500_INT_ID_WAKEUP_F,
|
||||
.end = AB8500_INT_ID_WAKEUP_F,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_DET_F",
|
||||
.start = AB8500_INT_VBUS_DET_F,
|
||||
.end = AB8500_INT_VBUS_DET_F,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "VBUS_DET_R",
|
||||
.start = AB8500_INT_VBUS_DET_R,
|
||||
.end = AB8500_INT_VBUS_DET_R,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "USB_LINK_STATUS",
|
||||
.start = AB8500_INT_USB_LINK_STATUS,
|
||||
.end = AB8500_INT_USB_LINK_STATUS,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ab8500_temp_resources[] = {
|
||||
{
|
||||
.name = "AB8500_TEMP_WARM",
|
||||
.start = AB8500_INT_TEMP_WARM,
|
||||
.end = AB8500_INT_TEMP_WARM,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell ab8500_devs[] = {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
{
|
||||
.name = "ab8500-debug",
|
||||
.num_resources = ARRAY_SIZE(ab8500_debug_resources),
|
||||
.resources = ab8500_debug_resources,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "ab8500-sysctrl",
|
||||
},
|
||||
{
|
||||
.name = "ab8500-regulator",
|
||||
},
|
||||
{
|
||||
.name = "ab8500-gpadc",
|
||||
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
|
||||
@ -409,6 +604,22 @@ static struct mfd_cell ab8500_devs[] = {
|
||||
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
|
||||
.resources = ab8500_rtc_resources,
|
||||
},
|
||||
{
|
||||
.name = "ab8500-bm",
|
||||
.num_resources = ARRAY_SIZE(ab8500_bm_resources),
|
||||
.resources = ab8500_bm_resources,
|
||||
},
|
||||
{ .name = "ab8500-codec", },
|
||||
{
|
||||
.name = "ab8500-usb",
|
||||
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
|
||||
.resources = ab8500_usb_resources,
|
||||
},
|
||||
{
|
||||
.name = "ab8500-poweron-key",
|
||||
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
|
||||
.resources = ab8500_poweronkey_db_resources,
|
||||
},
|
||||
{
|
||||
.name = "ab8500-pwm",
|
||||
.id = 1,
|
||||
@ -421,15 +632,35 @@ static struct mfd_cell ab8500_devs[] = {
|
||||
.name = "ab8500-pwm",
|
||||
.id = 3,
|
||||
},
|
||||
{ .name = "ab8500-charger", },
|
||||
{ .name = "ab8500-audio", },
|
||||
{ .name = "ab8500-usb", },
|
||||
{ .name = "ab8500-regulator", },
|
||||
{ .name = "ab8500-leds", },
|
||||
{
|
||||
.name = "ab8500-poweron-key",
|
||||
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
|
||||
.resources = ab8500_poweronkey_db_resources,
|
||||
.name = "ab8500-denc",
|
||||
},
|
||||
{
|
||||
.name = "ab8500-temp",
|
||||
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
|
||||
.resources = ab8500_temp_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static ssize_t show_chip_id(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ab8500 *ab8500;
|
||||
|
||||
ab8500 = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
|
||||
|
||||
static struct attribute *ab8500_sysfs_entries[] = {
|
||||
&dev_attr_chip_id.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ab8500_attr_group = {
|
||||
.attrs = ab8500_sysfs_entries,
|
||||
};
|
||||
|
||||
int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
@ -454,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
* 0x0 - Early Drop
|
||||
* 0x10 - Cut 1.0
|
||||
* 0x11 - Cut 1.1
|
||||
* 0x20 - Cut 2.0
|
||||
*/
|
||||
if (value == 0x0 || value == 0x10 || value == 0x11) {
|
||||
if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
|
||||
ab8500->revision = value;
|
||||
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
|
||||
} else {
|
||||
@ -468,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
plat->init(ab8500);
|
||||
|
||||
/* Clear and mask all interrupts */
|
||||
for (i = 0; i < 10; i++) {
|
||||
get_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
AB8500_IT_LATCH1_REG + i, &value);
|
||||
set_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
AB8500_IT_MASK1_REG + i, 0xff);
|
||||
}
|
||||
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
|
||||
continue;
|
||||
|
||||
for (i = 18; i < 24; i++) {
|
||||
get_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
AB8500_IT_LATCH1_REG + i, &value);
|
||||
AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
|
||||
&value);
|
||||
set_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
AB8500_IT_MASK1_REG + i, 0xff);
|
||||
AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
|
||||
}
|
||||
|
||||
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
|
||||
@ -495,7 +725,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
return ret;
|
||||
|
||||
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
|
||||
IRQF_ONESHOT, "ab8500", ab8500);
|
||||
IRQF_ONESHOT | IRQF_NO_SUSPEND,
|
||||
"ab8500", ab8500);
|
||||
if (ret)
|
||||
goto out_removeirq;
|
||||
}
|
||||
@ -506,6 +737,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
if (ret)
|
||||
goto out_freeirq;
|
||||
|
||||
ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
|
||||
if (ret)
|
||||
dev_err(ab8500->dev, "error creating sysfs entries\n");
|
||||
|
||||
return ret;
|
||||
|
||||
out_freeirq:
|
||||
@ -519,6 +754,7 @@ out_removeirq:
|
||||
|
||||
int __devexit ab8500_exit(struct ab8500 *ab8500)
|
||||
{
|
||||
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
|
||||
mfd_remove_devices(ab8500->dev);
|
||||
if (ab8500->irq_base) {
|
||||
free_irq(ab8500->irq, ab8500);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) ST-Ericsson SA 2010
|
||||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mfd/ab8500.h>
|
||||
|
||||
/*
|
||||
* This funtion writes to any AB8500 registers using
|
||||
* SPI protocol & before it writes it packs the data
|
||||
* in the below 24 bit frame format
|
||||
*
|
||||
* *|------------------------------------|
|
||||
* *| 23|22...18|17.......10|9|8|7......0|
|
||||
* *| r/w bank adr data |
|
||||
* * ------------------------------------
|
||||
*
|
||||
* This function shouldn't be called from interrupt
|
||||
* context
|
||||
*/
|
||||
static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data)
|
||||
{
|
||||
struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
|
||||
dev);
|
||||
unsigned long spi_data = addr << 10 | data;
|
||||
struct spi_transfer xfer;
|
||||
struct spi_message msg;
|
||||
|
||||
ab8500->tx_buf[0] = spi_data;
|
||||
ab8500->rx_buf[0] = 0;
|
||||
|
||||
xfer.tx_buf = ab8500->tx_buf;
|
||||
xfer.rx_buf = NULL;
|
||||
xfer.len = sizeof(unsigned long);
|
||||
|
||||
spi_message_init(&msg);
|
||||
spi_message_add_tail(&xfer, &msg);
|
||||
|
||||
return spi_sync(spi, &msg);
|
||||
}
|
||||
|
||||
static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
|
||||
{
|
||||
struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
|
||||
dev);
|
||||
unsigned long spi_data = 1 << 23 | addr << 10;
|
||||
struct spi_transfer xfer;
|
||||
struct spi_message msg;
|
||||
int ret;
|
||||
|
||||
ab8500->tx_buf[0] = spi_data;
|
||||
ab8500->rx_buf[0] = 0;
|
||||
|
||||
xfer.tx_buf = ab8500->tx_buf;
|
||||
xfer.rx_buf = ab8500->rx_buf;
|
||||
xfer.len = sizeof(unsigned long);
|
||||
|
||||
spi_message_init(&msg);
|
||||
spi_message_add_tail(&xfer, &msg);
|
||||
|
||||
ret = spi_sync(spi, &msg);
|
||||
if (!ret)
|
||||
/*
|
||||
* Only the 8 lowermost bytes are
|
||||
* defined with value, the rest may
|
||||
* vary depending on chip/board noise.
|
||||
*/
|
||||
ret = ab8500->rx_buf[0] & 0xFFU;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit ab8500_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ab8500 *ab8500;
|
||||
int ret;
|
||||
|
||||
spi->bits_per_word = 24;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
|
||||
if (!ab8500)
|
||||
return -ENOMEM;
|
||||
|
||||
ab8500->dev = &spi->dev;
|
||||
ab8500->irq = spi->irq;
|
||||
|
||||
ab8500->read = ab8500_spi_read;
|
||||
ab8500->write = ab8500_spi_write;
|
||||
|
||||
spi_set_drvdata(spi, ab8500);
|
||||
|
||||
ret = ab8500_init(ab8500);
|
||||
if (ret)
|
||||
kfree(ab8500);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ab8500_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct ab8500 *ab8500 = spi_get_drvdata(spi);
|
||||
|
||||
ab8500_exit(ab8500);
|
||||
kfree(ab8500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ab8500_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ab8500-spi",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ab8500_spi_probe,
|
||||
.remove = __devexit_p(ab8500_spi_remove)
|
||||
};
|
||||
|
||||
static int __init ab8500_spi_init(void)
|
||||
{
|
||||
return spi_register_driver(&ab8500_spi_driver);
|
||||
}
|
||||
subsys_initcall(ab8500_spi_init);
|
||||
|
||||
static void __exit ab8500_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ab8500_spi_driver);
|
||||
}
|
||||
module_exit(ab8500_spi_exit);
|
||||
|
||||
MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
|
||||
MODULE_DESCRIPTION("AB8500 SPI");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -57,7 +57,7 @@ struct asic3_clk {
|
||||
.rate = _rate, \
|
||||
}
|
||||
|
||||
struct asic3_clk asic3_clk_init[] __initdata = {
|
||||
static struct asic3_clk asic3_clk_init[] __initdata = {
|
||||
INIT_CDEX(SPI, 0),
|
||||
INIT_CDEX(OWM, 5000000),
|
||||
INIT_CDEX(PWM0, 0),
|
||||
@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic,
|
||||
(reg >> asic->bus_shift));
|
||||
}
|
||||
|
||||
void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
|
||||
static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
|
||||
return (irq - asic->irq_base) & 0xf;
|
||||
}
|
||||
|
||||
static void asic3_mask_gpio_irq(unsigned int irq)
|
||||
static void asic3_mask_gpio_irq(struct irq_data *data)
|
||||
{
|
||||
struct asic3 *asic = get_irq_chip_data(irq);
|
||||
struct asic3 *asic = irq_data_get_irq_chip_data(data);
|
||||
u32 val, bank, index;
|
||||
unsigned long flags;
|
||||
|
||||
bank = asic3_irq_to_bank(asic, irq);
|
||||
index = asic3_irq_to_index(asic, irq);
|
||||
bank = asic3_irq_to_bank(asic, data->irq);
|
||||
index = asic3_irq_to_index(asic, data->irq);
|
||||
|
||||
spin_lock_irqsave(&asic->lock, flags);
|
||||
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
|
||||
@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq)
|
||||
spin_unlock_irqrestore(&asic->lock, flags);
|
||||
}
|
||||
|
||||
static void asic3_mask_irq(unsigned int irq)
|
||||
static void asic3_mask_irq(struct irq_data *data)
|
||||
{
|
||||
struct asic3 *asic = get_irq_chip_data(irq);
|
||||
struct asic3 *asic = irq_data_get_irq_chip_data(data);
|
||||
int regval;
|
||||
unsigned long flags;
|
||||
|
||||
@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq)
|
||||
ASIC3_INTR_INT_MASK);
|
||||
|
||||
regval &= ~(ASIC3_INTMASK_MASK0 <<
|
||||
(irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
|
||||
(data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
|
||||
|
||||
asic3_write_register(asic,
|
||||
ASIC3_INTR_BASE +
|
||||
@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq)
|
||||
spin_unlock_irqrestore(&asic->lock, flags);
|
||||
}
|
||||
|
||||
static void asic3_unmask_gpio_irq(unsigned int irq)
|
||||
static void asic3_unmask_gpio_irq(struct irq_data *data)
|
||||
{
|
||||
struct asic3 *asic = get_irq_chip_data(irq);
|
||||
struct asic3 *asic = irq_data_get_irq_chip_data(data);
|
||||
u32 val, bank, index;
|
||||
unsigned long flags;
|
||||
|
||||
bank = asic3_irq_to_bank(asic, irq);
|
||||
index = asic3_irq_to_index(asic, irq);
|
||||
bank = asic3_irq_to_bank(asic, data->irq);
|
||||
index = asic3_irq_to_index(asic, data->irq);
|
||||
|
||||
spin_lock_irqsave(&asic->lock, flags);
|
||||
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
|
||||
@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq)
|
||||
spin_unlock_irqrestore(&asic->lock, flags);
|
||||
}
|
||||
|
||||
static void asic3_unmask_irq(unsigned int irq)
|
||||
static void asic3_unmask_irq(struct irq_data *data)
|
||||
{
|
||||
struct asic3 *asic = get_irq_chip_data(irq);
|
||||
struct asic3 *asic = irq_data_get_irq_chip_data(data);
|
||||
int regval;
|
||||
unsigned long flags;
|
||||
|
||||
@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq)
|
||||
ASIC3_INTR_INT_MASK);
|
||||
|
||||
regval |= (ASIC3_INTMASK_MASK0 <<
|
||||
(irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
|
||||
(data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
|
||||
|
||||
asic3_write_register(asic,
|
||||
ASIC3_INTR_BASE +
|
||||
@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq)
|
||||
spin_unlock_irqrestore(&asic->lock, flags);
|
||||
}
|
||||
|
||||
static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct asic3 *asic = get_irq_chip_data(irq);
|
||||
struct asic3 *asic = irq_data_get_irq_chip_data(data);
|
||||
u32 bank, index;
|
||||
u16 trigger, level, edge, bit;
|
||||
unsigned long flags;
|
||||
|
||||
bank = asic3_irq_to_bank(asic, irq);
|
||||
index = asic3_irq_to_index(asic, irq);
|
||||
bank = asic3_irq_to_bank(asic, data->irq);
|
||||
index = asic3_irq_to_index(asic, data->irq);
|
||||
bit = 1<<index;
|
||||
|
||||
spin_lock_irqsave(&asic->lock, flags);
|
||||
@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
bank + ASIC3_GPIO_EDGE_TRIGGER);
|
||||
trigger = asic3_read_register(asic,
|
||||
bank + ASIC3_GPIO_TRIGGER_TYPE);
|
||||
asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
|
||||
asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
|
||||
|
||||
if (type == IRQ_TYPE_EDGE_RISING) {
|
||||
trigger |= bit;
|
||||
@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
edge &= ~bit;
|
||||
} else if (type == IRQ_TYPE_EDGE_BOTH) {
|
||||
trigger |= bit;
|
||||
if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
|
||||
if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
|
||||
edge &= ~bit;
|
||||
else
|
||||
edge |= bit;
|
||||
asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
|
||||
asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
|
||||
} else if (type == IRQ_TYPE_LEVEL_LOW) {
|
||||
trigger &= ~bit;
|
||||
level &= ~bit;
|
||||
@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
|
||||
static struct irq_chip asic3_gpio_irq_chip = {
|
||||
.name = "ASIC3-GPIO",
|
||||
.ack = asic3_mask_gpio_irq,
|
||||
.mask = asic3_mask_gpio_irq,
|
||||
.unmask = asic3_unmask_gpio_irq,
|
||||
.set_type = asic3_gpio_irq_type,
|
||||
.irq_ack = asic3_mask_gpio_irq,
|
||||
.irq_mask = asic3_mask_gpio_irq,
|
||||
.irq_unmask = asic3_unmask_gpio_irq,
|
||||
.irq_set_type = asic3_gpio_irq_type,
|
||||
};
|
||||
|
||||
static struct irq_chip asic3_irq_chip = {
|
||||
.name = "ASIC3",
|
||||
.ack = asic3_mask_irq,
|
||||
.mask = asic3_mask_irq,
|
||||
.unmask = asic3_unmask_irq,
|
||||
.irq_ack = asic3_mask_irq,
|
||||
.irq_mask = asic3_mask_irq,
|
||||
.irq_unmask = asic3_unmask_irq,
|
||||
};
|
||||
|
||||
static int __init asic3_irq_probe(struct platform_device *pdev)
|
||||
@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = {
|
||||
},
|
||||
{
|
||||
.start = ASIC3_IRQ_OWM,
|
||||
.start = ASIC3_IRQ_OWM,
|
||||
.end = ASIC3_IRQ_OWM,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
|
||||
},
|
||||
};
|
||||
|
151
drivers/mfd/cs5535-mfd.c
Normal file
151
drivers/mfd/cs5535-mfd.c
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
|
||||
*
|
||||
* The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
|
||||
* used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has
|
||||
* an IO range that's specified in a single BAR. The BAR order is
|
||||
* hardcoded in the CS553x specifications.
|
||||
*
|
||||
* Copyright (c) 2010 Andres Salomon <dilinger@queued.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define DRV_NAME "cs5535-mfd"
|
||||
|
||||
enum cs5535_mfd_bars {
|
||||
SMB_BAR = 0,
|
||||
GPIO_BAR = 1,
|
||||
MFGPT_BAR = 2,
|
||||
PMS_BAR = 4,
|
||||
ACPI_BAR = 5,
|
||||
NR_BARS,
|
||||
};
|
||||
|
||||
static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
|
||||
|
||||
static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
|
||||
{
|
||||
.id = SMB_BAR,
|
||||
.name = "cs5535-smb",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[SMB_BAR],
|
||||
},
|
||||
{
|
||||
.id = GPIO_BAR,
|
||||
.name = "cs5535-gpio",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[GPIO_BAR],
|
||||
},
|
||||
{
|
||||
.id = MFGPT_BAR,
|
||||
.name = "cs5535-mfgpt",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[MFGPT_BAR],
|
||||
},
|
||||
{
|
||||
.id = PMS_BAR,
|
||||
.name = "cs5535-pms",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[PMS_BAR],
|
||||
},
|
||||
{
|
||||
.id = ACPI_BAR,
|
||||
.name = "cs5535-acpi",
|
||||
.num_resources = 1,
|
||||
.resources = &cs5535_mfd_resources[ACPI_BAR],
|
||||
},
|
||||
};
|
||||
|
||||
static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* fill in IO range for each cell; subdrivers handle the region */
|
||||
for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) {
|
||||
int bar = cs5535_mfd_cells[i].id;
|
||||
struct resource *r = &cs5535_mfd_resources[bar];
|
||||
|
||||
r->flags = IORESOURCE_IO;
|
||||
r->start = pci_resource_start(pdev, bar);
|
||||
r->end = pci_resource_end(pdev, bar);
|
||||
|
||||
/* id is used for temporarily storing BAR; unset it now */
|
||||
cs5535_mfd_cells[i].id = 0;
|
||||
}
|
||||
|
||||
err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
|
||||
ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%zu devices registered.\n",
|
||||
ARRAY_SIZE(cs5535_mfd_cells));
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable:
|
||||
pci_disable_device(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
|
||||
{
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static struct pci_device_id cs5535_mfd_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, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
|
||||
|
||||
static struct pci_driver cs5535_mfd_drv = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cs5535_mfd_pci_tbl,
|
||||
.probe = cs5535_mfd_probe,
|
||||
.remove = __devexit_p(cs5535_mfd_remove),
|
||||
};
|
||||
|
||||
static int __init cs5535_mfd_init(void)
|
||||
{
|
||||
return pci_register_driver(&cs5535_mfd_drv);
|
||||
}
|
||||
|
||||
static void __exit cs5535_mfd_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5535_mfd_drv);
|
||||
}
|
||||
|
||||
module_init(cs5535_mfd_init);
|
||||
module_exit(cs5535_mfd_exit);
|
||||
|
||||
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
|
||||
MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
|
||||
MODULE_LICENSE("GPL");
|
@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcap_to_irq);
|
||||
|
||||
static void pcap_mask_irq(unsigned int irq)
|
||||
static void pcap_mask_irq(struct irq_data *d)
|
||||
{
|
||||
struct pcap_chip *pcap = get_irq_chip_data(irq);
|
||||
struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pcap->msr |= 1 << irq_to_pcap(pcap, irq);
|
||||
pcap->msr |= 1 << irq_to_pcap(pcap, d->irq);
|
||||
queue_work(pcap->workqueue, &pcap->msr_work);
|
||||
}
|
||||
|
||||
static void pcap_unmask_irq(unsigned int irq)
|
||||
static void pcap_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
struct pcap_chip *pcap = get_irq_chip_data(irq);
|
||||
struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
|
||||
pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq));
|
||||
queue_work(pcap->workqueue, &pcap->msr_work);
|
||||
}
|
||||
|
||||
static struct irq_chip pcap_irq_chip = {
|
||||
.name = "pcap",
|
||||
.mask = pcap_mask_irq,
|
||||
.unmask = pcap_unmask_irq,
|
||||
.name = "pcap",
|
||||
.irq_mask = pcap_mask_irq,
|
||||
.irq_unmask = pcap_unmask_irq,
|
||||
};
|
||||
|
||||
static void pcap_msr_work(struct work_struct *work)
|
||||
@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work)
|
||||
if (service & 1) {
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (WARN(!desc, KERN_WARNING
|
||||
"Invalid PCAP IRQ %d\n", irq))
|
||||
if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq))
|
||||
break;
|
||||
|
||||
if (desc->status & IRQ_DISABLED)
|
||||
@ -218,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct pcap_chip *pcap = get_irq_data(irq);
|
||||
|
||||
desc->chip->ack(irq);
|
||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
||||
queue_work(pcap->workqueue, &pcap->isr_work);
|
||||
return;
|
||||
}
|
||||
@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
|
||||
mutex_lock(&pcap->adc_mutex);
|
||||
req = pcap->adc_queue[pcap->adc_head];
|
||||
|
||||
if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
|
||||
if (WARN(!req, "adc irq without pending request\n")) {
|
||||
mutex_unlock(&pcap->adc_mutex);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei)
|
||||
ei->ack_write, ei->ack_register << ei->bus_shift);
|
||||
}
|
||||
|
||||
static void egpio_ack(unsigned int irq)
|
||||
static void egpio_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
/* There does not appear to be a way to proactively mask interrupts
|
||||
* on the egpio chip itself. So, we simply ignore interrupts that
|
||||
* aren't desired. */
|
||||
static void egpio_mask(unsigned int irq)
|
||||
static void egpio_mask(struct irq_data *data)
|
||||
{
|
||||
struct egpio_info *ei = get_irq_chip_data(irq);
|
||||
ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
|
||||
pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
|
||||
struct egpio_info *ei = irq_data_get_irq_chip_data(data);
|
||||
ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
|
||||
pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
|
||||
}
|
||||
static void egpio_unmask(unsigned int irq)
|
||||
|
||||
static void egpio_unmask(struct irq_data *data)
|
||||
{
|
||||
struct egpio_info *ei = get_irq_chip_data(irq);
|
||||
ei->irqs_enabled |= 1 << (irq - ei->irq_start);
|
||||
pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
|
||||
struct egpio_info *ei = irq_data_get_irq_chip_data(data);
|
||||
ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
|
||||
pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
|
||||
}
|
||||
|
||||
static struct irq_chip egpio_muxed_chip = {
|
||||
.name = "htc-egpio",
|
||||
.ack = egpio_ack,
|
||||
.mask = egpio_mask,
|
||||
.unmask = egpio_unmask,
|
||||
.name = "htc-egpio",
|
||||
.irq_ack = egpio_ack,
|
||||
.irq_mask = egpio_mask,
|
||||
.irq_unmask = egpio_unmask,
|
||||
};
|
||||
|
||||
static void egpio_handler(unsigned int irq, struct irq_desc *desc)
|
||||
|
@ -82,25 +82,25 @@ struct htcpld_data {
|
||||
/* There does not appear to be a way to proactively mask interrupts
|
||||
* on the htcpld chip itself. So, we simply ignore interrupts that
|
||||
* aren't desired. */
|
||||
static void htcpld_mask(unsigned int irq)
|
||||
static void htcpld_mask(struct irq_data *data)
|
||||
{
|
||||
struct htcpld_chip *chip = get_irq_chip_data(irq);
|
||||
chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
|
||||
pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
|
||||
struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start));
|
||||
pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled);
|
||||
}
|
||||
static void htcpld_unmask(unsigned int irq)
|
||||
static void htcpld_unmask(struct irq_data *data)
|
||||
{
|
||||
struct htcpld_chip *chip = get_irq_chip_data(irq);
|
||||
chip->irqs_enabled |= 1 << (irq - chip->irq_start);
|
||||
pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
|
||||
struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
chip->irqs_enabled |= 1 << (data->irq - chip->irq_start);
|
||||
pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled);
|
||||
}
|
||||
|
||||
static int htcpld_set_type(unsigned int irq, unsigned int flags)
|
||||
static int htcpld_set_type(struct irq_data *data, unsigned int flags)
|
||||
{
|
||||
struct irq_desc *d = irq_to_desc(irq);
|
||||
struct irq_desc *d = irq_to_desc(data->irq);
|
||||
|
||||
if (!d) {
|
||||
pr_err("HTCPLD invalid IRQ: %d\n", irq);
|
||||
pr_err("HTCPLD invalid IRQ: %d\n", data->irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags)
|
||||
}
|
||||
|
||||
static struct irq_chip htcpld_muxed_chip = {
|
||||
.name = "htcpld",
|
||||
.mask = htcpld_mask,
|
||||
.unmask = htcpld_unmask,
|
||||
.set_type = htcpld_set_type,
|
||||
.name = "htcpld",
|
||||
.irq_mask = htcpld_mask,
|
||||
.irq_unmask = htcpld_unmask,
|
||||
.irq_set_type = htcpld_set_type,
|
||||
};
|
||||
|
||||
/* To properly dispatch IRQ events, we need to read from the
|
||||
@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
|
||||
* and that work is scheduled in the set routine. The kernel can then run
|
||||
* the I2C functions, which will sleep, in process context.
|
||||
*/
|
||||
void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct htcpld_chip *chip_data;
|
||||
@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
schedule_work(&(chip_data->set_val_work));
|
||||
}
|
||||
|
||||
void htcpld_chip_set_ni(struct work_struct *work)
|
||||
static void htcpld_chip_set_ni(struct work_struct *work)
|
||||
{
|
||||
struct htcpld_chip *chip_data;
|
||||
struct i2c_client *client;
|
||||
@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work)
|
||||
i2c_smbus_read_byte_data(client, chip_data->cache_out);
|
||||
}
|
||||
|
||||
int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
|
||||
static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct htcpld_chip *chip_data;
|
||||
int val = 0;
|
||||
@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
|
||||
return (offset < chip->ngpio) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct htcpld_chip *chip_data;
|
||||
|
||||
@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void htcpld_chip_reset(struct i2c_client *client)
|
||||
static void htcpld_chip_reset(struct i2c_client *client)
|
||||
{
|
||||
struct htcpld_chip *chip_data = i2c_get_clientdata(client);
|
||||
if (!chip_data)
|
||||
|
@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
}
|
||||
|
||||
static void jz4740_adc_irq_mask(unsigned int irq)
|
||||
static void jz4740_adc_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct jz4740_adc *adc = get_irq_chip_data(irq);
|
||||
jz4740_adc_irq_set_masked(adc, irq, true);
|
||||
struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
|
||||
jz4740_adc_irq_set_masked(adc, data->irq, true);
|
||||
}
|
||||
|
||||
static void jz4740_adc_irq_unmask(unsigned int irq)
|
||||
static void jz4740_adc_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct jz4740_adc *adc = get_irq_chip_data(irq);
|
||||
jz4740_adc_irq_set_masked(adc, irq, false);
|
||||
struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
|
||||
jz4740_adc_irq_set_masked(adc, data->irq, false);
|
||||
}
|
||||
|
||||
static void jz4740_adc_irq_ack(unsigned int irq)
|
||||
static void jz4740_adc_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct jz4740_adc *adc = get_irq_chip_data(irq);
|
||||
|
||||
irq -= adc->irq_base;
|
||||
struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
|
||||
unsigned int irq = data->irq - adc->irq_base;
|
||||
writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
|
||||
}
|
||||
|
||||
static struct irq_chip jz4740_adc_irq_chip = {
|
||||
.name = "jz4740-adc",
|
||||
.mask = jz4740_adc_irq_mask,
|
||||
.unmask = jz4740_adc_irq_unmask,
|
||||
.ack = jz4740_adc_irq_ack,
|
||||
.irq_mask = jz4740_adc_irq_mask,
|
||||
.irq_unmask = jz4740_adc_irq_unmask,
|
||||
.irq_ack = jz4740_adc_irq_ack,
|
||||
};
|
||||
|
||||
static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
|
||||
|
@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void max8925_irq_lock(unsigned int irq)
|
||||
static void max8925_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct max8925_chip *chip = get_irq_chip_data(irq);
|
||||
struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&chip->irq_lock);
|
||||
}
|
||||
|
||||
static void max8925_irq_sync_unlock(unsigned int irq)
|
||||
static void max8925_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct max8925_chip *chip = get_irq_chip_data(irq);
|
||||
struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct max8925_irq_data *irq_data;
|
||||
static unsigned char cache_chg[2] = {0xff, 0xff};
|
||||
static unsigned char cache_on[2] = {0xff, 0xff};
|
||||
@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&chip->irq_lock);
|
||||
}
|
||||
|
||||
static void max8925_irq_enable(unsigned int irq)
|
||||
static void max8925_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct max8925_chip *chip = get_irq_chip_data(irq);
|
||||
max8925_irqs[irq - chip->irq_base].enable
|
||||
= max8925_irqs[irq - chip->irq_base].offs;
|
||||
struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
max8925_irqs[data->irq - chip->irq_base].enable
|
||||
= max8925_irqs[data->irq - chip->irq_base].offs;
|
||||
}
|
||||
|
||||
static void max8925_irq_disable(unsigned int irq)
|
||||
static void max8925_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct max8925_chip *chip = get_irq_chip_data(irq);
|
||||
max8925_irqs[irq - chip->irq_base].enable = 0;
|
||||
struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
max8925_irqs[data->irq - chip->irq_base].enable = 0;
|
||||
}
|
||||
|
||||
static struct irq_chip max8925_irq_chip = {
|
||||
.name = "max8925",
|
||||
.bus_lock = max8925_irq_lock,
|
||||
.bus_sync_unlock = max8925_irq_sync_unlock,
|
||||
.enable = max8925_irq_enable,
|
||||
.disable = max8925_irq_disable,
|
||||
.irq_bus_lock = max8925_irq_lock,
|
||||
.irq_bus_sync_unlock = max8925_irq_sync_unlock,
|
||||
.irq_enable = max8925_irq_enable,
|
||||
.irq_disable = max8925_irq_disable,
|
||||
};
|
||||
|
||||
static int max8925_irq_init(struct max8925_chip *chip, int irq,
|
||||
|
@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
|
||||
return &max8998_irqs[irq - max8998->irq_base];
|
||||
}
|
||||
|
||||
static void max8998_irq_lock(unsigned int irq)
|
||||
static void max8998_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct max8998_dev *max8998 = get_irq_chip_data(irq);
|
||||
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&max8998->irqlock);
|
||||
}
|
||||
|
||||
static void max8998_irq_sync_unlock(unsigned int irq)
|
||||
static void max8998_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct max8998_dev *max8998 = get_irq_chip_data(irq);
|
||||
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
|
||||
@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&max8998->irqlock);
|
||||
}
|
||||
|
||||
static void max8998_irq_unmask(unsigned int irq)
|
||||
static void max8998_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct max8998_dev *max8998 = get_irq_chip_data(irq);
|
||||
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
|
||||
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
|
||||
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
|
||||
data->irq);
|
||||
|
||||
max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void max8998_irq_mask(unsigned int irq)
|
||||
static void max8998_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct max8998_dev *max8998 = get_irq_chip_data(irq);
|
||||
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
|
||||
struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
|
||||
struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
|
||||
data->irq);
|
||||
|
||||
max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip max8998_irq_chip = {
|
||||
.name = "max8998",
|
||||
.bus_lock = max8998_irq_lock,
|
||||
.bus_sync_unlock = max8998_irq_sync_unlock,
|
||||
.mask = max8998_irq_mask,
|
||||
.unmask = max8998_irq_unmask,
|
||||
.irq_bus_lock = max8998_irq_lock,
|
||||
.irq_bus_sync_unlock = max8998_irq_sync_unlock,
|
||||
.irq_mask = max8998_irq_mask,
|
||||
.irq_unmask = max8998_irq_unmask,
|
||||
};
|
||||
|
||||
static irqreturn_t max8998_irq_thread(int irq, void *data)
|
||||
@ -181,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int max8998_irq_resume(struct max8998_dev *max8998)
|
||||
{
|
||||
if (max8998->irq && max8998->irq_base)
|
||||
max8998_irq_thread(max8998->irq_base, max8998);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max8998_irq_init(struct max8998_dev *max8998)
|
||||
{
|
||||
int i;
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max8998.h>
|
||||
@ -40,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell lp3974_devs[] = {
|
||||
{
|
||||
.name = "lp3974-pmic",
|
||||
}, {
|
||||
.name = "lp3974-rtc",
|
||||
},
|
||||
};
|
||||
|
||||
int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
|
||||
{
|
||||
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
|
||||
@ -135,6 +145,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
|
||||
if (pdata) {
|
||||
max8998->ono = pdata->ono;
|
||||
max8998->irq_base = pdata->irq_base;
|
||||
max8998->wakeup = pdata->wakeup;
|
||||
}
|
||||
mutex_init(&max8998->iolock);
|
||||
|
||||
@ -143,9 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
max8998_irq_init(max8998);
|
||||
|
||||
ret = mfd_add_devices(max8998->dev, -1,
|
||||
max8998_devs, ARRAY_SIZE(max8998_devs),
|
||||
NULL, 0);
|
||||
pm_runtime_set_active(max8998->dev);
|
||||
|
||||
switch (id->driver_data) {
|
||||
case TYPE_LP3974:
|
||||
ret = mfd_add_devices(max8998->dev, -1,
|
||||
lp3974_devs, ARRAY_SIZE(lp3974_devs),
|
||||
NULL, 0);
|
||||
break;
|
||||
case TYPE_MAX8998:
|
||||
ret = mfd_add_devices(max8998->dev, -1,
|
||||
max8998_devs, ARRAY_SIZE(max8998_devs),
|
||||
NULL, 0);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@ -178,10 +203,113 @@ static const struct i2c_device_id max8998_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
|
||||
|
||||
static int max8998_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (max8998->wakeup)
|
||||
set_irq_wake(max8998->irq, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max8998_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (max8998->wakeup)
|
||||
set_irq_wake(max8998->irq, 0);
|
||||
/*
|
||||
* In LP3974, if IRQ registers are not "read & clear"
|
||||
* when it's set during sleep, the interrupt becomes
|
||||
* disabled.
|
||||
*/
|
||||
return max8998_irq_resume(i2c_get_clientdata(i2c));
|
||||
}
|
||||
|
||||
struct max8998_reg_dump {
|
||||
u8 addr;
|
||||
u8 val;
|
||||
};
|
||||
#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, }
|
||||
struct max8998_reg_dump max8998_dump[] = {
|
||||
SAVE_ITEM(MAX8998_REG_IRQM1),
|
||||
SAVE_ITEM(MAX8998_REG_IRQM2),
|
||||
SAVE_ITEM(MAX8998_REG_IRQM3),
|
||||
SAVE_ITEM(MAX8998_REG_IRQM4),
|
||||
SAVE_ITEM(MAX8998_REG_STATUSM1),
|
||||
SAVE_ITEM(MAX8998_REG_STATUSM2),
|
||||
SAVE_ITEM(MAX8998_REG_CHGR1),
|
||||
SAVE_ITEM(MAX8998_REG_CHGR2),
|
||||
SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
|
||||
SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3),
|
||||
SAVE_ITEM(MAX8998_REG_ONOFF1),
|
||||
SAVE_ITEM(MAX8998_REG_ONOFF2),
|
||||
SAVE_ITEM(MAX8998_REG_ONOFF3),
|
||||
SAVE_ITEM(MAX8998_REG_ONOFF4),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1),
|
||||
SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2),
|
||||
SAVE_ITEM(MAX8998_REG_LDO2_LDO3),
|
||||
SAVE_ITEM(MAX8998_REG_LDO4),
|
||||
SAVE_ITEM(MAX8998_REG_LDO5),
|
||||
SAVE_ITEM(MAX8998_REG_LDO6),
|
||||
SAVE_ITEM(MAX8998_REG_LDO7),
|
||||
SAVE_ITEM(MAX8998_REG_LDO8_LDO9),
|
||||
SAVE_ITEM(MAX8998_REG_LDO10_LDO11),
|
||||
SAVE_ITEM(MAX8998_REG_LDO12),
|
||||
SAVE_ITEM(MAX8998_REG_LDO13),
|
||||
SAVE_ITEM(MAX8998_REG_LDO14),
|
||||
SAVE_ITEM(MAX8998_REG_LDO15),
|
||||
SAVE_ITEM(MAX8998_REG_LDO16),
|
||||
SAVE_ITEM(MAX8998_REG_LDO17),
|
||||
SAVE_ITEM(MAX8998_REG_BKCHR),
|
||||
SAVE_ITEM(MAX8998_REG_LBCNFG1),
|
||||
SAVE_ITEM(MAX8998_REG_LBCNFG2),
|
||||
};
|
||||
/* Save registers before hibernation */
|
||||
static int max8998_freeze(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
|
||||
max8998_read_reg(i2c, max8998_dump[i].addr,
|
||||
&max8998_dump[i].val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore registers after hibernation */
|
||||
static int max8998_restore(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
|
||||
max8998_write_reg(i2c, max8998_dump[i].addr,
|
||||
max8998_dump[i].val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops max8998_pm = {
|
||||
.suspend = max8998_suspend,
|
||||
.resume = max8998_resume,
|
||||
.freeze = max8998_freeze,
|
||||
.restore = max8998_restore,
|
||||
};
|
||||
|
||||
static struct i2c_driver max8998_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max8998",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max8998_pm,
|
||||
},
|
||||
.probe = max8998_i2c_probe,
|
||||
.remove = max8998_i2c_remove,
|
||||
|
@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi)
|
||||
if (ret) {
|
||||
err_mask:
|
||||
err_revision:
|
||||
mutex_unlock(&mc13xxx->lock);
|
||||
mc13xxx_unlock(mc13xxx);
|
||||
dev_set_drvdata(&spi->dev, NULL);
|
||||
kfree(mc13xxx);
|
||||
return ret;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static int mfd_add_device(struct device *parent, int id,
|
||||
@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
if (ret)
|
||||
goto fail_res;
|
||||
|
||||
if (cell->pm_runtime_no_callbacks)
|
||||
pm_runtime_no_callbacks(&pdev->dev);
|
||||
|
||||
kfree(res);
|
||||
|
||||
return 0;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/sm501-regs.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
struct sm501_device {
|
||||
struct list_head list;
|
||||
@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm,
|
||||
int ret;
|
||||
|
||||
for (ptr = 0; ptr < pdev->num_resources; ptr++) {
|
||||
printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
|
||||
pdev->name, ptr,
|
||||
pdev->resource[ptr].flags,
|
||||
(unsigned long long)pdev->resource[ptr].start,
|
||||
(unsigned long long)pdev->resource[ptr].end);
|
||||
printk(KERN_DEBUG "%s[%d] %pR\n",
|
||||
pdev->name, ptr, &pdev->resource[ptr]);
|
||||
}
|
||||
|
||||
ret = platform_device_register(pdev);
|
||||
|
@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void stmpe_irq_lock(unsigned int irq)
|
||||
static void stmpe_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct stmpe *stmpe = get_irq_chip_data(irq);
|
||||
struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&stmpe->irq_lock);
|
||||
}
|
||||
|
||||
static void stmpe_irq_sync_unlock(unsigned int irq)
|
||||
static void stmpe_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct stmpe *stmpe = get_irq_chip_data(irq);
|
||||
struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
|
||||
struct stmpe_variant_info *variant = stmpe->variant;
|
||||
int num = DIV_ROUND_UP(variant->num_irqs, 8);
|
||||
int i;
|
||||
@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&stmpe->irq_lock);
|
||||
}
|
||||
|
||||
static void stmpe_irq_mask(unsigned int irq)
|
||||
static void stmpe_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct stmpe *stmpe = get_irq_chip_data(irq);
|
||||
int offset = irq - stmpe->irq_base;
|
||||
struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
|
||||
int offset = data->irq - stmpe->irq_base;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
stmpe->ier[regoffset] &= ~mask;
|
||||
}
|
||||
|
||||
static void stmpe_irq_unmask(unsigned int irq)
|
||||
static void stmpe_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct stmpe *stmpe = get_irq_chip_data(irq);
|
||||
int offset = irq - stmpe->irq_base;
|
||||
struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
|
||||
int offset = data->irq - stmpe->irq_base;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
||||
@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq)
|
||||
|
||||
static struct irq_chip stmpe_irq_chip = {
|
||||
.name = "stmpe",
|
||||
.bus_lock = stmpe_irq_lock,
|
||||
.bus_sync_unlock = stmpe_irq_sync_unlock,
|
||||
.mask = stmpe_irq_mask,
|
||||
.unmask = stmpe_irq_unmask,
|
||||
.irq_bus_lock = stmpe_irq_lock,
|
||||
.irq_bus_sync_unlock = stmpe_irq_sync_unlock,
|
||||
.irq_mask = stmpe_irq_mask,
|
||||
.irq_unmask = stmpe_irq_unmask,
|
||||
};
|
||||
|
||||
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
|
||||
|
@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
|
||||
generic_handle_irq(irq_base + i);
|
||||
}
|
||||
|
||||
static void t7l66xb_irq_mask(unsigned int irq)
|
||||
static void t7l66xb_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
|
||||
struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u8 imr;
|
||||
|
||||
spin_lock_irqsave(&t7l66xb->lock, flags);
|
||||
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
|
||||
imr |= 1 << (irq - t7l66xb->irq_base);
|
||||
imr |= 1 << (data->irq - t7l66xb->irq_base);
|
||||
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
|
||||
spin_unlock_irqrestore(&t7l66xb->lock, flags);
|
||||
}
|
||||
|
||||
static void t7l66xb_irq_unmask(unsigned int irq)
|
||||
static void t7l66xb_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
|
||||
struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u8 imr;
|
||||
|
||||
spin_lock_irqsave(&t7l66xb->lock, flags);
|
||||
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
|
||||
imr &= ~(1 << (irq - t7l66xb->irq_base));
|
||||
imr &= ~(1 << (data->irq - t7l66xb->irq_base));
|
||||
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
|
||||
spin_unlock_irqrestore(&t7l66xb->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip t7l66xb_chip = {
|
||||
.name = "t7l66xb",
|
||||
.ack = t7l66xb_irq_mask,
|
||||
.mask = t7l66xb_irq_mask,
|
||||
.unmask = t7l66xb_irq_unmask,
|
||||
.name = "t7l66xb",
|
||||
.irq_ack = t7l66xb_irq_mask,
|
||||
.irq_mask = t7l66xb_irq_mask,
|
||||
.irq_unmask = t7l66xb_irq_unmask,
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
|
||||
}
|
||||
}
|
||||
|
||||
static void tc6393xb_irq_ack(unsigned int irq)
|
||||
static void tc6393xb_irq_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void tc6393xb_irq_mask(unsigned int irq)
|
||||
static void tc6393xb_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
|
||||
struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u8 imr;
|
||||
|
||||
spin_lock_irqsave(&tc6393xb->lock, flags);
|
||||
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
|
||||
imr |= 1 << (irq - tc6393xb->irq_base);
|
||||
imr |= 1 << (data->irq - tc6393xb->irq_base);
|
||||
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
|
||||
spin_unlock_irqrestore(&tc6393xb->lock, flags);
|
||||
}
|
||||
|
||||
static void tc6393xb_irq_unmask(unsigned int irq)
|
||||
static void tc6393xb_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
|
||||
struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u8 imr;
|
||||
|
||||
spin_lock_irqsave(&tc6393xb->lock, flags);
|
||||
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
|
||||
imr &= ~(1 << (irq - tc6393xb->irq_base));
|
||||
imr &= ~(1 << (data->irq - tc6393xb->irq_base));
|
||||
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
|
||||
spin_unlock_irqrestore(&tc6393xb->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip tc6393xb_chip = {
|
||||
.name = "tc6393xb",
|
||||
.ack = tc6393xb_irq_ack,
|
||||
.mask = tc6393xb_irq_mask,
|
||||
.unmask = tc6393xb_irq_unmask,
|
||||
.name = "tc6393xb",
|
||||
.irq_ack = tc6393xb_irq_ack,
|
||||
.irq_mask = tc6393xb_irq_mask,
|
||||
.irq_unmask = tc6393xb_irq_unmask,
|
||||
};
|
||||
|
||||
static void tc6393xb_attach_irq(struct platform_device *dev)
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#include <linux/i2c/tps65010.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -46,8 +46,6 @@
|
||||
|
||||
/* device id */
|
||||
#define TPS6586X_VERSIONCRC 0xcd
|
||||
#define TPS658621A_VERSIONCRC 0x15
|
||||
#define TPS658621C_VERSIONCRC 0x2c
|
||||
|
||||
struct tps6586x_irq_data {
|
||||
u8 mask_reg;
|
||||
@ -325,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
|
||||
return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
|
||||
}
|
||||
|
||||
static void tps6586x_irq_lock(unsigned int irq)
|
||||
static void tps6586x_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct tps6586x *tps6586x = get_irq_chip_data(irq);
|
||||
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&tps6586x->irq_lock);
|
||||
}
|
||||
|
||||
static void tps6586x_irq_enable(unsigned int irq)
|
||||
static void tps6586x_irq_enable(struct irq_data *irq_data)
|
||||
{
|
||||
struct tps6586x *tps6586x = get_irq_chip_data(irq);
|
||||
unsigned int __irq = irq - tps6586x->irq_base;
|
||||
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
|
||||
unsigned int __irq = irq_data->irq - tps6586x->irq_base;
|
||||
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
|
||||
|
||||
tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
|
||||
tps6586x->irq_en |= (1 << __irq);
|
||||
}
|
||||
|
||||
static void tps6586x_irq_disable(unsigned int irq)
|
||||
static void tps6586x_irq_disable(struct irq_data *irq_data)
|
||||
{
|
||||
struct tps6586x *tps6586x = get_irq_chip_data(irq);
|
||||
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
unsigned int __irq = irq - tps6586x->irq_base;
|
||||
unsigned int __irq = irq_data->irq - tps6586x->irq_base;
|
||||
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
|
||||
|
||||
tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
|
||||
tps6586x->irq_en &= ~(1 << __irq);
|
||||
}
|
||||
|
||||
static void tps6586x_irq_sync_unlock(unsigned int irq)
|
||||
static void tps6586x_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct tps6586x *tps6586x = get_irq_chip_data(irq);
|
||||
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
|
||||
@ -421,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
|
||||
tps6586x->irq_base = irq_base;
|
||||
|
||||
tps6586x->irq_chip.name = "tps6586x";
|
||||
tps6586x->irq_chip.enable = tps6586x_irq_enable;
|
||||
tps6586x->irq_chip.disable = tps6586x_irq_disable;
|
||||
tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
|
||||
tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
|
||||
tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
|
||||
tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
|
||||
tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
|
||||
tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
|
||||
int __irq = i + tps6586x->irq_base;
|
||||
@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((ret != TPS658621A_VERSIONCRC) &&
|
||||
(ret != TPS658621C_VERSIONCRC)) {
|
||||
dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
|
||||
|
||||
tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
|
||||
if (tps6586x == NULL)
|
||||
|
@ -1003,7 +1003,7 @@ static int twl_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
|
||||
static int __init
|
||||
static int __devinit
|
||||
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
int status;
|
||||
|
@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work)
|
||||
* completion, potentially including some re-ordering, of these requests.
|
||||
*/
|
||||
|
||||
static void twl4030_sih_mask(unsigned irq)
|
||||
static void twl4030_sih_mask(struct irq_data *data)
|
||||
{
|
||||
struct sih_agent *sih = get_irq_chip_data(irq);
|
||||
struct sih_agent *sih = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sih_agent_lock, flags);
|
||||
sih->imr |= BIT(irq - sih->irq_base);
|
||||
sih->imr |= BIT(data->irq - sih->irq_base);
|
||||
sih->imr_change_pending = true;
|
||||
queue_work(wq, &sih->mask_work);
|
||||
spin_unlock_irqrestore(&sih_agent_lock, flags);
|
||||
}
|
||||
|
||||
static void twl4030_sih_unmask(unsigned irq)
|
||||
static void twl4030_sih_unmask(struct irq_data *data)
|
||||
{
|
||||
struct sih_agent *sih = get_irq_chip_data(irq);
|
||||
struct sih_agent *sih = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sih_agent_lock, flags);
|
||||
sih->imr &= ~BIT(irq - sih->irq_base);
|
||||
sih->imr &= ~BIT(data->irq - sih->irq_base);
|
||||
sih->imr_change_pending = true;
|
||||
queue_work(wq, &sih->mask_work);
|
||||
spin_unlock_irqrestore(&sih_agent_lock, flags);
|
||||
}
|
||||
|
||||
static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
|
||||
static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
|
||||
{
|
||||
struct sih_agent *sih = get_irq_chip_data(irq);
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct sih_agent *sih = irq_data_get_irq_chip_data(data);
|
||||
struct irq_desc *desc = irq_to_desc(data->irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (!desc) {
|
||||
pr_err("twl4030: Invalid IRQ: %d\n", irq);
|
||||
pr_err("twl4030: Invalid IRQ: %d\n", data->irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
|
||||
if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
|
||||
desc->status &= ~IRQ_TYPE_SENSE_MASK;
|
||||
desc->status |= trigger;
|
||||
sih->edge_change |= BIT(irq - sih->irq_base);
|
||||
sih->edge_change |= BIT(data->irq - sih->irq_base);
|
||||
queue_work(wq, &sih->edge_work);
|
||||
}
|
||||
spin_unlock_irqrestore(&sih_agent_lock, flags);
|
||||
@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
|
||||
|
||||
static struct irq_chip twl4030_sih_irq_chip = {
|
||||
.name = "twl4030",
|
||||
.mask = twl4030_sih_mask,
|
||||
.unmask = twl4030_sih_unmask,
|
||||
.set_type = twl4030_sih_set_type,
|
||||
.irq_mask = twl4030_sih_mask,
|
||||
.irq_unmask = twl4030_sih_unmask,
|
||||
.irq_set_type = twl4030_sih_set_type,
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -332,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
||||
*/
|
||||
twl6030_irq_chip = dummy_irq_chip;
|
||||
twl6030_irq_chip.name = "twl6030";
|
||||
twl6030_irq_chip.set_type = NULL;
|
||||
twl6030_irq_chip.irq_set_type = NULL;
|
||||
|
||||
for (i = irq_base; i < irq_end; i++) {
|
||||
set_irq_chip_and_handler(i, &twl6030_irq_chip,
|
||||
|
@ -112,7 +112,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vx855_remove(struct pci_dev *pdev)
|
||||
static void __devexit vx855_remove(struct pci_dev *pdev)
|
||||
{
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pci_disable_device(pdev);
|
||||
|
@ -1541,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
|
||||
dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
|
||||
break;
|
||||
|
||||
case WM8326:
|
||||
parent = WM8326;
|
||||
wm831x->num_gpio = 12;
|
||||
dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
|
||||
ret = -EINVAL;
|
||||
@ -1610,18 +1616,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
|
||||
break;
|
||||
|
||||
case WM8320:
|
||||
ret = mfd_add_devices(wm831x->dev, -1,
|
||||
wm8320_devs, ARRAY_SIZE(wm8320_devs),
|
||||
NULL, 0);
|
||||
break;
|
||||
|
||||
case WM8321:
|
||||
ret = mfd_add_devices(wm831x->dev, -1,
|
||||
wm8320_devs, ARRAY_SIZE(wm8320_devs),
|
||||
NULL, 0);
|
||||
break;
|
||||
|
||||
case WM8325:
|
||||
case WM8326:
|
||||
ret = mfd_add_devices(wm831x->dev, -1,
|
||||
wm8320_devs, ARRAY_SIZE(wm8320_devs),
|
||||
NULL, wm831x->irq_base);
|
||||
|
@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
|
||||
static int wm831x_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct wm831x *wm831x = i2c_get_clientdata(i2c);
|
||||
struct wm831x *wm831x = dev_get_drvdata(dev);
|
||||
|
||||
return wm831x_device_suspend(wm831x);
|
||||
}
|
||||
@ -108,19 +108,23 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
|
||||
{ "wm8320", WM8320 },
|
||||
{ "wm8321", WM8321 },
|
||||
{ "wm8325", WM8325 },
|
||||
{ "wm8326", WM8326 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
|
||||
|
||||
static const struct dev_pm_ops wm831x_pm_ops = {
|
||||
.suspend = wm831x_i2c_suspend,
|
||||
};
|
||||
|
||||
static struct i2c_driver wm831x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm831x",
|
||||
.owner = THIS_MODULE,
|
||||
.name = "wm831x",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm831x_pm_ops,
|
||||
},
|
||||
.probe = wm831x_i2c_probe,
|
||||
.remove = wm831x_i2c_remove,
|
||||
.suspend = wm831x_i2c_suspend,
|
||||
.id_table = wm831x_i2c_id,
|
||||
};
|
||||
|
||||
|
@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
|
||||
return &wm831x_irqs[irq - wm831x->irq_base];
|
||||
}
|
||||
|
||||
static void wm831x_irq_lock(unsigned int irq)
|
||||
static void wm831x_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = get_irq_chip_data(irq);
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&wm831x->irq_lock);
|
||||
}
|
||||
|
||||
static void wm831x_irq_sync_unlock(unsigned int irq)
|
||||
static void wm831x_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = get_irq_chip_data(irq);
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
|
||||
@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&wm831x->irq_lock);
|
||||
}
|
||||
|
||||
static void wm831x_irq_unmask(unsigned int irq)
|
||||
static void wm831x_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = get_irq_chip_data(irq);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
|
||||
data->irq);
|
||||
|
||||
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm831x_irq_mask(unsigned int irq)
|
||||
static void wm831x_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct wm831x *wm831x = get_irq_chip_data(irq);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
|
||||
data->irq);
|
||||
|
||||
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
|
||||
static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct wm831x *wm831x = get_irq_chip_data(irq);
|
||||
int val;
|
||||
struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
|
||||
int val, irq;
|
||||
|
||||
irq = irq - wm831x->irq_base;
|
||||
irq = data->irq - wm831x->irq_base;
|
||||
|
||||
if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
|
||||
/* Ignore internal-only IRQs */
|
||||
@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
|
||||
}
|
||||
|
||||
static struct irq_chip wm831x_irq_chip = {
|
||||
.name = "wm831x",
|
||||
.bus_lock = wm831x_irq_lock,
|
||||
.bus_sync_unlock = wm831x_irq_sync_unlock,
|
||||
.mask = wm831x_irq_mask,
|
||||
.unmask = wm831x_irq_unmask,
|
||||
.set_type = wm831x_irq_set_type,
|
||||
.name = "wm831x",
|
||||
.irq_bus_lock = wm831x_irq_lock,
|
||||
.irq_bus_sync_unlock = wm831x_irq_sync_unlock,
|
||||
.irq_mask = wm831x_irq_mask,
|
||||
.irq_unmask = wm831x_irq_unmask,
|
||||
.irq_set_type = wm831x_irq_set_type,
|
||||
};
|
||||
|
||||
/* The processing of the primary interrupt occurs in a thread so that
|
||||
@ -515,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to flag /IRQ as a wake source; there are a number of
|
||||
* unconditional wake sources in the PMIC so this isn't
|
||||
* conditional but we don't actually care *too* much if it
|
||||
* fails.
|
||||
*/
|
||||
ret = enable_irq_wake(irq);
|
||||
if (ret != 0) {
|
||||
dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
wm831x->irq = irq;
|
||||
wm831x->irq_base = pdata->irq_base;
|
||||
|
||||
|
@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
|
||||
type = WM8321;
|
||||
else if (strcmp(spi->modalias, "wm8325") == 0)
|
||||
type = WM8325;
|
||||
else if (strcmp(spi->modalias, "wm8326") == 0)
|
||||
type = WM8326;
|
||||
else {
|
||||
dev_err(&spi->dev, "Unknown device type\n");
|
||||
return -EINVAL;
|
||||
@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = {
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static struct spi_driver wm8326_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8326",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm831x_spi_probe,
|
||||
.remove = __devexit_p(wm831x_spi_remove),
|
||||
.suspend = wm831x_spi_suspend,
|
||||
};
|
||||
|
||||
static int __init wm831x_spi_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void)
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
|
||||
|
||||
ret = spi_register_driver(&wm8326_spi_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(wm831x_spi_init);
|
||||
|
||||
static void __exit wm831x_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&wm8326_spi_driver);
|
||||
spi_unregister_driver(&wm8325_spi_driver);
|
||||
spi_unregister_driver(&wm8321_spi_driver);
|
||||
spi_unregister_driver(&wm8320_spi_driver);
|
||||
|
@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void wm8350_irq_lock(unsigned int irq)
|
||||
static void wm8350_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct wm8350 *wm8350 = get_irq_chip_data(irq);
|
||||
struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&wm8350->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8350_irq_sync_unlock(unsigned int irq)
|
||||
static void wm8350_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct wm8350 *wm8350 = get_irq_chip_data(irq);
|
||||
struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
|
||||
@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&wm8350->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8350_irq_enable(unsigned int irq)
|
||||
static void wm8350_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct wm8350 *wm8350 = get_irq_chip_data(irq);
|
||||
struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
|
||||
struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
|
||||
data->irq);
|
||||
|
||||
wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm8350_irq_disable(unsigned int irq)
|
||||
static void wm8350_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct wm8350 *wm8350 = get_irq_chip_data(irq);
|
||||
struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
|
||||
struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
|
||||
data->irq);
|
||||
|
||||
wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip wm8350_irq_chip = {
|
||||
.name = "wm8350",
|
||||
.bus_lock = wm8350_irq_lock,
|
||||
.bus_sync_unlock = wm8350_irq_sync_unlock,
|
||||
.disable = wm8350_irq_disable,
|
||||
.enable = wm8350_irq_enable,
|
||||
.name = "wm8350",
|
||||
.irq_bus_lock = wm8350_irq_lock,
|
||||
.irq_bus_sync_unlock = wm8350_irq_sync_unlock,
|
||||
.irq_disable = wm8350_irq_disable,
|
||||
.irq_enable = wm8350_irq_enable,
|
||||
};
|
||||
|
||||
int wm8350_irq_init(struct wm8350 *wm8350, int irq,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
@ -169,8 +170,16 @@ out:
|
||||
EXPORT_SYMBOL_GPL(wm8994_set_bits);
|
||||
|
||||
static struct mfd_cell wm8994_regulator_devs[] = {
|
||||
{ .name = "wm8994-ldo", .id = 1 },
|
||||
{ .name = "wm8994-ldo", .id = 2 },
|
||||
{
|
||||
.name = "wm8994-ldo",
|
||||
.id = 1,
|
||||
.pm_runtime_no_callbacks = true,
|
||||
},
|
||||
{
|
||||
.name = "wm8994-ldo",
|
||||
.id = 2,
|
||||
.pm_runtime_no_callbacks = true,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource wm8994_codec_resources[] = {
|
||||
@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = {
|
||||
.name = "wm8994-gpio",
|
||||
.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
|
||||
.resources = wm8994_gpio_resources,
|
||||
.pm_runtime_no_callbacks = true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -231,7 +241,7 @@ static const char *wm8958_main_supplies[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm8994_device_suspend(struct device *dev)
|
||||
static int wm8994_suspend(struct device *dev)
|
||||
{
|
||||
struct wm8994 *wm8994 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
@ -261,7 +271,7 @@ static int wm8994_device_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_device_resume(struct device *dev)
|
||||
static int wm8994_resume(struct device *dev)
|
||||
{
|
||||
struct wm8994 *wm8994 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
@ -471,6 +481,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
pm_runtime_enable(wm8994->dev);
|
||||
pm_runtime_resume(wm8994->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
@ -490,6 +503,7 @@ err:
|
||||
|
||||
static void wm8994_device_exit(struct wm8994 *wm8994)
|
||||
{
|
||||
pm_runtime_disable(wm8994->dev);
|
||||
mfd_remove_devices(wm8994->dev);
|
||||
wm8994_irq_exit(wm8994);
|
||||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
@ -573,21 +587,6 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
|
||||
{
|
||||
return wm8994_device_suspend(&i2c->dev);
|
||||
}
|
||||
|
||||
static int wm8994_i2c_resume(struct i2c_client *i2c)
|
||||
{
|
||||
return wm8994_device_resume(&i2c->dev);
|
||||
}
|
||||
#else
|
||||
#define wm8994_i2c_suspend NULL
|
||||
#define wm8994_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id wm8994_i2c_id[] = {
|
||||
{ "wm8994", WM8994 },
|
||||
{ "wm8958", WM8958 },
|
||||
@ -595,15 +594,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
|
||||
|
||||
UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
|
||||
|
||||
static struct i2c_driver wm8994_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8994",
|
||||
.owner = THIS_MODULE,
|
||||
.name = "wm8994",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm8994_pm_ops,
|
||||
},
|
||||
.probe = wm8994_i2c_probe,
|
||||
.remove = wm8994_i2c_remove,
|
||||
.suspend = wm8994_i2c_suspend,
|
||||
.resume = wm8994_i2c_resume,
|
||||
.id_table = wm8994_i2c_id,
|
||||
};
|
||||
|
||||
|
@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
|
||||
return &wm8994_irqs[irq - wm8994->irq_base];
|
||||
}
|
||||
|
||||
static void wm8994_irq_lock(unsigned int irq)
|
||||
static void wm8994_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = get_irq_chip_data(irq);
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&wm8994->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8994_irq_sync_unlock(unsigned int irq)
|
||||
static void wm8994_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = get_irq_chip_data(irq);
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
|
||||
@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq)
|
||||
mutex_unlock(&wm8994->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8994_irq_unmask(unsigned int irq)
|
||||
static void wm8994_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = get_irq_chip_data(irq);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
data->irq);
|
||||
|
||||
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm8994_irq_mask(unsigned int irq)
|
||||
static void wm8994_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = get_irq_chip_data(irq);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
data->irq);
|
||||
|
||||
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip wm8994_irq_chip = {
|
||||
.name = "wm8994",
|
||||
.bus_lock = wm8994_irq_lock,
|
||||
.bus_sync_unlock = wm8994_irq_sync_unlock,
|
||||
.mask = wm8994_irq_mask,
|
||||
.unmask = wm8994_irq_unmask,
|
||||
.name = "wm8994",
|
||||
.irq_bus_lock = wm8994_irq_lock,
|
||||
.irq_bus_sync_unlock = wm8994_irq_sync_unlock,
|
||||
.irq_mask = wm8994_irq_mask,
|
||||
.irq_unmask = wm8994_irq_unmask,
|
||||
};
|
||||
|
||||
/* The processing of the primary interrupt occurs in a thread so that
|
||||
|
@ -64,7 +64,7 @@ config ATMEL_PWM
|
||||
|
||||
config AB8500_PWM
|
||||
bool "AB8500 PWM support"
|
||||
depends on AB8500_CORE
|
||||
depends on AB8500_CORE && ARCH_U8500
|
||||
select HAVE_PWM
|
||||
help
|
||||
This driver exports functions to enable/disble/config/free Pulse
|
||||
|
@ -16,12 +16,11 @@
|
||||
#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);
|
||||
@ -37,7 +36,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;
|
||||
@ -290,10 +289,10 @@ 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 __devinit cs5535_mfgpt_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err, t;
|
||||
struct resource *res;
|
||||
int err = -EIO, t;
|
||||
|
||||
/* 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 +301,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 +329,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_drv = {
|
||||
.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_drv);
|
||||
}
|
||||
|
||||
module_init(cs5535_mfgpt_init);
|
||||
@ -380,3 +348,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);
|
||||
|
@ -424,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->buck_voltage_lock)
|
||||
return -EINVAL;
|
||||
|
||||
/* no predefine regulator found */
|
||||
max8998->buck1_idx = (buck1_last_val % 2) + 2;
|
||||
dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
|
||||
@ -451,18 +454,26 @@ buck1_exit:
|
||||
"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
|
||||
, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
|
||||
if (gpio_is_valid(pdata->buck2_set3)) {
|
||||
if (max8998->buck2_vol[0] == i) {
|
||||
max8998->buck1_idx = 0;
|
||||
buck2_gpio_set(pdata->buck2_set3, 0);
|
||||
} else {
|
||||
max8998->buck1_idx = 1;
|
||||
ret = max8998_get_voltage_register(rdev, ®,
|
||||
&shift,
|
||||
&mask);
|
||||
ret = max8998_write_reg(i2c, reg, i);
|
||||
max8998->buck2_vol[1] = i;
|
||||
buck2_gpio_set(pdata->buck2_set3, 1);
|
||||
|
||||
/* check if requested voltage */
|
||||
/* value is already defined */
|
||||
for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
|
||||
if (max8998->buck2_vol[j] == i) {
|
||||
max8998->buck2_idx = j;
|
||||
buck2_gpio_set(pdata->buck2_set3, j);
|
||||
goto buck2_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->buck_voltage_lock)
|
||||
return -EINVAL;
|
||||
|
||||
max8998_get_voltage_register(rdev,
|
||||
®, &shift, &mask);
|
||||
ret = max8998_write_reg(i2c, reg, i);
|
||||
max8998->buck2_vol[max8998->buck2_idx] = i;
|
||||
buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
|
||||
buck2_exit:
|
||||
dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
|
||||
gpio_get_value(pdata->buck2_set3));
|
||||
} else {
|
||||
@ -707,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, max8998);
|
||||
i2c = max8998->iodev->i2c;
|
||||
|
||||
max8998->buck1_idx = pdata->buck1_default_idx;
|
||||
max8998->buck2_idx = pdata->buck2_default_idx;
|
||||
|
||||
/* NOTE: */
|
||||
/* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */
|
||||
/* will be displayed */
|
||||
@ -739,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
!= (pdata->buck1_max_voltage1 / 1000))
|
||||
< (pdata->buck1_voltage1 / 1000))
|
||||
i++;
|
||||
printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
|
||||
max8998->buck1_vol[0] = i;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set predefined value for BUCK1 register 2 */
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
!= (pdata->buck1_max_voltage2 / 1000))
|
||||
< (pdata->buck1_voltage2 / 1000))
|
||||
i++;
|
||||
|
||||
max8998->buck1_vol[1] = i;
|
||||
printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
|
||||
+ ret;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set predefined value for BUCK1 register 3 */
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
< (pdata->buck1_voltage3 / 1000))
|
||||
i++;
|
||||
|
||||
max8998->buck1_vol[2] = i;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set predefined value for BUCK1 register 4 */
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
< (pdata->buck1_voltage4 / 1000))
|
||||
i++;
|
||||
|
||||
max8998->buck1_vol[3] = i;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -772,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
|
||||
gpio_direction_output(pdata->buck2_set3,
|
||||
max8998->buck2_idx & 0x1);
|
||||
|
||||
/* BUCK2 - set preset default voltage value to buck2_vol[0] */
|
||||
/* BUCK2 register 1 */
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
!= (pdata->buck2_max_voltage / 1000))
|
||||
< (pdata->buck2_voltage1 / 1000))
|
||||
i++;
|
||||
printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
|
||||
max8998->buck2_vol[0] = i;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* BUCK2 register 2 */
|
||||
i = 0;
|
||||
while (buck12_voltage_map_desc.min +
|
||||
buck12_voltage_map_desc.step*i
|
||||
< (pdata->buck2_voltage2 / 1000))
|
||||
i++;
|
||||
printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
|
||||
max8998->buck2_vol[1] = i;
|
||||
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->num_regulators; i++) {
|
||||
@ -835,6 +882,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max8998_pmic_id[] = {
|
||||
{ "max8998-pmic", TYPE_MAX8998 },
|
||||
{ "lp3974-pmic", TYPE_LP3974 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver max8998_pmic_driver = {
|
||||
.driver = {
|
||||
.name = "max8998-pmic",
|
||||
@ -842,6 +895,7 @@ static struct platform_driver max8998_pmic_driver = {
|
||||
},
|
||||
.probe = max8998_pmic_probe,
|
||||
.remove = __devexit_p(max8998_pmic_remove),
|
||||
.id_table = max8998_pmic_id,
|
||||
};
|
||||
|
||||
static int __init max8998_pmic_init(void)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max8998.h>
|
||||
#include <linux/mfd/max8998-private.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MAX8998_RTC_SEC 0x00
|
||||
#define MAX8998_RTC_MIN 0x01
|
||||
@ -73,6 +74,7 @@ struct max8998_rtc_info {
|
||||
struct i2c_client *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
int irq;
|
||||
bool lp3974_bug_workaround;
|
||||
};
|
||||
|
||||
static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
|
||||
@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct max8998_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[8];
|
||||
int ret;
|
||||
|
||||
max8998_tm_to_data(tm, data);
|
||||
|
||||
return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
|
||||
ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
|
||||
{
|
||||
return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
|
||||
int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
|
||||
{
|
||||
return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
|
||||
int ret;
|
||||
u8 alarm0_conf = 0x77;
|
||||
|
||||
/* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
|
||||
if (info->lp3974_bug_workaround)
|
||||
alarm0_conf = 0x57;
|
||||
|
||||
ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (alrm->enabled)
|
||||
return max8998_rtc_start_alarm(info);
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return 0;
|
||||
if (alrm->enabled)
|
||||
ret = max8998_rtc_start_alarm(info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_alarm_irq_enable(struct device *dev,
|
||||
@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
|
||||
static int __devinit max8998_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
|
||||
struct max8998_rtc_info *info;
|
||||
int ret;
|
||||
|
||||
@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
|
||||
"rtc-alarm0", info);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
info->irq, ret);
|
||||
|
||||
dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
|
||||
if (pdata->rtc_delay) {
|
||||
info->lp3974_bug_workaround = true;
|
||||
dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
|
||||
" RTC updates will be extremely slow.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_rtc:
|
||||
@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max8998_rtc_id[] = {
|
||||
{ "max8998-rtc", TYPE_MAX8998 },
|
||||
{ "lp3974-rtc", TYPE_LP3974 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver max8998_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "max8998-rtc",
|
||||
@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
|
||||
},
|
||||
.probe = max8998_rtc_probe,
|
||||
.remove = __devexit_p(max8998_rtc_remove),
|
||||
.id_table = max8998_rtc_id,
|
||||
};
|
||||
|
||||
static int __init max8998_rtc_init(void)
|
||||
|
@ -74,30 +74,37 @@
|
||||
#define AB8500_INT_ACC_DETECT_21DB_F 37
|
||||
#define AB8500_INT_ACC_DETECT_21DB_R 38
|
||||
#define AB8500_INT_GP_SW_ADC_CONV_END 39
|
||||
#define AB8500_INT_BTEMP_LOW 72
|
||||
#define AB8500_INT_BTEMP_LOW_MEDIUM 73
|
||||
#define AB8500_INT_BTEMP_MEDIUM_HIGH 74
|
||||
#define AB8500_INT_BTEMP_HIGH 75
|
||||
#define AB8500_INT_USB_CHARGER_NOT_OK 81
|
||||
#define AB8500_INT_ID_WAKEUP_R 82
|
||||
#define AB8500_INT_ID_DET_R1R 84
|
||||
#define AB8500_INT_ID_DET_R2R 85
|
||||
#define AB8500_INT_ID_DET_R3R 86
|
||||
#define AB8500_INT_ID_DET_R4R 87
|
||||
#define AB8500_INT_ID_WAKEUP_F 88
|
||||
#define AB8500_INT_ID_DET_R1F 90
|
||||
#define AB8500_INT_ID_DET_R2F 91
|
||||
#define AB8500_INT_ID_DET_R3F 92
|
||||
#define AB8500_INT_ID_DET_R4F 93
|
||||
#define AB8500_INT_USB_CHG_DET_DONE 94
|
||||
#define AB8500_INT_USB_CH_TH_PROT_F 96
|
||||
#define AB8500_INT_USB_CH_TH_PROP_R 97
|
||||
#define AB8500_INT_MAIN_CH_TH_PROP_F 98
|
||||
#define AB8500_INT_MAIN_CH_TH_PROT_R 99
|
||||
#define AB8500_INT_USB_CHARGER_NOT_OKF 103
|
||||
#define AB8500_INT_ADP_SOURCE_ERROR 72
|
||||
#define AB8500_INT_ADP_SINK_ERROR 73
|
||||
#define AB8500_INT_ADP_PROBE_PLUG 74
|
||||
#define AB8500_INT_ADP_PROBE_UNPLUG 75
|
||||
#define AB8500_INT_ADP_SENSE_OFF 76
|
||||
#define AB8500_INT_USB_PHY_POWER_ERR 78
|
||||
#define AB8500_INT_USB_LINK_STATUS 79
|
||||
#define AB8500_INT_BTEMP_LOW 80
|
||||
#define AB8500_INT_BTEMP_LOW_MEDIUM 81
|
||||
#define AB8500_INT_BTEMP_MEDIUM_HIGH 82
|
||||
#define AB8500_INT_BTEMP_HIGH 83
|
||||
#define AB8500_INT_USB_CHARGER_NOT_OK 89
|
||||
#define AB8500_INT_ID_WAKEUP_R 90
|
||||
#define AB8500_INT_ID_DET_R1R 92
|
||||
#define AB8500_INT_ID_DET_R2R 93
|
||||
#define AB8500_INT_ID_DET_R3R 94
|
||||
#define AB8500_INT_ID_DET_R4R 95
|
||||
#define AB8500_INT_ID_WAKEUP_F 96
|
||||
#define AB8500_INT_ID_DET_R1F 98
|
||||
#define AB8500_INT_ID_DET_R2F 99
|
||||
#define AB8500_INT_ID_DET_R3F 100
|
||||
#define AB8500_INT_ID_DET_R4F 101
|
||||
#define AB8500_INT_USB_CHG_DET_DONE 102
|
||||
#define AB8500_INT_USB_CH_TH_PROT_F 104
|
||||
#define AB8500_INT_USB_CH_TH_PROT_R 105
|
||||
#define AB8500_INT_MAIN_CH_TH_PROT_F 106
|
||||
#define AB8500_INT_MAIN_CH_TH_PROT_R 107
|
||||
#define AB8500_INT_USB_CHARGER_NOT_OKF 111
|
||||
|
||||
#define AB8500_NR_IRQS 104
|
||||
#define AB8500_NUM_IRQ_REGS 13
|
||||
#define AB8500_NR_IRQS 112
|
||||
#define AB8500_NUM_IRQ_REGS 14
|
||||
|
||||
/**
|
||||
* struct ab8500 - ab8500 internal structure
|
||||
|
@ -47,6 +47,12 @@ struct mfd_cell {
|
||||
|
||||
/* don't check for resource conflicts */
|
||||
bool ignore_resource_conflicts;
|
||||
|
||||
/*
|
||||
* Disable runtime PM callbacks for this subdevice - see
|
||||
* pm_runtime_no_callbacks().
|
||||
*/
|
||||
bool pm_runtime_no_callbacks;
|
||||
};
|
||||
|
||||
extern int mfd_add_devices(struct device *parent, int id,
|
||||
|
@ -159,10 +159,12 @@ struct max8998_dev {
|
||||
u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
|
||||
u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
|
||||
int type;
|
||||
bool wakeup;
|
||||
};
|
||||
|
||||
int max8998_irq_init(struct max8998_dev *max8998);
|
||||
void max8998_irq_exit(struct max8998_dev *max8998);
|
||||
int max8998_irq_resume(struct max8998_dev *max8998);
|
||||
|
||||
extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
|
||||
extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
|
||||
|
@ -70,24 +70,43 @@ struct max8998_regulator_data {
|
||||
* @num_regulators: number of regultors used
|
||||
* @irq_base: base IRQ number for max8998, required for IRQs
|
||||
* @ono: power onoff IRQ number for max8998
|
||||
* @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1
|
||||
* @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2
|
||||
* @buck2_max_voltage: BUCK2 maximum alowed voltage
|
||||
* @buck_voltage_lock: Do NOT change the values of the following six
|
||||
* registers set by buck?_voltage?. The voltage of BUCK1/2 cannot
|
||||
* be other than the preset values.
|
||||
* @buck1_voltage1: BUCK1 DVS mode 1 voltage register
|
||||
* @buck1_voltage2: BUCK1 DVS mode 2 voltage register
|
||||
* @buck1_voltage3: BUCK1 DVS mode 3 voltage register
|
||||
* @buck1_voltage4: BUCK1 DVS mode 4 voltage register
|
||||
* @buck2_voltage1: BUCK2 DVS mode 1 voltage register
|
||||
* @buck2_voltage2: BUCK2 DVS mode 2 voltage register
|
||||
* @buck1_set1: BUCK1 gpio pin 1 to set output voltage
|
||||
* @buck1_set2: BUCK1 gpio pin 2 to set output voltage
|
||||
* @buck1_default_idx: Default for BUCK1 gpio pin 1, 2
|
||||
* @buck2_set3: BUCK2 gpio pin to set output voltage
|
||||
* @buck2_default_idx: Default for BUCK2 gpio pin.
|
||||
* @wakeup: Allow to wake up from suspend
|
||||
* @rtc_delay: LP3974 RTC chip bug that requires delay after a register
|
||||
* write before reading it.
|
||||
*/
|
||||
struct max8998_platform_data {
|
||||
struct max8998_regulator_data *regulators;
|
||||
int num_regulators;
|
||||
int irq_base;
|
||||
int ono;
|
||||
int buck1_max_voltage1;
|
||||
int buck1_max_voltage2;
|
||||
int buck2_max_voltage;
|
||||
bool buck_voltage_lock;
|
||||
int buck1_voltage1;
|
||||
int buck1_voltage2;
|
||||
int buck1_voltage3;
|
||||
int buck1_voltage4;
|
||||
int buck2_voltage1;
|
||||
int buck2_voltage2;
|
||||
int buck1_set1;
|
||||
int buck1_set2;
|
||||
int buck1_default_idx;
|
||||
int buck2_set3;
|
||||
int buck2_default_idx;
|
||||
bool wakeup;
|
||||
bool rtc_delay;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_MAX8998_H */
|
||||
|
@ -245,6 +245,7 @@ enum wm831x_parent {
|
||||
WM8320 = 0x8320,
|
||||
WM8321 = 0x8321,
|
||||
WM8325 = 0x8325,
|
||||
WM8326 = 0x8326,
|
||||
};
|
||||
|
||||
struct wm831x {
|
||||
|
Loading…
Reference in New Issue
Block a user