Commit 17d30ac0 authored by Linus Torvalds's avatar Linus Torvalds

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: (47 commits)
  mfd: Rename twl5031 sih modules
  mfd: Storage class for timberdale should be before const qualifier
  mfd: Remove unneeded and dangerous clearing of clientdata
  mfd: New AB8500 driver
  gpio: Fix inverted rdc321x gpio data out registers
  mfd: Change rdc321x resources flags to IORESOURCE_IO
  mfd: Move pcf50633 irq related functions to its own file.
  mfd: Use threaded irq for pcf50633
  mfd: pcf50633-adc: Fix potential race in pcf50633_adc_sync_read
  mfd: Fix pcf50633 bitfield logic in interrupt handler
  gpio: rdc321x needs to select MFD_CORE
  mfd: Use menuconfig for quicker config editing
  ARM: AB3550 board configuration and irq for U300
  mfd: AB3550 core driver
  mfd: AB3100 register access change to abx500 API
  mfd: Renamed ab3100.h to abx500.h
  gpio: Add TC35892 GPIO driver
  mfd: Add Toshiba's TC35892 MFD core
  mfd: Delay to mask tsc irq in max8925
  mfd: Remove incorrect wm8350 kfree
  ...
parents e38c1e54 191211f5
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/at24.h> #include <linux/i2c/at24.h>
#include <linux/i2c/pca953x.h> #include <linux/i2c/pca953x.h>
#include <linux/mfd/tps6507x.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
...@@ -24,6 +25,8 @@ ...@@ -24,6 +25,8 @@
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/mfd/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
...@@ -533,10 +536,24 @@ struct regulator_init_data tps65070_regulator_data[] = { ...@@ -533,10 +536,24 @@ struct regulator_init_data tps65070_regulator_data[] = {
}, },
}; };
static struct touchscreen_init_data tps6507x_touchscreen_data = {
.poll_period = 30, /* ms between touch samples */
.min_pressure = 0x30, /* minimum pressure to trigger touch */
.vref = 0, /* turn off vref when not using A/D */
.vendor = 0, /* /sys/class/input/input?/id/vendor */
.product = 65070, /* /sys/class/input/input?/id/product */
.version = 0x100, /* /sys/class/input/input?/id/version */
};
static struct tps6507x_board tps_board = {
.tps6507x_pmic_init_data = &tps65070_regulator_data[0],
.tps6507x_ts_init_data = &tps6507x_touchscreen_data,
};
static struct i2c_board_info __initdata da850evm_tps65070_info[] = { static struct i2c_board_info __initdata da850evm_tps65070_info[] = {
{ {
I2C_BOARD_INFO("tps6507x", 0x48), I2C_BOARD_INFO("tps6507x", 0x48),
.platform_data = &tps65070_regulator_data[0], .platform_data = &tps_board,
}, },
}; };
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <mach/irqs.h> #include <mach/irqs.h>
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */ /* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */
#define BUCK_SLEEP_SETTING 0xAC #define BUCK_SLEEP_SETTING 0xAC
#ifdef CONFIG_AB3100_CORE
static struct regulator_consumer_supply supply_ldo_c[] = { static struct regulator_consumer_supply supply_ldo_c[] = {
{ {
.dev_name = "ab3100-codec", .dev_name = "ab3100-codec",
...@@ -253,14 +254,68 @@ static struct ab3100_platform_data ab3100_plf_data = { ...@@ -253,14 +254,68 @@ static struct ab3100_platform_data ab3100_plf_data = {
LDO_D_SETTING, LDO_D_SETTING,
}, },
}; };
#endif
#ifdef CONFIG_AB3550_CORE
static struct abx500_init_settings ab3550_init_settings[] = {
{
.bank = 0,
.reg = AB3550_IMR1,
.setting = 0xff
},
{
.bank = 0,
.reg = AB3550_IMR2,
.setting = 0xff
},
{
.bank = 0,
.reg = AB3550_IMR3,
.setting = 0xff
},
{
.bank = 0,
.reg = AB3550_IMR4,
.setting = 0xff
},
{
.bank = 0,
.reg = AB3550_IMR5,
/* The two most significant bits are not used */
.setting = 0x3f
},
};
static struct ab3550_platform_data ab3550_plf_data = {
.irq = {
.base = IRQ_AB3550_BASE,
.count = (IRQ_AB3550_END - IRQ_AB3550_BASE + 1),
},
.dev_data = {
},
.init_settings = ab3550_init_settings,
.init_settings_sz = ARRAY_SIZE(ab3550_init_settings),
};
#endif
static struct i2c_board_info __initdata bus0_i2c_board_info[] = { static struct i2c_board_info __initdata bus0_i2c_board_info[] = {
#if defined(CONFIG_AB3550_CORE)
{
.type = "ab3550",
.addr = 0x4A,
.irq = IRQ_U300_IRQ0_EXT,
.platform_data = &ab3550_plf_data,
},
#elif defined(CONFIG_AB3100_CORE)
{ {
.type = "ab3100", .type = "ab3100",
.addr = 0x48, .addr = 0x48,
.irq = IRQ_U300_IRQ0_EXT, .irq = IRQ_U300_IRQ0_EXT,
.platform_data = &ab3100_plf_data, .platform_data = &ab3100_plf_data,
}, },
#else
{ },
#endif
}; };
static struct i2c_board_info __initdata bus1_i2c_board_info[] = { static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
......
...@@ -109,6 +109,13 @@ ...@@ -109,6 +109,13 @@
#define U300_NR_IRQS 48 #define U300_NR_IRQS 48
#endif #endif
#ifdef CONFIG_AB3550_CORE
#define IRQ_AB3550_BASE (U300_NR_IRQS)
#define IRQ_AB3550_END (IRQ_AB3550_BASE + 37)
#define NR_IRQS (IRQ_AB3550_END + 1)
#else
#define NR_IRQS U300_NR_IRQS #define NR_IRQS U300_NR_IRQS
#endif
#endif #endif
...@@ -50,7 +50,7 @@ struct pl022_config_chip ab4500_chip_info = { ...@@ -50,7 +50,7 @@ struct pl022_config_chip ab4500_chip_info = {
static struct spi_board_info u8500_spi_devices[] = { static struct spi_board_info u8500_spi_devices[] = {
{ {
.modalias = "ab4500", .modalias = "ab8500",
.controller_data = &ab4500_chip_info, .controller_data = &ab4500_chip_info,
.max_speed_hz = 12000000, .max_speed_hz = 12000000,
.bus_num = 0, .bus_num = 0,
......
...@@ -195,6 +195,13 @@ config GPIO_PCF857X ...@@ -195,6 +195,13 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls. platform-neutral GPIO calls.
config GPIO_TC35892
bool "TC35892 GPIOs"
depends on MFD_TC35892
help
This enables support for the GPIOs found on the TC35892
I/O Expander.
config GPIO_TWL4030 config GPIO_TWL4030
tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
depends on TWL4030_CORE depends on TWL4030_CORE
...@@ -282,6 +289,15 @@ config GPIO_TIMBERDALE ...@@ -282,6 +289,15 @@ config GPIO_TIMBERDALE
---help--- ---help---
Add support for the GPIO IP in the timberdale FPGA. Add support for the GPIO IP in the timberdale FPGA.
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
depends on PCI && GPIOLIB
select MFD_CORE
select MFD_RDC321X
help
Support for the RDC R321x SoC GPIOs over southbridge
PCI configuration space.
comment "SPI GPIO expanders:" comment "SPI GPIO expanders:"
config GPIO_MAX7301 config GPIO_MAX7301
...@@ -317,4 +333,14 @@ config GPIO_UCB1400 ...@@ -317,4 +333,14 @@ config GPIO_UCB1400
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ucb1400_gpio. module will be called ucb1400_gpio.
comment "MODULbus GPIO expanders:"
config GPIO_JANZ_TTL
tristate "Janz VMOD-TTL Digital IO Module"
depends on MFD_JANZ_CMODIO
help
This enables support for the Janz VMOD-TTL Digital IO module.
This driver provides support for driving the pins in output
mode only. Input mode is not supported.
endif endif
...@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o
obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o
...@@ -28,3 +29,5 @@ obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o ...@@ -28,3 +29,5 @@ obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o
obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o
obj-$(CONFIG_GPIO_SCH) += sch_gpio.o obj-$(CONFIG_GPIO_SCH) += sch_gpio.o
obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o
obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o
/*
* Janz MODULbus VMOD-TTL GPIO Driver
*
* Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/mfd/janz.h>
#define DRV_NAME "janz-ttl"
#define PORTA_DIRECTION 0x23
#define PORTB_DIRECTION 0x2B
#define PORTC_DIRECTION 0x06
#define PORTA_IOCTL 0x24
#define PORTB_IOCTL 0x2C
#define PORTC_IOCTL 0x07
#define MASTER_INT_CTL 0x00
#define MASTER_CONF_CTL 0x01
#define CONF_PAE (1 << 2)
#define CONF_PBE (1 << 7)
#define CONF_PCE (1 << 4)
struct ttl_control_regs {
__be16 portc;
__be16 portb;
__be16 porta;
__be16 control;
};
struct ttl_module {
struct gpio_chip gpio;
/* base address of registers */
struct ttl_control_regs __iomem *regs;
u8 portc_shadow;
u8 portb_shadow;
u8 porta_shadow;
spinlock_t lock;
};
static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
{
struct ttl_module *mod = dev_get_drvdata(gpio->dev);
u8 *shadow;
int ret;
if (offset < 8) {
shadow = &mod->porta_shadow;
} else if (offset < 16) {
shadow = &mod->portb_shadow;
offset -= 8;
} else {
shadow = &mod->portc_shadow;
offset -= 16;
}
spin_lock(&mod->lock);
ret = *shadow & (1 << offset);
spin_unlock(&mod->lock);
return ret;
}
static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
{
struct ttl_module *mod = dev_get_drvdata(gpio->dev);
void __iomem *port;
u8 *shadow;
if (offset < 8) {
port = &mod->regs->porta;
shadow = &mod->porta_shadow;
} else if (offset < 16) {
port = &mod->regs->portb;
shadow = &mod->portb_shadow;
offset -= 8;
} else {
port = &mod->regs->portc;
shadow = &mod->portc_shadow;
offset -= 16;
}
spin_lock(&mod->lock);
if (value)
*shadow |= (1 << offset);
else
*shadow &= ~(1 << offset);
iowrite16be(*shadow, port);
spin_unlock(&mod->lock);
}
static void __devinit ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
{
iowrite16be(reg, &mod->regs->control);
iowrite16be(val, &mod->regs->control);
}
static void __devinit ttl_setup_device(struct ttl_module *mod)
{
/* reset the device to a known state */
iowrite16be(0x0000, &mod->regs->control);
iowrite16be(0x0001, &mod->regs->control);
iowrite16be(0x0000, &mod->regs->control);
/* put all ports in open-drain mode */
ttl_write_reg(mod, PORTA_IOCTL, 0x00ff);
ttl_write_reg(mod, PORTB_IOCTL, 0x00ff);
ttl_write_reg(mod, PORTC_IOCTL, 0x000f);
/* set all ports as outputs */
ttl_write_reg(mod, PORTA_DIRECTION, 0x0000);
ttl_write_reg(mod, PORTB_DIRECTION, 0x0000);
ttl_write_reg(mod, PORTC_DIRECTION, 0x0000);
/* set all ports to drive zeroes */
iowrite16be(0x0000, &mod->regs->porta);
iowrite16be(0x0000, &mod->regs->portb);
iowrite16be(0x0000, &mod->regs->portc);
/* enable all ports */
ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
}
static int __devinit ttl_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
struct device *dev = &pdev->dev;
struct ttl_module *mod;
struct gpio_chip *gpio;
struct resource *res;
int ret;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(dev, "no platform data\n");
ret = -ENXIO;
goto out_return;
}
mod = kzalloc(sizeof(*mod), GFP_KERNEL);
if (!mod) {
dev_err(dev, "unable to allocate private data\n");
ret = -ENOMEM;
goto out_return;
}
platform_set_drvdata(pdev, mod);
spin_lock_init(&mod->lock);
/* get access to the MODULbus registers for this module */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "MODULbus registers not found\n");
ret = -ENODEV;
goto out_free_mod;
}
mod->regs = ioremap(res->start, resource_size(res));
if (!mod->regs) {
dev_err(dev, "MODULbus registers not ioremap\n");
ret = -ENOMEM;
goto out_free_mod;
}
ttl_setup_device(mod);
/* Initialize the GPIO data structures */
gpio = &mod->gpio;
gpio->dev = &pdev->dev;
gpio->label = pdev->name;
gpio->get = ttl_get_value;
gpio->set = ttl_set_value;
gpio->owner = THIS_MODULE;
/* request dynamic allocation */
gpio->base = -1;
gpio->ngpio = 20;
ret = gpiochip_add(gpio);
if (ret) {
dev_err(dev, "unable to add GPIO chip\n");
goto out_iounmap_regs;
}
dev_info(&pdev->dev, "module %d: registered GPIO device\n",
pdata->modno);
return 0;
out_iounmap_regs:
iounmap(mod->regs);
out_free_mod:
kfree(mod);
out_return:
return ret;
}
static int __devexit ttl_remove(struct platform_device *pdev)
{
struct ttl_module *mod = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
int ret;
ret = gpiochip_remove(&mod->gpio);
if (ret) {
dev_err(dev, "unable to remove GPIO chip\n");
return ret;
}
iounmap(mod->regs);
kfree(mod);
return 0;
}
static struct platform_driver ttl_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = ttl_probe,
.remove = __devexit_p(ttl_remove),
};
static int __init ttl_init(void)
{
return platform_driver_register(&ttl_driver);
}
static void __exit ttl_exit(void)
{
platform_driver_unregister(&ttl_driver);
}
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:janz-ttl");
module_init(ttl_init);
module_exit(ttl_exit);
/*
* RDC321x GPIO driver
*
* Copyright (C) 2008, Volker Weiss <dev@tintuc.de>
* Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/mfd/rdc321x.h>
#include <linux/slab.h>
struct rdc321x_gpio {
spinlock_t lock;
struct pci_dev *sb_pdev;
u32 data_reg[2];
int reg1_ctrl_base;
int reg1_data_base;
int reg2_ctrl_base;
int reg2_data_base;
struct gpio_chip chip;
};
/* read GPIO pin */
static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
struct rdc321x_gpio *gpch;
u32 value = 0;
int reg;
gpch = container_of(chip, struct rdc321x_gpio, chip);
reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
spin_lock(&gpch->lock);
pci_write_config_dword(gpch->sb_pdev, reg,
gpch->data_reg[gpio < 32 ? 0 : 1]);
pci_read_config_dword(gpch->sb_pdev, reg, &value);
spin_unlock(&gpch->lock);
return (1 << (gpio & 0x1f)) & value ? 1 : 0;
}
static void rdc_gpio_set_value_impl(struct gpio_chip *chip,
unsigned gpio, int value)
{
struct rdc321x_gpio *gpch;
int reg = (gpio < 32) ? 0 : 1;
gpch = container_of(chip, struct rdc321x_gpio, chip);
if (value)
gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
else
gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f));
pci_write_config_dword(gpch->sb_pdev,
reg ? gpch->reg2_data_base : gpch->reg1_data_base,
gpch->data_reg[reg]);
}
/* set GPIO pin to value */
static void rdc_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
struct rdc321x_gpio *gpch;
gpch = container_of(chip, struct rdc321x_gpio, chip);
spin_lock(&gpch->lock);
rdc_gpio_set_value_impl(chip, gpio, value);
spin_unlock(&gpch->lock);
}
static int rdc_gpio_config(struct gpio_chip *chip,
unsigned gpio, int value)
{
struct rdc321x_gpio *gpch;
int err;
u32 reg;
gpch = container_of(chip, struct rdc321x_gpio, chip);
spin_lock(&gpch->lock);
err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, &reg);
if (err)
goto unlock;
reg |= 1 << (gpio & 0x1f);
err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ?
gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg);
if (err)
goto unlock;
rdc_gpio_set_value_impl(chip, gpio, value);
unlock:
spin_unlock(&gpch->lock);
return err;
}
/* configure GPIO pin as input */
static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
return rdc_gpio_config(chip, gpio, 1);
}
/*
* Cache the initial value of both GPIO data registers
*/
static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
{
int err;
struct resource *r;
struct rdc321x_gpio *rdc321x_gpio_dev;
struct rdc321x_gpio_pdata *pdata;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
}
rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL);
if (!rdc321x_gpio_dev) {
dev_err(&pdev->dev, "failed to allocate private data\n");
return -ENOMEM;
}
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
err = -ENODEV;
goto out_free;
}
spin_lock_init(&rdc321x_gpio_dev->lock);
rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev;
rdc321x_gpio_dev->reg1_ctrl_base = r->start;
rdc321x_gpio_dev->reg1_data_base = r->start + 0x4;
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
err = -ENODEV;
goto out_free;
}
rdc321x_gpio_dev->reg2_ctrl_base = r->start;
rdc321x_gpio_dev->reg2_data_base = r->start + 0x4;
rdc321x_gpio_dev->chip.label = "rdc321x-gpio";
rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input;
rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config;
rdc321x_gpio_dev->chip.get = rdc_gpio_get_value;
rdc321x_gpio_dev->chip.set = rdc_gpio_set_value;
rdc321x_gpio_dev->chip.base = 0;
rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios;
platform_set_drvdata(pdev, rdc321x_gpio_dev);
/* This might not be, what others (BIOS, bootloader, etc.)
wrote to these registers before, but it's a good guess. Still
better than just using 0xffffffff. */
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]);
if (err)
goto out_drvdata;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]);
if (err)
goto out_drvdata;
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip);
out_drvdata:
platform_set_drvdata(pdev, NULL);
out_free:
kfree(rdc321x_gpio_dev);
return err;
}
static int __devexit rdc321x_gpio_remove(struct platform_device *pdev)
{
int ret;
struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev);
ret = gpiochip_remove(&rdc321x_gpio_dev->chip);
if (ret)
dev_err(&pdev->dev, "failed to unregister chip\n");
kfree(rdc321x_gpio_dev);
platform_set_drvdata(pdev, NULL);
return ret;
}
static struct platform_driver rdc321x_gpio_driver = {
.driver.name = "rdc321x-gpio",
.driver.owner = THIS_MODULE,
.probe = rdc321x_gpio_probe,
.remove = __devexit_p(rdc321x_gpio_remove),
};
static int __init rdc321x_gpio_init(void)
{
return platform_driver_register(&rdc321x_gpio_driver);
}
static void __exit rdc321x_gpio_exit(void)
{
platform_driver_unregister(&rdc321x_gpio_driver);
}
module_init(rdc321x_gpio_init);
module_exit(rdc321x_gpio_exit);
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_DESCRIPTION("RDC321x GPIO driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rdc321x-gpio");
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc35892.h>
/*
* These registers are modified under the irq bus lock and cached to avoid
* unnecessary writes in bus_sync_unlock.
*/
enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
#define CACHE_NR_REGS 4
#define CACHE_NR_BANKS 3
struct tc35892_gpio {
struct gpio_chip chip;
struct tc35892 *tc35892;
struct device *dev;
struct mutex irq_lock;
int irq_base;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct tc35892_gpio, chip);
}
static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
u8 mask = 1 << (offset % 8);
int ret;
ret = tc35892_reg_read(tc35892, reg);
if (ret < 0)
return ret;
return ret & mask;
}
static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
unsigned pos = offset % 8;
u8 data[] = {!!val << pos, 1 << pos};
tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data);
}
static int tc35892_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
tc35892_gpio_set(chip, offset, val);
return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos);
}
static int tc35892_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
return tc35892_set_bits(tc35892, reg, 1 << pos, 0);
}
static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
return tc35892_gpio->irq_base + offset;
}
static struct gpio_chip template_chip = {
.label = "tc35892",
.owner = THIS_MODULE,
.direction_input = tc35892_gpio_direction_input,
.get = tc35892_gpio_get,
.direction_output = tc35892_gpio_direction_output,
.set = tc35892_gpio_set,
.to_irq = tc35892_gpio_to_irq,
.can_sleep = 1,
};
static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
if (type == IRQ_TYPE_EDGE_BOTH) {
tc35892_gpio->regs[REG_IBE][regoffset] |= mask;
return 0;
}
tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask;
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
tc35892_gpio->regs[REG_IS][regoffset] |= mask;
else
tc35892_gpio->regs[REG_IS][regoffset] &= ~mask;
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
tc35892_gpio->regs[REG_IEV][regoffset] |= mask;
else
tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask;
return 0;
}
static void tc35892_gpio_irq_lock(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
mutex_lock(&tc35892_gpio->irq_lock);
}
static void tc35892_gpio_irq_sync_unlock(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
static const u8 regmap[] = {
[REG_IBE] = TC35892_GPIOIBE0,
[REG_IEV] = TC35892_GPIOIEV0,
[REG_IS] = TC35892_GPIOIS0,
[REG_IE] = TC35892_GPIOIE0,
};
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
for (j = 0; j < CACHE_NR_BANKS; j++) {
u8 old = tc35892_gpio->oldregs[i][j];
u8 new = tc35892_gpio->regs[i][j];
if (new == old)
continue;
tc35892_gpio->oldregs[i][j] = new;
tc35892_reg_write(tc35892, regmap[i] + j * 8, new);
}
}
mutex_unlock(&tc35892_gpio->irq_lock);
}
static void tc35892_gpio_irq_mask(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc35892_gpio->regs[REG_IE][regoffset] &= ~mask;
}
static void tc35892_gpio_irq_unmask(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc35892_gpio->regs[REG_IE][regoffset] |= mask;
}
static struct irq_chip tc35892_gpio_irq_chip = {
.name = "tc35892-gpio",
.bus_lock = tc35892_gpio_irq_lock,
.bus_sync_unlock = tc35892_gpio_irq_sync_unlock,
.mask = tc35892_gpio_irq_mask,
.unmask = tc35892_gpio_irq_unmask,
.set_type = tc35892_gpio_irq_set_type,
};
static irqreturn_t tc35892_gpio_irq(int irq, void *dev)
{
struct tc35892_gpio *tc35892_gpio = dev;
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 status[CACHE_NR_BANKS];
int ret;
int i;
ret = tc35892_block_read(tc35892, TC35892_GPIOMIS0,
ARRAY_SIZE(status), status);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(status); i++) {
unsigned int stat = status[i];
if (!stat)
continue;
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
handle_nested_irq(tc35892_gpio->irq_base + line);
stat &= ~(1 << bit);
}
tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]);
}
return IRQ_HANDLED;
}
static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio)
{
int base = tc35892_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) {
set_irq_chip_data(irq, tc35892_gpio);
set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip,
handle_simple_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void tc35892_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio)
{
int base = tc35892_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static int __devinit tc35892_gpio_probe(struct platform_device *pdev)
{
struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent);
struct tc35892_gpio_platform_data *pdata;
struct tc35892_gpio *tc35892_gpio;
int ret;
int irq;
pdata = tc35892->pdata->gpio;
if (!pdata)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL);
if (!tc35892_gpio)
return -ENOMEM;
mutex_init(&tc35892_gpio->irq_lock);
tc35892_gpio->dev = &pdev->dev;
tc35892_gpio->tc35892 = tc35892;
tc35892_gpio->chip = template_chip;
tc35892_gpio->chip.ngpio = tc35892->num_gpio;
tc35892_gpio->chip.dev = &pdev->dev;
tc35892_gpio->chip.base = pdata->gpio_base;
tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0);
/* Bring the GPIO module out of reset */
ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL,
TC35892_RSTCTRL_GPIRST, 0);
if (ret < 0)
goto out_free;
ret = tc35892_gpio_irq_init(tc35892_gpio);
if (ret)
goto out_free;
ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT,
"tc35892-gpio", tc35892_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
}
ret = gpiochip_add(&tc35892_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
goto out_freeirq;
}
platform_set_drvdata(pdev, tc35892_gpio);
return 0;
out_freeirq:
free_irq(irq, tc35892_gpio);
out_removeirq:
tc35892_gpio_irq_remove(tc35892_gpio);
out_free:
kfree(tc35892_gpio);
return ret;
}
static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
{
struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
int ret;
ret = gpiochip_remove(&tc35892_gpio->chip);
if (ret < 0) {
dev_err(tc35892_gpio->dev,
"unable to remove gpiochip: %d\n", ret);
return ret;
}
free_irq(irq, tc35892_gpio);
tc35892_gpio_irq_remove(tc35892_gpio);
platform_set_drvdata(pdev, NULL);
kfree(tc35892_gpio);
return 0;
}
static struct platform_driver tc35892_gpio_driver = {
.driver.name = "tc35892-gpio",
.driver.owner = THIS_MODULE,
.probe = tc35892_gpio_probe,
.remove = __devexit_p(tc35892_gpio_remove),
};
static int __init tc35892_gpio_init(void)
{
return platform_driver_register(&tc35892_gpio_driver);
}
subsys_initcall(tc35892_gpio_init);
static void __exit tc35892_gpio_exit(void)
{
platform_driver_unregister(&tc35892_gpio_driver);
}
module_exit(tc35892_gpio_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC35892 GPIO driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
...@@ -590,4 +590,17 @@ config TOUCHSCREEN_PCAP ...@@ -590,4 +590,17 @@ config TOUCHSCREEN_PCAP
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called pcap_ts. module will be called pcap_ts.
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
help
Say Y here if you have a TPS6507x based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
endif endif
...@@ -46,3 +46,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o ...@@ -46,3 +46,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
/*
* drivers/input/touchscreen/tps6507x_ts.c
*
* Touchscreen driver for the tps6507x chip.
*
* Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com)
*
* Credits:
*
* Using code from tsc2007, MtekVision Co., Ltd.
*
* For licencing details see kernel-base/COPYING
*
* TPS65070, TPS65073, TPS650731, and TPS650732 support
* 10 bit touch screen interface.
*/
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
#include <linux/delay.h>
#define TSC_DEFAULT_POLL_PERIOD 30 /* ms */
#define TPS_DEFAULT_MIN_PRESSURE 0x30
#define MAX_10BIT ((1 << 10) - 1)
#define TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \
TPS6507X_ADCONFIG_START_CONVERSION | \
TPS6507X_ADCONFIG_INPUT_REAL_TSC)
#define TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC)
struct ts_event {
u16 x;
u16 y;
u16 pressure;
};
struct tps6507x_ts {
struct input_dev *input_dev;
struct device *dev;
char phys[32];
struct workqueue_struct *wq;
struct delayed_work work;
unsigned polling; /* polling is active */
struct ts_event tc;
struct tps6507x_dev *mfd;
u16 model;
unsigned pendown;
int irq;
void (*clear_penirq)(void);
unsigned long poll_period; /* ms */
u16 min_pressure;
int vref; /* non-zero to leave vref on */
};
static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
{
int err;
err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
if (err)
return err;
return 0;
}
static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data)
{
return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data);
}
static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc,
u8 tsc_mode, u16 *value)
{
s32 ret;
u8 adc_status;
u8 result;
/* Route input signal to A/D converter */
ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode);
if (ret) {
dev_err(tsc->dev, "TSC mode read failed\n");
goto err;
}
/* Start A/D conversion */
ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
TPS6507X_ADCONFIG_CONVERT_TS);
if (ret) {
dev_err(tsc->dev, "ADC config write failed\n");
return ret;
}
do {
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG,
&adc_status);
if (ret) {
dev_err(tsc->dev, "ADC config read failed\n");
goto err;
}
} while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION);
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result);
if (ret) {
dev_err(tsc->dev, "ADC result 2 read failed\n");
goto err;
}
*value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8;
ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result);
if (ret) {
dev_err(tsc->dev, "ADC result 1 read failed\n");
goto err;
}
*value |= result;
dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value);
err:
return ret;
}
/* Need to call tps6507x_adc_standby() after using A/D converter for the
* touch screen interrupt to work properly.
*/
static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
{
s32 ret;
s32 loops = 0;
u8 val;
ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
TPS6507X_ADCONFIG_INPUT_TSC);
if (ret)
return ret;
ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE,
TPS6507X_TSCMODE_STANDBY);
if (ret)
return ret;
ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
if (ret)
return ret;
while (val & TPS6507X_REG_TSC_INT) {
mdelay(10);
ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
if (ret)
return ret;
loops++;
}
return ret;
}
static void tps6507x_ts_handler(struct work_struct *work)
{
struct tps6507x_ts *tsc = container_of(work,
struct tps6507x_ts, work.work);
struct input_dev *input_dev = tsc->input_dev;
int pendown;
int schd;
int poll = 0;
s32 ret;
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
&tsc->tc.pressure);
if (ret)
goto done;
pendown = tsc->tc.pressure > tsc->min_pressure;
if (unlikely(!pendown && tsc->pendown)) {
dev_dbg(tsc->dev, "UP\n");
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
tsc->pendown = 0;
}
if (pendown) {
if (!tsc->pendown) {
dev_dbg(tsc->dev, "DOWN\n");
input_report_key(input_dev, BTN_TOUCH, 1);
} else
dev_dbg(tsc->dev, "still down\n");
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION,
&tsc->tc.x);
if (ret)
goto done;
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION,
&tsc->tc.y);
if (ret)
goto done;
input_report_abs(input_dev, ABS_X, tsc->tc.x);
input_report_abs(input_dev, ABS_Y, tsc->tc.y);
input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
input_sync(input_dev);
tsc->pendown = 1;
poll = 1;
}
done:
/* always poll if not using interrupts */
poll = 1;
if (poll) {
schd = queue_delayed_work(tsc->wq, &tsc->work,
tsc->poll_period * HZ / 1000);
if (schd)
tsc->polling = 1;
else {
tsc->polling = 0;
dev_err(tsc->dev, "re-schedule failed");
}
} else
tsc->polling = 0;
ret = tps6507x_adc_standby(tsc);
}
static int tps6507x_ts_probe(struct platform_device *pdev)
{
int error;
struct tps6507x_ts *tsc;
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
struct touchscreen_init_data *init_data;
struct input_dev *input_dev;
struct tps6507x_board *tps_board;
int schd;
/**
* tps_board points to pmic related constants
* coming from the board-evm file.
*/
tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data;
if (!tps_board) {
dev_err(tps6507x_dev->dev,
"Could not find tps6507x platform data\n");
return -EIO;
}
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = tps_board->tps6507x_ts_init_data;
tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
if (!tsc) {
dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
error = -ENOMEM;
goto err0;
}
tps6507x_dev->ts = tsc;
tsc->mfd = tps6507x_dev;
tsc->dev = tps6507x_dev->dev;
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(tsc->dev, "Failed to allocate input device.\n");
error = -ENOMEM;
goto err1;
}
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
input_dev->name = "TPS6507x Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = tsc->dev;
snprintf(tsc->phys, sizeof(tsc->phys),
"%s/input0", dev_name(tsc->dev));
input_dev->phys = tsc->phys;
dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
input_set_drvdata(input_dev, tsc);
tsc->input_dev = input_dev;
INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
tsc->wq = create_workqueue("TPS6507x Touchscreen");
if (init_data) {
tsc->poll_period = init_data->poll_period;
tsc->vref = init_data->vref;
tsc->min_pressure = init_data->min_pressure;
input_dev->id.vendor = init_data->vendor;
input_dev->id.product = init_data->product;
input_dev->id.version = init_data->version;
} else {
tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
}
error = tps6507x_adc_standby(tsc);
if (error)
goto err2;
error = input_register_device(input_dev);
if (error)
goto err2;
schd = queue_delayed_work(tsc->wq, &tsc->work,
tsc->poll_period * HZ / 1000);
if (schd)
tsc->polling = 1;
else {
tsc->polling = 0;
dev_err(tsc->dev, "schedule failed");
goto err2;
}
return 0;
err2:
cancel_delayed_work(&tsc->work);
flush_workqueue(tsc->wq);
destroy_workqueue(tsc->wq);
tsc->wq = 0;
input_free_device(input_dev);
err1:
kfree(tsc);
tps6507x_dev->ts = NULL;
err0:
return error;
}
static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
struct tps6507x_ts *tsc = tps6507x_dev->ts;
struct input_dev *input_dev = tsc->input_dev;
if (!tsc)
return 0;
cancel_delayed_work(&tsc->work);
flush_workqueue(tsc->wq);
destroy_workqueue(tsc->wq);
tsc->wq = 0;
input_free_device(input_dev);
tps6507x_dev->ts = NULL;
kfree(tsc);
return 0;
}
static struct platform_driver tps6507x_ts_driver = {
.driver = {
.name = "tps6507x-ts",
.owner = THIS_MODULE,
},
.probe = tps6507x_ts_probe,
.remove = __devexit_p(tps6507x_ts_remove),
};
static int __init tps6507x_ts_init(void)
{
return platform_driver_register(&tps6507x_ts_driver);
}
module_init(tps6507x_ts_init);
static void __exit tps6507x_ts_exit(void)
{
platform_driver_unregister(&tps6507x_ts_driver);
}
module_exit(tps6507x_ts_exit);
MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>");
MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tps6507x-tsc");
...@@ -566,7 +566,7 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, ...@@ -566,7 +566,7 @@ static int __devinit device_irq_init(struct pm860x_chip *chip,
return ret; return ret;
} }
static void __devexit device_irq_exit(struct pm860x_chip *chip) static void device_irq_exit(struct pm860x_chip *chip)
{ {
if (chip->core_irq) if (chip->core_irq)
free_irq(chip->core_irq, chip); free_irq(chip->core_irq, chip);
...@@ -703,7 +703,7 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, ...@@ -703,7 +703,7 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
return; return;
} }
int pm860x_device_init(struct pm860x_chip *chip, int __devinit pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata) struct pm860x_platform_data *pdata)
{ {
chip->core_irq = 0; chip->core_irq = 0;
...@@ -731,7 +731,7 @@ int pm860x_device_init(struct pm860x_chip *chip, ...@@ -731,7 +731,7 @@ int pm860x_device_init(struct pm860x_chip *chip,
return 0; return 0;
} }
void pm860x_device_exit(struct pm860x_chip *chip) void __devexit pm860x_device_exit(struct pm860x_chip *chip)
{ {
device_irq_exit(chip); device_irq_exit(chip);
mfd_remove_devices(chip->dev); mfd_remove_devices(chip->dev);
......
...@@ -200,8 +200,8 @@ static int __devexit pm860x_remove(struct i2c_client *client) ...@@ -200,8 +200,8 @@ static int __devexit pm860x_remove(struct i2c_client *client)
pm860x_device_exit(chip); pm860x_device_exit(chip);
i2c_unregister_device(chip->companion); i2c_unregister_device(chip->companion);
i2c_set_clientdata(chip->companion, NULL);
i2c_set_clientdata(chip->client, NULL); i2c_set_clientdata(chip->client, NULL);
i2c_set_clientdata(client, NULL);
kfree(chip); kfree(chip);
return 0; return 0;
} }
......
...@@ -2,8 +2,14 @@ ...@@ -2,8 +2,14 @@
# Multifunction miscellaneous devices # Multifunction miscellaneous devices
# #
menu "Multifunction device drivers" menuconfig MFD_SUPPORT
bool "Multifunction device drivers"
depends on HAS_IOMEM depends on HAS_IOMEM
default y
help
Configure MFD device drivers.
if MFD_SUPPORT
config MFD_CORE config MFD_CORE
tristate tristate
...@@ -116,6 +122,18 @@ config TPS65010 ...@@ -116,6 +122,18 @@ config TPS65010
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called tps65010. will be called tps65010.
config TPS6507X
tristate "TPS6507x Power Management / Touch Screen chips"
select MFD_CORE
depends on I2C
help
If you say yes here you get support for the TPS6507x series of
Power Management / Touch Screen chips. These include voltage
regulators, lithium ion/polymer battery charging, touch screen
and other features that are often used in portable devices.
This driver can also be built as a module. If so, the module
will be called tps6507x.
config MENELAUS config MENELAUS
bool "Texas Instruments TWL92330/Menelaus PM chip" bool "Texas Instruments TWL92330/Menelaus PM chip"
depends on I2C=y && ARCH_OMAP2 depends on I2C=y && ARCH_OMAP2
...@@ -159,6 +177,17 @@ config TWL4030_CODEC ...@@ -159,6 +177,17 @@ config TWL4030_CODEC
select MFD_CORE select MFD_CORE
default n default n
config MFD_TC35892
bool "Support Toshiba TC35892"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
help
Support for the Toshiba TC35892 I/O Expander.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_TMIO config MFD_TMIO
bool bool
default n default n
...@@ -351,9 +380,19 @@ config PCF50633_GPIO ...@@ -351,9 +380,19 @@ config PCF50633_GPIO
Say yes here if you want to include support GPIO for pins on Say yes here if you want to include support GPIO for pins on
the PCF50633 chip. the PCF50633 chip.
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
default y if ARCH_U300
help
Say yes here if you have the ABX500 Mixed Signal IC family
chips. This core driver expose register access functions.
Functionality specific drivers using these functions can
remain unchanged when IC changes. Binding of the functions to
actual register access is done by the IC core driver.
config AB3100_CORE config AB3100_CORE
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
depends on I2C=y depends on I2C=y && ABX500_CORE
default y if ARCH_U300 default y if ARCH_U300
help help
Select this to enable the AB3100 Mixed Signal IC core Select this to enable the AB3100 Mixed Signal IC core
...@@ -381,15 +420,30 @@ config EZX_PCAP ...@@ -381,15 +420,30 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc.. needed for MMC, TouchScreen, Sound, USB, etc..
config AB4500_CORE config AB8500_CORE
tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip" bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on SPI depends on SPI=y && GENERIC_HARDIRQS
select MFD_CORE
help help
Select this option to enable access to AB4500 power management Select this option to enable access to AB8500 power management
chip. This connects to U8500 on the SSP/SPI bus and exports chip. This connects to U8500 on the SSP/SPI bus and exports
read/write functions for the devices to get access to this chip. read/write functions for the devices to get access to this chip.
This chip embeds various other multimedia funtionalities as well. This chip embeds various other multimedia funtionalities as well.
config AB3550_CORE
bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
select MFD_CORE
depends on I2C=y && GENERIC_HARDIRQS && ABX500_CORE
help
Select this to enable the AB3550 Mixed Signal IC core
functionality. This connects to a AB3550 on the I2C bus
and expose a number of symbols needed for dependent devices
to read and write registers and subscribe to events from
this multi-functional IC. This is needed to use other features
of the AB3550 such as battery-backed RTC, charging control,
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
config MFD_TIMBERDALE config MFD_TIMBERDALE
tristate "Support for the Timberdale FPGA" tristate "Support for the Timberdale FPGA"
select MFD_CORE select MFD_CORE
...@@ -409,7 +463,26 @@ config LPC_SCH ...@@ -409,7 +463,26 @@ config LPC_SCH
LPC bridge function of the Intel SCH provides support for LPC bridge function of the Intel SCH provides support for
System Management Bus and General Purpose I/O. System Management Bus and General Purpose I/O.
endmenu config MFD_RDC321X
tristate "Support for RDC-R321x southbridge"
select MFD_CORE
depends on PCI
help
Say yes here if you want to have support for the RDC R-321x SoC
southbridge which provides access to GPIOs and Watchdog using the
southbridge PCI device configuration space.
config MFD_JANZ_CMODIO
tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
select MFD_CORE
depends on PCI
help
This is the core driver for the Janz CMOD-IO PCI MODULbus
carrier board. This device is a PCI to MODULbus bridge which may
host many different types of MODULbus daughterboards, including
CAN and GPIO controllers.
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers" menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100 depends on ARCH_SA1100
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_TC35892) += tc35892.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
...@@ -29,6 +30,7 @@ obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o ...@@ -29,6 +30,7 @@ obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
...@@ -55,12 +57,17 @@ obj-$(CONFIG_PMIC_DA903X) += da903x.o ...@@ -55,12 +57,17 @@ obj-$(CONFIG_PMIC_DA903X) += da903x.o
max8925-objs := max8925-core.o max8925-i2c.o max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB4500_CORE) += ab4500-core.o obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o obj-$(CONFIG_LPC_SCH) += lpc_sch.o
obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h>
/* These are the only registers inside AB3100 used in this main file */ /* These are the only registers inside AB3100 used in this main file */
...@@ -59,24 +59,15 @@ ...@@ -59,24 +59,15 @@
* The AB3100 is usually assigned address 0x48 (7-bit) * The AB3100 is usually assigned address 0x48 (7-bit)
* The chip is defined in the platform i2c_board_data section. * The chip is defined in the platform i2c_board_data section.
*/ */
static int ab3100_get_chip_id(struct device *dev)
u8 ab3100_get_chip_type(struct ab3100 *ab3100)
{ {
u8 chip = ABUNKNOWN; struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
switch (ab3100->chip_id & 0xf0) { return (int)ab3100->chip_id;
case 0xa0:
chip = AB3000;
break;
case 0xc0:
chip = AB3100;
break;
}
return chip;
} }
EXPORT_SYMBOL(ab3100_get_chip_type);
int ab3100_set_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 regval) static int ab3100_set_register_interruptible(struct ab3100 *ab3100,
u8 reg, u8 regval)
{ {
u8 regandval[2] = {reg, regval}; u8 regandval[2] = {reg, regval};
int err; int err;
...@@ -108,8 +99,14 @@ int ab3100_set_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 regval) ...@@ -108,8 +99,14 @@ int ab3100_set_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 regval)
mutex_unlock(&ab3100->access_mutex); mutex_unlock(&ab3100->access_mutex);
return err; return err;
} }
EXPORT_SYMBOL(ab3100_set_register_interruptible);
static int set_register_interruptible(struct device *dev,
u8 bank, u8 reg, u8 value)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
return ab3100_set_register_interruptible(ab3100, reg, value);
}
/* /*
* The test registers exist at an I2C bus address up one * The test registers exist at an I2C bus address up one
...@@ -148,8 +145,8 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, ...@@ -148,8 +145,8 @@ static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100,
return err; return err;
} }
static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
int ab3100_get_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 *regval) u8 reg, u8 *regval)
{ {
int err; int err;
...@@ -203,10 +200,16 @@ int ab3100_get_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 *regval) ...@@ -203,10 +200,16 @@ int ab3100_get_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 *regval)
mutex_unlock(&ab3100->access_mutex); mutex_unlock(&ab3100->access_mutex);
return err; return err;
} }
EXPORT_SYMBOL(ab3100_get_register_interruptible);
static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 *value)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
return ab3100_get_register_interruptible(ab3100, reg, value);
}
int ab3100_get_register_page_interruptible(struct ab3100 *ab3100, static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100,
u8 first_reg, u8 *regvals, u8 numregs) u8 first_reg, u8 *regvals, u8 numregs)
{ {
int err; int err;
...@@ -260,10 +263,17 @@ int ab3100_get_register_page_interruptible(struct ab3100 *ab3100, ...@@ -260,10 +263,17 @@ int ab3100_get_register_page_interruptible(struct ab3100 *ab3100,
mutex_unlock(&ab3100->access_mutex); mutex_unlock(&ab3100->access_mutex);
return err; return err;
} }
EXPORT_SYMBOL(ab3100_get_register_page_interruptible);
static int get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
return ab3100_get_register_page_interruptible(ab3100,
first_reg, regvals, numregs);
}
int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100, static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100,
u8 reg, u8 andmask, u8 ormask) u8 reg, u8 andmask, u8 ormask)
{ {
u8 regandval[2] = {reg, 0}; u8 regandval[2] = {reg, 0};
...@@ -331,8 +341,15 @@ int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100, ...@@ -331,8 +341,15 @@ int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100,
mutex_unlock(&ab3100->access_mutex); mutex_unlock(&ab3100->access_mutex);
return err; return err;
} }
EXPORT_SYMBOL(ab3100_mask_and_set_register_interruptible);
static int mask_and_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
return ab3100_mask_and_set_register_interruptible(ab3100,
reg, bitmask, (bitmask & bitvalues));
}
/* /*
* Register a simple callback for handling any AB3100 events. * Register a simple callback for handling any AB3100 events.
...@@ -357,15 +374,27 @@ int ab3100_event_unregister(struct ab3100 *ab3100, ...@@ -357,15 +374,27 @@ int ab3100_event_unregister(struct ab3100 *ab3100,
EXPORT_SYMBOL(ab3100_event_unregister); EXPORT_SYMBOL(ab3100_event_unregister);
int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100, static int ab3100_event_registers_startup_state_get(struct device *dev,
u32 *fatevent) u8 *event)
{ {
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
if (!ab3100->startup_events_read) if (!ab3100->startup_events_read)
return -EAGAIN; /* Try again later */ return -EAGAIN; /* Try again later */
*fatevent = ab3100->startup_events; memcpy(event, ab3100->startup_events, 3);
return 0; return 0;
} }
EXPORT_SYMBOL(ab3100_event_registers_startup_state_get);
static struct abx500_ops ab3100_ops = {
.get_chip_id = ab3100_get_chip_id,
.set_register = set_register_interruptible,
.get_register = get_register_interruptible,
.get_register_page = get_register_page_interruptible,
.set_register_page = NULL,
.mask_and_set_register = mask_and_set_register_interruptible,
.event_registers_startup_state_get =
ab3100_event_registers_startup_state_get,
.startup_irq_enabled = NULL,
};
/* /*
* This is a threaded interrupt handler so we can make some * This is a threaded interrupt handler so we can make some
...@@ -390,7 +419,9 @@ static irqreturn_t ab3100_irq_handler(int irq, void *data) ...@@ -390,7 +419,9 @@ static irqreturn_t ab3100_irq_handler(int irq, void *data)
event_regs[2]; event_regs[2];
if (!ab3100->startup_events_read) { if (!ab3100->startup_events_read) {
ab3100->startup_events = fatevent; ab3100->startup_events[0] = event_regs[0];
ab3100->startup_events[1] = event_regs[1];
ab3100->startup_events[2] = event_regs[2];
ab3100->startup_events_read = true; ab3100->startup_events_read = true;
} }
/* /*
...@@ -703,7 +734,8 @@ static int __init ab3100_setup(struct ab3100 *ab3100) ...@@ -703,7 +734,8 @@ static int __init ab3100_setup(struct ab3100 *ab3100)
dev_warn(ab3100->dev, dev_warn(ab3100->dev,
"AB3100 P1E variant detected, " "AB3100 P1E variant detected, "
"forcing chip to 32KHz\n"); "forcing chip to 32KHz\n");
err = ab3100_set_test_register_interruptible(ab3100, 0x02, 0x08); err = ab3100_set_test_register_interruptible(ab3100,
0x02, 0x08);
} }
exit_no_setup: exit_no_setup:
...@@ -898,6 +930,10 @@ static int __init ab3100_probe(struct i2c_client *client, ...@@ -898,6 +930,10 @@ static int __init ab3100_probe(struct i2c_client *client,
if (err) if (err)
goto exit_no_irq; goto exit_no_irq;
err = abx500_register_ops(&client->dev, &ab3100_ops);
if (err)
goto exit_no_ops;
/* Set parent and a pointer back to the container in device data */ /* Set parent and a pointer back to the container in device data */
for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) { for (i = 0; i < ARRAY_SIZE(ab3100_platform_devs); i++) {
ab3100_platform_devs[i]->dev.parent = ab3100_platform_devs[i]->dev.parent =
...@@ -915,11 +951,13 @@ static int __init ab3100_probe(struct i2c_client *client, ...@@ -915,11 +951,13 @@ static int __init ab3100_probe(struct i2c_client *client,
return 0; return 0;
exit_no_ops:
exit_no_irq: exit_no_irq:
exit_no_setup: exit_no_setup:
i2c_unregister_device(ab3100->testreg_client); i2c_unregister_device(ab3100->testreg_client);
exit_no_testreg_client: exit_no_testreg_client:
exit_no_detect: exit_no_detect:
i2c_set_clientdata(client, NULL);
kfree(ab3100); kfree(ab3100);
return err; return err;
} }
...@@ -941,6 +979,7 @@ static int __exit ab3100_remove(struct i2c_client *client) ...@@ -941,6 +979,7 @@ static int __exit ab3100_remove(struct i2c_client *client)
* their notifiers so deactivate IRQ * their notifiers so deactivate IRQ
*/ */
free_irq(client->irq, ab3100); free_irq(client->irq, ab3100);
i2c_set_clientdata(client, NULL);
kfree(ab3100); kfree(ab3100);
return 0; return 0;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
/** /**
* struct ab3100_otp * struct ab3100_otp
* @dev containing device * @dev containing device
* @ab3100 a pointer to the parent ab3100 device struct
* @locked whether the OTP is locked, after locking, no more bits * @locked whether the OTP is locked, after locking, no more bits
* can be changed but before locking it is still possible * can be changed but before locking it is still possible
* to change bits from 1->0. * to change bits from 1->0.
...@@ -49,7 +48,6 @@ ...@@ -49,7 +48,6 @@
*/ */
struct ab3100_otp { struct ab3100_otp {
struct device *dev; struct device *dev;
struct ab3100 *ab3100;
bool locked; bool locked;
u32 freq; u32 freq;
bool paf; bool paf;
...@@ -63,19 +61,19 @@ struct ab3100_otp { ...@@ -63,19 +61,19 @@ struct ab3100_otp {
static int __init ab3100_otp_read(struct ab3100_otp *otp) static int __init ab3100_otp_read(struct ab3100_otp *otp)
{ {
struct ab3100 *ab = otp->ab3100;
u8 otpval[8]; u8 otpval[8];
u8 otpp; u8 otpp;
int err; int err;
err = ab3100_get_register_interruptible(ab, AB3100_OTPP, &otpp); err = abx500_get_register_interruptible(otp->dev, 0,
AB3100_OTPP, &otpp);
if (err) { if (err) {
dev_err(otp->dev, "unable to read OTPP register\n"); dev_err(otp->dev, "unable to read OTPP register\n");
return err; return err;
} }
err = ab3100_get_register_page_interruptible(ab, AB3100_OTP0, err = abx500_get_register_page_interruptible(otp->dev, 0,
otpval, 8); AB3100_OTP0, otpval, 8);
if (err) { if (err) {
dev_err(otp->dev, "unable to read OTP register page\n"); dev_err(otp->dev, "unable to read OTP register page\n");
return err; return err;
...@@ -197,7 +195,6 @@ static int __init ab3100_otp_probe(struct platform_device *pdev) ...@@ -197,7 +195,6 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
otp->dev = &pdev->dev; otp->dev = &pdev->dev;
/* Replace platform data coming in with a local struct */ /* Replace platform data coming in with a local struct */
otp->ab3100 = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, otp); platform_set_drvdata(pdev, otp);
err = ab3100_otp_read(otp); err = ab3100_otp_read(otp);
......
/*
* Copyright (C) 2007-2010 ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
* Low-level core for exclusive access to the AB3550 IC on the I2C bus
* and some basic chip-configuration.
* Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
* Author: Rickard Andersson <rickard.andersson@stericsson.com>
*/
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/random.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/mfd/abx500.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/mfd/core.h>
#define AB3550_NAME_STRING "ab3550"
#define AB3550_ID_FORMAT_STRING "AB3550 %s"
#define AB3550_NUM_BANKS 2
#define AB3550_NUM_EVENT_REG 5
/* These are the only registers inside AB3550 used in this main file */
/* Chip ID register */
#define AB3550_CID_REG 0x20
/* Interrupt event registers */
#define AB3550_EVENT_BANK 0
#define AB3550_EVENT_REG 0x22
/* Read/write operation values. */
#define AB3550_PERM_RD (0x01)
#define AB3550_PERM_WR (0x02)
/* Read/write permissions. */
#define AB3550_PERM_RO (AB3550_PERM_RD)
#define AB3550_PERM_RW (AB3550_PERM_RD | AB3550_PERM_WR)
/**
* struct ab3550
* @access_mutex: lock out concurrent accesses to the AB registers
* @i2c_client: I2C client for this chip
* @chip_name: name of this chip variant
* @chip_id: 8 bit chip ID for this chip variant
* @mask_work: a worker for writing to mask registers
* @event_lock: a lock to protect the event_mask
* @event_mask: a local copy of the mask event registers
* @startup_events: a copy of the first reading of the event registers
* @startup_events_read: whether the first events have been read
*/
struct ab3550 {
struct mutex access_mutex;
struct i2c_client *i2c_client[AB3550_NUM_BANKS];
char chip_name[32];
u8 chip_id;
struct work_struct mask_work;
spinlock_t event_lock;
u8 event_mask[AB3550_NUM_EVENT_REG];
u8 startup_events[AB3550_NUM_EVENT_REG];
bool startup_events_read;
#ifdef CONFIG_DEBUG_FS
unsigned int debug_bank;
unsigned int debug_address;
#endif
};
/**
* struct ab3550_reg_range
* @first: the first address of the range
* @last: the last address of the range
* @perm: access permissions for the range
*/
struct ab3550_reg_range {
u8 first;
u8 last;
u8 perm;
};
/**
* struct ab3550_reg_ranges
* @count: the number of ranges in the list
* @range: the list of register ranges
*/
struct ab3550_reg_ranges {
u8 count;
const struct ab3550_reg_range *range;
};
/*
* Permissible register ranges for reading and writing per device and bank.
*
* The ranges must be listed in increasing address order, and no overlaps are
* allowed. It is assumed that write permission implies read permission
* (i.e. only RO and RW permissions should be used). Ranges with write
* permission must not be split up.
*/
#define NO_RANGE {.count = 0, .range = NULL,}
static struct
ab3550_reg_ranges ab3550_reg_ranges[AB3550_NUM_DEVICES][AB3550_NUM_BANKS] = {
[AB3550_DEVID_DAC] = {
NO_RANGE,
{
.count = 2,
.range = (struct ab3550_reg_range[]) {
{
.first = 0xb0,
.last = 0xba,
.perm = AB3550_PERM_RW,
},
{
.first = 0xbc,
.last = 0xc3,
.perm = AB3550_PERM_RW,
},
},
},
},
[AB3550_DEVID_LEDS] = {
NO_RANGE,
{
.count = 2,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x5a,
.last = 0x88,
.perm = AB3550_PERM_RW,
},
{
.first = 0x8a,
.last = 0xad,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_POWER] = {
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x21,
.last = 0x21,
.perm = AB3550_PERM_RO,
},
}
},
NO_RANGE,
},
[AB3550_DEVID_REGULATORS] = {
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x69,
.last = 0xa3,
.perm = AB3550_PERM_RW,
},
}
},
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x14,
.last = 0x16,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_SIM] = {
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x21,
.last = 0x21,
.perm = AB3550_PERM_RO,
},
}
},
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x14,
.last = 0x17,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_UART] = {
NO_RANGE,
NO_RANGE,
},
[AB3550_DEVID_RTC] = {
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x00,
.last = 0x0c,
.perm = AB3550_PERM_RW,
},
}
},
NO_RANGE,
},
[AB3550_DEVID_CHARGER] = {
{
.count = 2,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x10,
.last = 0x1a,
.perm = AB3550_PERM_RW,
},
{
.first = 0x21,
.last = 0x21,
.perm = AB3550_PERM_RO,
},
}
},
NO_RANGE,
},
[AB3550_DEVID_ADC] = {
NO_RANGE,
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x20,
.last = 0x56,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_FUELGAUGE] = {
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x21,
.last = 0x21,
.perm = AB3550_PERM_RO,
},
}
},
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x00,
.last = 0x0e,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_VIBRATOR] = {
NO_RANGE,
{
.count = 1,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x10,
.last = 0x13,
.perm = AB3550_PERM_RW,
},
}
},
},
[AB3550_DEVID_CODEC] = {
{
.count = 2,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x31,
.last = 0x63,
.perm = AB3550_PERM_RW,
},
{
.first = 0x65,
.last = 0x68,
.perm = AB3550_PERM_RW,
},
}
},
NO_RANGE,
},
};
static struct mfd_cell ab3550_devs[AB3550_NUM_DEVICES] = {
[AB3550_DEVID_DAC] = {
.name = "ab3550-dac",
.id = AB3550_DEVID_DAC,
.num_resources = 0,
},
[AB3550_DEVID_LEDS] = {
.name = "ab3550-leds",
.id = AB3550_DEVID_LEDS,
},
[AB3550_DEVID_POWER] = {
.name = "ab3550-power",
.id = AB3550_DEVID_POWER,
},
[AB3550_DEVID_REGULATORS] = {
.name = "ab3550-regulators",
.id = AB3550_DEVID_REGULATORS,
},
[AB3550_DEVID_SIM] = {
.name = "ab3550-sim",
.id = AB3550_DEVID_SIM,
},
[AB3550_DEVID_UART] = {
.name = "ab3550-uart",
.id = AB3550_DEVID_UART,
},
[AB3550_DEVID_RTC] = {
.name = "ab3550-rtc",
.id = AB3550_DEVID_RTC,
},
[AB3550_DEVID_CHARGER] = {
.name = "ab3550-charger",
.id = AB3550_DEVID_CHARGER,
},
[AB3550_DEVID_ADC] = {
.name = "ab3550-adc",
.id = AB3550_DEVID_ADC,
.num_resources = 10,
.resources = (struct resource[]) {
{
.name = "TRIGGER-0",
.flags = IORESOURCE_IRQ,
.start = 16,
.end = 16,
},
{
.name = "TRIGGER-1",
.flags = IORESOURCE_IRQ,
.start = 17,
.end = 17,
},
{
.name = "TRIGGER-2",
.flags = IORESOURCE_IRQ,
.start = 18,
.end = 18,
},
{
.name = "TRIGGER-3",
.flags = IORESOURCE_IRQ,
.start = 19,
.end = 19,
},
{
.name = "TRIGGER-4",
.flags = IORESOURCE_IRQ,
.start = 20,
.end = 20,
},
{
.name = "TRIGGER-5",
.flags = IORESOURCE_IRQ,
.start = 21,
.end = 21,
},
{
.name = "TRIGGER-6",
.flags = IORESOURCE_IRQ,
.start = 22,
.end = 22,
},
{
.name = "TRIGGER-7",
.flags = IORESOURCE_IRQ,
.start = 23,
.end = 23,
},
{
.name = "TRIGGER-VBAT-TXON",
.flags = IORESOURCE_IRQ,
.start = 13,
.end = 13,
},
{
.name = "TRIGGER-VBAT",
.flags = IORESOURCE_IRQ,
.start = 12,
.end = 12,
},
},
},
[AB3550_DEVID_FUELGAUGE] = {
.name = "ab3550-fuelgauge",
.id = AB3550_DEVID_FUELGAUGE,
},
[AB3550_DEVID_VIBRATOR] = {
.name = "ab3550-vibrator",
.id = AB3550_DEVID_VIBRATOR,
},
[AB3550_DEVID_CODEC] = {
.name = "ab3550-codec",
.id = AB3550_DEVID_CODEC,
},
};
/*
* I2C transactions with error messages.
*/
static int ab3550_i2c_master_send(struct ab3550 *ab, u8 bank, u8 *data,
u8 count)
{
int err;
err = i2c_master_send(ab->i2c_client[bank], data, count);
if (err < 0) {
dev_err(&ab->i2c_client[0]->dev, "send error: %d\n", err);
return err;
}
return 0;
}
static int ab3550_i2c_master_recv(struct ab3550 *ab, u8 bank, u8 *data,
u8 count)
{
int err;
err = i2c_master_recv(ab->i2c_client[bank], data, count);
if (err < 0) {
dev_err(&ab->i2c_client[0]->dev, "receive error: %d\n", err);
return err;
}
return 0;
}
/*
* Functionality for getting/setting register values.
*/
static int get_register_interruptible(struct ab3550 *ab, u8 bank, u8 reg,
u8 *value)
{
int err;
err = mutex_lock_interruptible(&ab->access_mutex);
if (err)
return err;
err = ab3550_i2c_master_send(ab, bank, &reg, 1);
if (!err)
err = ab3550_i2c_master_recv(ab, bank, value, 1);
mutex_unlock(&ab->access_mutex);
return err;
}
static int get_register_page_interruptible(struct ab3550 *ab, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
int err;
err = mutex_lock_interruptible(&ab->access_mutex);
if (err)
return err;
err = ab3550_i2c_master_send(ab, bank, &first_reg, 1);
if (!err)
err = ab3550_i2c_master_recv(ab, bank, regvals, numregs);
mutex_unlock(&ab->access_mutex);
return err;
}
static int mask_and_set_register_interruptible(struct ab3550 *ab, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
int err = 0;
if (likely(bitmask)) {
u8 reg_bits[2] = {reg, 0};
err = mutex_lock_interruptible(&ab->access_mutex);
if (err)
return err;
if (bitmask == 0xFF) /* No need to read in this case. */
reg_bits[1] = bitvalues;
else { /* Read and modify the register value. */
u8 bits;
err = ab3550_i2c_master_send(ab, bank, &reg, 1);
if (err)
goto unlock_and_return;
err = ab3550_i2c_master_recv(ab, bank, &bits, 1);
if (err)
goto unlock_and_return;
reg_bits[1] = ((~bitmask & bits) |
(bitmask & bitvalues));
}
/* Write the new value. */
err = ab3550_i2c_master_send(ab, bank, reg_bits, 2);
unlock_and_return:
mutex_unlock(&ab->access_mutex);
}
return err;
}
/*
* Read/write permission checking functions.
*/
static bool page_write_allowed(const struct ab3550_reg_ranges *ranges,
u8 first_reg, u8 last_reg)
{
u8 i;
if (last_reg < first_reg)
return false;
for (i = 0; i < ranges->count; i++) {
if (first_reg < ranges->range[i].first)
break;
if ((last_reg <= ranges->range[i].last) &&
(ranges->range[i].perm & AB3550_PERM_WR))
return true;
}
return false;
}
static bool reg_write_allowed(const struct ab3550_reg_ranges *ranges, u8 reg)
{
return page_write_allowed(ranges, reg, reg);
}
static bool page_read_allowed(const struct ab3550_reg_ranges *ranges,
u8 first_reg, u8 last_reg)
{
u8 i;
if (last_reg < first_reg)
return false;
/* Find the range (if it exists in the list) that includes first_reg. */
for (i = 0; i < ranges->count; i++) {
if (first_reg < ranges->range[i].first)
return false;
if (first_reg <= ranges->range[i].last)
break;
}
/* Make sure that the entire range up to and including last_reg is
* readable. This may span several of the ranges in the list.
*/
while ((i < ranges->count) &&
(ranges->range[i].perm & AB3550_PERM_RD)) {
if (last_reg <= ranges->range[i].last)
return true;
if ((++i >= ranges->count) ||
(ranges->range[i].first !=
(ranges->range[i - 1].last + 1))) {
break;
}
}
return false;
}
static bool reg_read_allowed(const struct ab3550_reg_ranges *ranges, u8 reg)
{
return page_read_allowed(ranges, reg, reg);
}
/*
* The exported register access functionality.
*/
int ab3550_get_chip_id(struct device *dev)
{
struct ab3550 *ab = dev_get_drvdata(dev->parent);
return (int)ab->chip_id;
}
int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
if ((AB3550_NUM_BANKS <= bank) ||
!reg_write_allowed(&ab3550_reg_ranges[pdev->id][bank], reg))
return -EINVAL;
ab = dev_get_drvdata(dev->parent);
return mask_and_set_register_interruptible(ab, bank, reg,
bitmask, bitvalues);
}
int ab3550_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value)
{
return ab3550_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
value);
}
int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 *value)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
if ((AB3550_NUM_BANKS <= bank) ||
!reg_read_allowed(&ab3550_reg_ranges[pdev->id][bank], reg))
return -EINVAL;
ab = dev_get_drvdata(dev->parent);
return get_register_interruptible(ab, bank, reg, value);
}
int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
if ((AB3550_NUM_BANKS <= bank) ||
!page_read_allowed(&ab3550_reg_ranges[pdev->id][bank],
first_reg, (first_reg + numregs - 1)))
return -EINVAL;
ab = dev_get_drvdata(dev->parent);
return get_register_page_interruptible(ab, bank, first_reg, regvals,
numregs);
}
int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
{
struct ab3550 *ab;
ab = dev_get_drvdata(dev->parent);
if (!ab->startup_events_read)
return -EAGAIN; /* Try again later */
memcpy(event, ab->startup_events, AB3550_NUM_EVENT_REG);
return 0;
}
int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
{
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
bool val;
ab = get_irq_chip_data(irq);
plf_data = ab->i2c_client[0]->dev.platform_data;
irq -= plf_data->irq.base;
val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0);
return val;
}
static struct abx500_ops ab3550_ops = {
.get_chip_id = ab3550_get_chip_id,
.get_register = ab3550_get_register_interruptible,
.set_register = ab3550_set_register_interruptible,
.get_register_page = ab3550_get_register_page_interruptible,
.set_register_page = NULL,
.mask_and_set_register = ab3550_mask_and_set_register_interruptible,
.event_registers_startup_state_get =
ab3550_event_registers_startup_state_get,
.startup_irq_enabled = ab3550_startup_irq_enabled,
};
static irqreturn_t ab3550_irq_handler(int irq, void *data)
{
struct ab3550 *ab = data;
int err;
unsigned int i;
u8 e[AB3550_NUM_EVENT_REG];
u8 *events;
unsigned long flags;
events = (ab->startup_events_read ? e : ab->startup_events);
err = get_register_page_interruptible(ab, AB3550_EVENT_BANK,
AB3550_EVENT_REG, events, AB3550_NUM_EVENT_REG);
if (err)
goto err_event_rd;
if (!ab->startup_events_read) {
dev_info(&ab->i2c_client[0]->dev,
"startup events 0x%x,0x%x,0x%x,0x%x,0x%x\n",
ab->startup_events[0], ab->startup_events[1],
ab->startup_events[2], ab->startup_events[3],
ab->startup_events[4]);
ab->startup_events_read = true;
goto out;
}
/* The two highest bits in event[4] are not used. */
events[4] &= 0x3f;
spin_lock_irqsave(&ab->event_lock, flags);
for (i = 0; i < AB3550_NUM_EVENT_REG; i++)
events[i] &= ~ab->event_mask[i];
spin_unlock_irqrestore(&ab->event_lock, flags);
for (i = 0; i < AB3550_NUM_EVENT_REG; i++) {
u8 bit;
u8 event_reg;
dev_dbg(&ab->i2c_client[0]->dev, "IRQ Event[%d]: 0x%2x\n",
i, events[i]);
event_reg = events[i];
for (bit = 0; event_reg; bit++, event_reg /= 2) {
if (event_reg % 2) {
unsigned int irq;
struct ab3550_platform_data *plf_data;
plf_data = ab->i2c_client[0]->dev.platform_data;
irq = plf_data->irq.base + (i * 8) + bit;
handle_nested_irq(irq);
}
}
}
out:
return IRQ_HANDLED;
err_event_rd:
dev_dbg(&ab->i2c_client[0]->dev, "error reading event registers\n");
return IRQ_HANDLED;
}
#ifdef CONFIG_DEBUG_FS
static struct ab3550_reg_ranges debug_ranges[AB3550_NUM_BANKS] = {
{
.count = 6,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x00,
.last = 0x0e,
},
{
.first = 0x10,
.last = 0x1a,
},
{
.first = 0x1e,
.last = 0x4f,
},
{
.first = 0x51,
.last = 0x63,
},
{
.first = 0x65,
.last = 0xa3,
},
{
.first = 0xa5,
.last = 0xa8,
},
}
},
{
.count = 8,
.range = (struct ab3550_reg_range[]) {
{
.first = 0x00,
.last = 0x0e,
},
{
.first = 0x10,
.last = 0x17,
},
{
.first = 0x1a,
.last = 0x1c,
},
{
.first = 0x20,
.last = 0x56,
},
{
.first = 0x5a,
.last = 0x88,
},
{
.first = 0x8a,
.last = 0xad,
},
{
.first = 0xb0,
.last = 0xba,
},
{
.first = 0xbc,
.last = 0xc3,
},
}
},
};
static int ab3550_registers_print(struct seq_file *s, void *p)
{
struct ab3550 *ab = s->private;
int bank;
seq_printf(s, AB3550_NAME_STRING " register values:\n");
for (bank = 0; bank < AB3550_NUM_BANKS; bank++) {
unsigned int i;
seq_printf(s, " bank %d:\n", bank);
for (i = 0; i < debug_ranges[bank].count; i++) {
u8 reg;
for (reg = debug_ranges[bank].range[i].first;
reg <= debug_ranges[bank].range[i].last;
reg++) {
u8 value;
get_register_interruptible(ab, bank, reg,
&value);
seq_printf(s, " [%d/0x%02X]: 0x%02X\n", bank,
reg, value);
}
}
}
return 0;
}
static int ab3550_registers_open(struct inode *inode, struct file *file)
{
return single_open(file, ab3550_registers_print, inode->i_private);
}
static const struct file_operations ab3550_registers_fops = {
.open = ab3550_registers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int ab3550_bank_print(struct seq_file *s, void *p)
{
struct ab3550 *ab = s->private;
seq_printf(s, "%d\n", ab->debug_bank);
return 0;
}
static int ab3550_bank_open(struct inode *inode, struct file *file)
{
return single_open(file, ab3550_bank_print, inode->i_private);
}
static ssize_t ab3550_bank_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
char buf[32];
int buf_size;
unsigned long user_bank;
int err;
/* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf) - 1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = 0;
err = strict_strtoul(buf, 0, &user_bank);
if (err)
return -EINVAL;
if (user_bank >= AB3550_NUM_BANKS) {
dev_err(&ab->i2c_client[0]->dev,
"debugfs error input > number of banks\n");
return -EINVAL;
}
ab->debug_bank = user_bank;
return buf_size;
}
static int ab3550_address_print(struct seq_file *s, void *p)
{
struct ab3550 *ab = s->private;
seq_printf(s, "0x%02X\n", ab->debug_address);
return 0;
}
static int ab3550_address_open(struct inode *inode, struct file *file)
{
return single_open(file, ab3550_address_print, inode->i_private);
}
static ssize_t ab3550_address_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
char buf[32];
int buf_size;
unsigned long user_address;
int err;
/* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf) - 1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = 0;
err = strict_strtoul(buf, 0, &user_address);
if (err)
return -EINVAL;
if (user_address > 0xff) {
dev_err(&ab->i2c_client[0]->dev,
"debugfs error input > 0xff\n");
return -EINVAL;
}
ab->debug_address = user_address;
return buf_size;
}
static int ab3550_val_print(struct seq_file *s, void *p)
{
struct ab3550 *ab = s->private;
int err;
u8 regvalue;
err = get_register_interruptible(ab, (u8)ab->debug_bank,
(u8)ab->debug_address, &regvalue);
if (err)
return -EINVAL;
seq_printf(s, "0x%02X\n", regvalue);
return 0;
}
static int ab3550_val_open(struct inode *inode, struct file *file)
{
return single_open(file, ab3550_val_print, inode->i_private);
}
static ssize_t ab3550_val_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
char buf[32];
int buf_size;
unsigned long user_val;
int err;
u8 regvalue;
/* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = 0;
err = strict_strtoul(buf, 0, &user_val);
if (err)
return -EINVAL;
if (user_val > 0xff) {
dev_err(&ab->i2c_client[0]->dev,
"debugfs error input > 0xff\n");
return -EINVAL;
}
err = mask_and_set_register_interruptible(
ab, (u8)ab->debug_bank,
(u8)ab->debug_address, 0xFF, (u8)user_val);
if (err)
return -EINVAL;
get_register_interruptible(ab, (u8)ab->debug_bank,
(u8)ab->debug_address, &regvalue);
if (err)
return -EINVAL;
return buf_size;
}
static const struct file_operations ab3550_bank_fops = {
.open = ab3550_bank_open,
.write = ab3550_bank_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab3550_address_fops = {
.open = ab3550_address_open,
.write = ab3550_address_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab3550_val_fops = {
.open = ab3550_val_open,
.write = ab3550_val_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static struct dentry *ab3550_dir;
static struct dentry *ab3550_reg_file;
static struct dentry *ab3550_bank_file;
static struct dentry *ab3550_address_file;
static struct dentry *ab3550_val_file;
static inline void ab3550_setup_debugfs(struct ab3550 *ab)
{
ab->debug_bank = 0;
ab->debug_address = 0x00;
ab3550_dir = debugfs_create_dir(AB3550_NAME_STRING, NULL);
if (!ab3550_dir)
goto exit_no_debugfs;
ab3550_reg_file = debugfs_create_file("all-registers",
S_IRUGO, ab3550_dir, ab, &ab3550_registers_fops);
if (!ab3550_reg_file)
goto exit_destroy_dir;
ab3550_bank_file = debugfs_create_file("register-bank",
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops);
if (!ab3550_bank_file)
goto exit_destroy_reg;
ab3550_address_file = debugfs_create_file("register-address",
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops);
if (!ab3550_address_file)
goto exit_destroy_bank;
ab3550_val_file = debugfs_create_file("register-value",
(S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops);
if (!ab3550_val_file)
goto exit_destroy_address;
return;
exit_destroy_address:
debugfs_remove(ab3550_address_file);
exit_destroy_bank:
debugfs_remove(ab3550_bank_file);
exit_destroy_reg:
debugfs_remove(ab3550_reg_file);
exit_destroy_dir:
debugfs_remove(ab3550_dir);
exit_no_debugfs:
dev_err(&ab->i2c_client[0]->dev, "failed to create debugfs entries.\n");
return;
}
static inline void ab3550_remove_debugfs(void)
{
debugfs_remove(ab3550_val_file);
debugfs_remove(ab3550_address_file);
debugfs_remove(ab3550_bank_file);
debugfs_remove(ab3550_reg_file);
debugfs_remove(ab3550_dir);
}
#else /* !CONFIG_DEBUG_FS */
static inline void ab3550_setup_debugfs(struct ab3550 *ab)
{
}
static inline void ab3550_remove_debugfs(void)
{
}
#endif
/*
* Basic set-up, datastructure creation/destruction and I2C interface.
* This sets up a default config in the AB3550 chip so that it
* will work as expected.
*/
static int __init ab3550_setup(struct ab3550 *ab)
{
int err = 0;
int i;
struct ab3550_platform_data *plf_data;
struct abx500_init_settings *settings;
plf_data = ab->i2c_client[0]->dev.platform_data;
settings = plf_data->init_settings;
for (i = 0; i < plf_data->init_settings_sz; i++) {
err = mask_and_set_register_interruptible(ab,
settings[i].bank,
settings[i].reg,
0xFF, settings[i].setting);
if (err)
goto exit_no_setup;
/* If event mask register update the event mask in ab3550 */
if ((settings[i].bank == 0) &&
(AB3550_IMR1 <= settings[i].reg) &&
(settings[i].reg <= AB3550_IMR5)) {
ab->event_mask[settings[i].reg - AB3550_IMR1] =
settings[i].setting;
}
}
exit_no_setup:
return err;
}
static void ab3550_mask_work(struct work_struct *work)
{
struct ab3550 *ab = container_of(work, struct ab3550, mask_work);
int i;
unsigned long flags;
u8 mask[AB3550_NUM_EVENT_REG];
spin_lock_irqsave(&ab->event_lock, flags);
for (i = 0; i < AB3550_NUM_EVENT_REG; i++)
mask[i] = ab->event_mask[i];
spin_unlock_irqrestore(&ab->event_lock, flags);
for (i = 0; i < AB3550_NUM_EVENT_REG; i++) {
int err;
err = mask_and_set_register_interruptible(ab, 0,
(AB3550_IMR1 + i), ~0, mask[i]);
if (err)
dev_err(&ab->i2c_client[0]->dev,
"ab3550_mask_work failed 0x%x,0x%x\n",
(AB3550_IMR1 + i), mask[i]);
}
}
static void ab3550_mask(unsigned int irq)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
ab = get_irq_chip_data(irq);
plf_data = ab->i2c_client[0]->dev.platform_data;
irq -= plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] |= BIT(irq % 8);
spin_unlock_irqrestore(&ab->event_lock, flags);
schedule_work(&ab->mask_work);
}
static void ab3550_unmask(unsigned int irq)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
ab = get_irq_chip_data(irq);
plf_data = ab->i2c_client[0]->dev.platform_data;
irq -= plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] &= ~BIT(irq % 8);
spin_unlock_irqrestore(&ab->event_lock, flags);
schedule_work(&ab->mask_work);
}
static void noop(unsigned int irq)
{
}
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,
};
struct ab_family_id {
u8 id;
char *name;
};
static const struct ab_family_id ids[] __initdata = {
/* AB3550 */
{
.id = AB3550_P1A,
.name = "P1A"
},
/* Terminator */
{
.id = 0x00,
}
};
static int __init ab3550_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ab3550 *ab;
struct ab3550_platform_data *ab3550_plf_data =
client->dev.platform_data;
int err;
int i;
int num_i2c_clients = 0;
ab = kzalloc(sizeof(struct ab3550), GFP_KERNEL);
if (!ab) {
dev_err(&client->dev,
"could not allocate " AB3550_NAME_STRING " device\n");
return -ENOMEM;
}
/* Initialize data structure */
mutex_init(&ab->access_mutex);
spin_lock_init(&ab->event_lock);
ab->i2c_client[0] = client;
i2c_set_clientdata(client, ab);
/* Read chip ID register */
err = get_register_interruptible(ab, 0, AB3550_CID_REG, &ab->chip_id);
if (err) {
dev_err(&client->dev, "could not communicate with the analog "
"baseband chip\n");
goto exit_no_detect;
}
for (i = 0; ids[i].id != 0x0; i++) {
if (ids[i].id == ab->chip_id) {
snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1,
AB3550_ID_FORMAT_STRING, ids[i].name);
break;
}
}
if (ids[i].id == 0x0) {
dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n",
ab->chip_id);
dev_err(&client->dev, "driver not started!\n");
goto exit_no_detect;
}
dev_info(&client->dev, "detected AB chip: %s\n", &ab->chip_name[0]);
/* Attach other dummy I2C clients. */
while (++num_i2c_clients < AB3550_NUM_BANKS) {
ab->i2c_client[num_i2c_clients] =
i2c_new_dummy(client->adapter,
(client->addr + num_i2c_clients));
if (!ab->i2c_client[num_i2c_clients]) {
err = -ENOMEM;
goto exit_no_dummy_client;
}
strlcpy(ab->i2c_client[num_i2c_clients]->name, id->name,
sizeof(ab->i2c_client[num_i2c_clients]->name));
}
err = ab3550_setup(ab);
if (err)
goto exit_no_setup;
INIT_WORK(&ab->mask_work, ab3550_mask_work);
for (i = 0; i < ab3550_plf_data->irq.count; i++) {
unsigned int irq;
irq = ab3550_plf_data->irq.base + i;
set_irq_chip_data(irq, ab);
set_irq_chip_and_handler(irq, &ab3550_irq_chip,
handle_simple_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
err = request_threaded_irq(client->irq, NULL, ab3550_irq_handler,
IRQF_ONESHOT, "ab3550-core", ab);
/* This real unpredictable IRQ is of course sampled for entropy */
rand_initialize_irq(client->irq);
if (err)
goto exit_no_irq;
err = abx500_register_ops(&client->dev, &ab3550_ops);
if (err)
goto exit_no_ops;
/* Set up and register the platform devices. */
for (i = 0; i < AB3550_NUM_DEVICES; i++) {
ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i];
}
err = mfd_add_devices(&client->dev, 0, ab3550_devs,
ARRAY_SIZE(ab3550_devs), NULL,
ab3550_plf_data->irq.base);
ab3550_setup_debugfs(ab);
return 0;
exit_no_ops:
exit_no_irq:
exit_no_setup:
exit_no_dummy_client:
/* Unregister the dummy i2c clients. */
while (--num_i2c_clients)
i2c_unregister_device(ab->i2c_client[num_i2c_clients]);
exit_no_detect:
kfree(ab);
return err;
}
static int __exit ab3550_remove(struct i2c_client *client)
{
struct ab3550 *ab = i2c_get_clientdata(client);
int num_i2c_clients = AB3550_NUM_BANKS;
mfd_remove_devices(&client->dev);
ab3550_remove_debugfs();
while (--num_i2c_clients)
i2c_unregister_device(ab->i2c_client[num_i2c_clients]);
/*
* At this point, all subscribers should have unregistered
* their notifiers so deactivate IRQ
*/
free_irq(client->irq, ab);
i2c_set_clientdata(client, NULL);
kfree(ab);
return 0;
}
static const struct i2c_device_id ab3550_id[] = {
{AB3550_NAME_STRING, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ab3550_id);
static struct i2c_driver ab3550_driver = {
.driver = {
.name = AB3550_NAME_STRING,
.owner = THIS_MODULE,
},
.id_table = ab3550_id,
.probe = ab3550_probe,
.remove = __exit_p(ab3550_remove),
};
static int __init ab3550_i2c_init(void)
{
return i2c_add_driver(&ab3550_driver);
}
static void __exit ab3550_i2c_exit(void)
{
i2c_del_driver(&ab3550_driver);
}
subsys_initcall(ab3550_i2c_init);
module_exit(ab3550_i2c_exit);
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
MODULE_DESCRIPTION("AB3550 core driver");
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2009 ST-Ericsson
*
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
*
* 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.
*
* AB4500 is a companion power management chip used with U8500.
* On this platform, this is interfaced with SSP0 controller
* which is a ARM primecell pl022.
*
* At the moment the module just exports read/write features.
* Interrupt management to be added - TODO.
*/
#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/ab4500.h>
/* just required if probe fails, we need to
* unregister the device
*/
static struct spi_driver ab4500_driver;
/*
* This funtion writes to any AB4500 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
*/
int ab4500_write(struct ab4500 *ab4500, unsigned char block,
unsigned long addr, unsigned char data)
{
struct spi_transfer xfer;
struct spi_message msg;
int err;
unsigned long spi_data =
block << 18 | addr << 10 | data;
mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;
xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = NULL;
xfer.len = sizeof(unsigned long);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
err = spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);
return err;
}
EXPORT_SYMBOL(ab4500_write);
int ab4500_read(struct ab4500 *ab4500, unsigned char block,
unsigned long addr)
{
struct spi_transfer xfer;
struct spi_message msg;
unsigned long spi_data =
1 << 23 | block << 18 | addr << 10;
mutex_lock(&ab4500->lock);
ab4500->tx_buf[0] = spi_data;
ab4500->rx_buf[0] = 0;
xfer.tx_buf = ab4500->tx_buf;
xfer.rx_buf = ab4500->rx_buf;
xfer.len = sizeof(unsigned long);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
spi_sync(ab4500->spi, &msg);
mutex_unlock(&ab4500->lock);
return ab4500->rx_buf[0];
}
EXPORT_SYMBOL(ab4500_read);
/* ref: ab3100 core */
#define AB4500_DEVICE(devname, devid) \
static struct platform_device ab4500_##devname##_device = { \
.name = devid, \
.id = -1, \
}
/* list of childern devices of ab4500 - all are
* not populated here - TODO
*/
AB4500_DEVICE(charger, "ab4500-charger");
AB4500_DEVICE(audio, "ab4500-audio");
AB4500_DEVICE(usb, "ab4500-usb");
AB4500_DEVICE(tvout, "ab4500-tvout");
AB4500_DEVICE(sim, "ab4500-sim");
AB4500_DEVICE(gpadc, "ab4500-gpadc");
AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
AB4500_DEVICE(misc, "ab4500-misc");
static struct platform_device *ab4500_platform_devs[] = {
&ab4500_charger_device,
&ab4500_audio_device,
&ab4500_usb_device,
&ab4500_tvout_device,
&ab4500_sim_device,
&ab4500_gpadc_device,
&ab4500_clkmgt_device,
&ab4500_misc_device,
};
static int __init ab4500_probe(struct spi_device *spi)
{
struct ab4500 *ab4500;
unsigned char revision;
int err = 0;
int i;
ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
if (!ab4500) {
dev_err(&spi->dev, "could not allocate AB4500\n");
err = -ENOMEM;
goto not_detect;
}
ab4500->spi = spi;
spi_set_drvdata(spi, ab4500);
mutex_init(&ab4500->lock);
/* read the revision register */
revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);
/* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
if (revision == 0x0 || revision == 0x10)
dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
ab4500_driver.driver.name, revision);
else {
dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
goto not_detect;
}
for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) {
ab4500_platform_devs[i]->dev.parent =
&spi->dev;
platform_set_drvdata(ab4500_platform_devs[i], ab4500);
}
/* register the ab4500 platform devices */
platform_add_devices(ab4500_platform_devs,
ARRAY_SIZE(ab4500_platform_devs));
return err;
not_detect:
spi_unregister_driver(&ab4500_driver);
kfree(ab4500);
return err;
}
static int __devexit ab4500_remove(struct spi_device *spi)
{
struct ab4500 *ab4500 =
spi_get_drvdata(spi);
kfree(ab4500);
return 0;
}
static struct spi_driver ab4500_driver = {
.driver = {
.name = "ab4500",
.owner = THIS_MODULE,
},
.probe = ab4500_probe,
.remove = __devexit_p(ab4500_remove)
};
static int __devinit ab4500_init(void)
{
return spi_register_driver(&ab4500_driver);
}
static void __exit ab4500_exit(void)
{
spi_unregister_driver(&ab4500_driver);
}
subsys_initcall(ab4500_init);
module_exit(ab4500_exit);
MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
MODULE_DESCRIPTION("AB4500 core driver");
MODULE_LICENSE("GPL");
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
* Author: Rabin Vincent <rabin.vincent@stericsson.com>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ab8500.h>
/*
* Interrupt register offsets
* Bank : 0x0E
*/
#define AB8500_IT_SOURCE1_REG 0x0E00
#define AB8500_IT_SOURCE2_REG 0x0E01
#define AB8500_IT_SOURCE3_REG 0x0E02
#define AB8500_IT_SOURCE4_REG 0x0E03
#define AB8500_IT_SOURCE5_REG 0x0E04
#define AB8500_IT_SOURCE6_REG 0x0E05
#define AB8500_IT_SOURCE7_REG 0x0E06
#define AB8500_IT_SOURCE8_REG 0x0E07
#define AB8500_IT_SOURCE19_REG 0x0E12
#define AB8500_IT_SOURCE20_REG 0x0E13
#define AB8500_IT_SOURCE21_REG 0x0E14
#define AB8500_IT_SOURCE22_REG 0x0E15
#define AB8500_IT_SOURCE23_REG 0x0E16
#define AB8500_IT_SOURCE24_REG 0x0E17
/*
* latch registers
*/
#define AB8500_IT_LATCH1_REG 0x0E20
#define AB8500_IT_LATCH2_REG 0x0E21
#define AB8500_IT_LATCH3_REG 0x0E22
#define AB8500_IT_LATCH4_REG 0x0E23
#define AB8500_IT_LATCH5_REG 0x0E24
#define AB8500_IT_LATCH6_REG 0x0E25
#define AB8500_IT_LATCH7_REG 0x0E26
#define AB8500_IT_LATCH8_REG 0x0E27
#define AB8500_IT_LATCH9_REG 0x0E28
#define AB8500_IT_LATCH10_REG 0x0E29
#define AB8500_IT_LATCH19_REG 0x0E32
#define AB8500_IT_LATCH20_REG 0x0E33
#define AB8500_IT_LATCH21_REG 0x0E34
#define AB8500_IT_LATCH22_REG 0x0E35
#define AB8500_IT_LATCH23_REG 0x0E36
#define AB8500_IT_LATCH24_REG 0x0E37
/*
* mask registers
*/
#define AB8500_IT_MASK1_REG 0x0E40
#define AB8500_IT_MASK2_REG 0x0E41
#define AB8500_IT_MASK3_REG 0x0E42
#define AB8500_IT_MASK4_REG 0x0E43
#define AB8500_IT_MASK5_REG 0x0E44
#define AB8500_IT_MASK6_REG 0x0E45
#define AB8500_IT_MASK7_REG 0x0E46
#define AB8500_IT_MASK8_REG 0x0E47
#define AB8500_IT_MASK9_REG 0x0E48
#define AB8500_IT_MASK10_REG 0x0E49
#define AB8500_IT_MASK11_REG 0x0E4A
#define AB8500_IT_MASK12_REG 0x0E4B
#define AB8500_IT_MASK13_REG 0x0E4C
#define AB8500_IT_MASK14_REG 0x0E4D
#define AB8500_IT_MASK15_REG 0x0E4E
#define AB8500_IT_MASK16_REG 0x0E4F
#define AB8500_IT_MASK17_REG 0x0E50
#define AB8500_IT_MASK18_REG 0x0E51
#define AB8500_IT_MASK19_REG 0x0E52
#define AB8500_IT_MASK20_REG 0x0E53
#define AB8500_IT_MASK21_REG 0x0E54
#define AB8500_IT_MASK22_REG 0x0E55
#define AB8500_IT_MASK23_REG 0x0E56
#define AB8500_IT_MASK24_REG 0x0E57
#define AB8500_REV_REG 0x1080
/*
* Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
* numbers are indexed into this array with (num / 8).
*
* This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
* 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,
};
static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
int ret;
dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
ret = ab8500->write(ab8500, addr, data);
if (ret < 0)
dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
addr, ret);
return ret;
}
/**
* ab8500_write() - write an AB8500 register
* @ab8500: device to write to
* @addr: address of the register
* @data: value to write
*/
int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
int ret;
mutex_lock(&ab8500->lock);
ret = __ab8500_write(ab8500, addr, data);
mutex_unlock(&ab8500->lock);
return ret;
}
EXPORT_SYMBOL_GPL(ab8500_write);
static int __ab8500_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
ret = ab8500->read(ab8500, addr);
if (ret < 0)
dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
addr, ret);
dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
return ret;
}
/**
* ab8500_read() - read an AB8500 register
* @ab8500: device to read from
* @addr: address of the register
*/
int ab8500_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
mutex_lock(&ab8500->lock);
ret = __ab8500_read(ab8500, addr);
mutex_unlock(&ab8500->lock);
return ret;
}
EXPORT_SYMBOL_GPL(ab8500_read);
/**
* ab8500_set_bits() - set a bitfield in an AB8500 register
* @ab8500: device to read from
* @addr: address of the register
* @mask: mask of the bitfield to modify
* @data: value to set to the bitfield
*/
int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data)
{
int ret;
mutex_lock(&ab8500->lock);
ret = __ab8500_read(ab8500, addr);
if (ret < 0)
goto out;
ret &= ~mask;
ret |= data;
ret = __ab8500_write(ab8500, addr, ret);
out:
mutex_unlock(&ab8500->lock);
return ret;
}
EXPORT_SYMBOL_GPL(ab8500_set_bits);
static void ab8500_irq_lock(unsigned int irq)
{
struct ab8500 *ab8500 = get_irq_chip_data(irq);
mutex_lock(&ab8500->irq_lock);
}
static void ab8500_irq_sync_unlock(unsigned int irq)
{
struct ab8500 *ab8500 = get_irq_chip_data(irq);
int i;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
u8 old = ab8500->oldmask[i];
u8 new = ab8500->mask[i];
int reg;
if (new == old)
continue;
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
ab8500_write(ab8500, reg, new);
}
mutex_unlock(&ab8500->irq_lock);
}
static void ab8500_irq_mask(unsigned int irq)
{
struct ab8500 *ab8500 = get_irq_chip_data(irq);
int offset = 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)
{
struct ab8500 *ab8500 = get_irq_chip_data(irq);
int offset = irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
ab8500->mask[index] &= ~mask;
}
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,
};
static irqreturn_t ab8500_irq(int irq, void *dev)
{
struct ab8500 *ab8500 = dev;
int i;
dev_vdbg(ab8500->dev, "interrupt\n");
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
int regoffset = ab8500_irq_regoffset[i];
int status;
status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset);
if (status <= 0)
continue;
do {
int bit = __ffs(status);
int line = i * 8 + bit;
handle_nested_irq(ab8500->irq_base + line);
status &= ~(1 << bit);
} while (status);
}
return IRQ_HANDLED;
}
static int ab8500_irq_init(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
set_irq_chip_data(irq, ab8500);
set_irq_chip_and_handler(irq, &ab8500_irq_chip,
handle_simple_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void ab8500_irq_remove(struct ab8500 *ab8500)
{
int base = ab8500->irq_base;
int irq;
for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static struct resource ab8500_gpadc_resources[] = {
{
.name = "HW_CONV_END",
.start = AB8500_INT_GP_HW_ADC_CONV_END,
.end = AB8500_INT_GP_HW_ADC_CONV_END,
.flags = IORESOURCE_IRQ,
},
{
.name = "SW_CONV_END",
.start = AB8500_INT_GP_SW_ADC_CONV_END,
.end = AB8500_INT_GP_SW_ADC_CONV_END,
.flags = IORESOURCE_IRQ,
},
};
static struct resource ab8500_rtc_resources[] = {
{
.name = "60S",
.start = AB8500_INT_RTC_60S,
.end = AB8500_INT_RTC_60S,
.flags = IORESOURCE_IRQ,
},
{
.name = "ALARM",
.start = AB8500_INT_RTC_ALARM,
.end = AB8500_INT_RTC_ALARM,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell ab8500_devs[] = {
{
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
},
{
.name = "ab8500-rtc",
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
.resources = ab8500_rtc_resources,
},
{ .name = "ab8500-charger", },
{ .name = "ab8500-audio", },
{ .name = "ab8500-usb", },
{ .name = "ab8500-pwm", },
};
int __devinit ab8500_init(struct ab8500 *ab8500)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
int ret;
int i;
if (plat)
ab8500->irq_base = plat->irq_base;
mutex_init(&ab8500->lock);
mutex_init(&ab8500->irq_lock);
ret = ab8500_read(ab8500, AB8500_REV_REG);
if (ret < 0)
return ret;
/*
* 0x0 - Early Drop
* 0x10 - Cut 1.0
* 0x11 - Cut 1.1
*/
if (ret == 0x0 || ret == 0x10 || ret == 0x11) {
ab8500->revision = ret;
dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret);
} else {
dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret);
return -EINVAL;
}
if (plat && plat->init)
plat->init(ab8500);
/* Clear and mask all interrupts */
for (i = 0; i < 10; i++) {
ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
}
for (i = 18; i < 24; i++) {
ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i);
ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff);
}
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
if (ab8500->irq_base) {
ret = ab8500_irq_init(ab8500);
if (ret)
return ret;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
IRQF_ONESHOT, "ab8500", ab8500);
if (ret)
goto out_removeirq;
}
ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
return ret;
out_freeirq:
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
out_removeirq:
ab8500_irq_remove(ab8500);
}
return ret;
}
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
ab8500_irq_remove(ab8500);
}
return 0;
}
MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent");
MODULE_DESCRIPTION("AB8500 MFD core");
MODULE_LICENSE("GPL v2");
/*
* 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)
ret = ab8500->rx_buf[0];
return ret;
}
static int __devinit ab8500_spi_probe(struct spi_device *spi)
{
struct ab8500 *ab8500;
int 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",
.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");
/*
* Copyright (C) 2007-2010 ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
* Register access functions for the ABX500 Mixed Signal IC family.
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
*/
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/mfd/abx500.h>
static LIST_HEAD(abx500_list);
struct abx500_device_entry {
struct list_head list;
struct abx500_ops ops;
struct device *dev;
};
static void lookup_ops(struct device *dev, struct abx500_ops **ops)
{
struct abx500_device_entry *dev_entry;
*ops = NULL;
list_for_each_entry(dev_entry, &abx500_list, list) {
if (dev_entry->dev == dev) {
*ops = &dev_entry->ops;
return;
}
}
}
int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
{
struct abx500_device_entry *dev_entry;
dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
if (IS_ERR(dev_entry)) {
dev_err(dev, "register_ops kzalloc failed");
return -ENOMEM;
}
dev_entry->dev = dev;
memcpy(&dev_entry->ops, ops, sizeof(struct abx500_ops));
list_add_tail(&dev_entry->list, &abx500_list);
return 0;
}
EXPORT_SYMBOL(abx500_register_ops);
void abx500_remove_ops(struct device *dev)
{
struct abx500_device_entry *dev_entry, *tmp;
list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list)
{
if (dev_entry->dev == dev) {
list_del(&dev_entry->list);
kfree(dev_entry);
}
}
}
EXPORT_SYMBOL(abx500_remove_ops);
int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->set_register != NULL))
return ops->set_register(dev, bank, reg, value);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_set_register_interruptible);
int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 *value)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->get_register != NULL))
return ops->get_register(dev, bank, reg, value);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_get_register_interruptible);
int abx500_get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->get_register_page != NULL))
return ops->get_register_page(dev, bank,
first_reg, regvals, numregs);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_get_register_page_interruptible);
int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->mask_and_set_register != NULL))
return ops->mask_and_set_register(dev, bank,
reg, bitmask, bitvalues);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_mask_and_set_register_interruptible);
int abx500_get_chip_id(struct device *dev)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->get_chip_id != NULL))
return ops->get_chip_id(dev);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_get_chip_id);
int abx500_event_registers_startup_state_get(struct device *dev, u8 *event)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->event_registers_startup_state_get != NULL))
return ops->event_registers_startup_state_get(dev, event);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_event_registers_startup_state_get);
int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
{
struct abx500_ops *ops;
lookup_ops(dev->parent, &ops);
if ((ops != NULL) && (ops->startup_irq_enabled != NULL))
return ops->startup_irq_enabled(dev, irq);
else
return -ENOTSUPP;
}
EXPORT_SYMBOL(abx500_startup_irq_enabled);
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
MODULE_DESCRIPTION("ABX500 core driver");
MODULE_LICENSE("GPL");
...@@ -544,6 +544,7 @@ static int __devexit da903x_remove(struct i2c_client *client) ...@@ -544,6 +544,7 @@ static int __devexit da903x_remove(struct i2c_client *client)
struct da903x_chip *chip = i2c_get_clientdata(client); struct da903x_chip *chip = i2c_get_clientdata(client);
da903x_remove_subdevs(chip); da903x_remove_subdevs(chip);
i2c_set_clientdata(client, NULL);
kfree(chip); kfree(chip);
return 0; return 0;
} }
......
/*
* Janz CMOD-IO MODULbus Carrier Board PCI Driver
*
* Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
*
* Lots of inspiration and code was copied from drivers/mfd/sm501.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/janz.h>
#define DRV_NAME "janz-cmodio"
/* Size of each MODULbus module in PCI BAR4 */
#define CMODIO_MODULBUS_SIZE 0x200
/* Maximum number of MODULbus modules on a CMOD-IO carrier board */
#define CMODIO_MAX_MODULES 4
/* Module Parameters */
static unsigned int num_modules = CMODIO_MAX_MODULES;
static unsigned char *modules[CMODIO_MAX_MODULES] = {
"empty", "empty", "empty", "empty",
};
module_param_array(modules, charp, &num_modules, S_IRUGO);
MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
/* Unique Device Id */
static unsigned int cmodio_id;
struct cmodio_device {
/* Parent PCI device */
struct pci_dev *pdev;
/* PLX control registers */
struct janz_cmodio_onboard_regs __iomem *ctrl;
/* hex switch position */
u8 hex;
/* mfd-core API */
struct mfd_cell cells[CMODIO_MAX_MODULES];
struct resource resources[3 * CMODIO_MAX_MODULES];
struct janz_platform_data pdata[CMODIO_MAX_MODULES];
};
/*
* Subdevices using the mfd-core API
*/
static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
char *name, unsigned int devno,
unsigned int modno)
{
struct janz_platform_data *pdata;
struct mfd_cell *cell;
struct resource *res;
struct pci_dev *pci;
pci = priv->pdev;
cell = &priv->cells[devno];
res = &priv->resources[devno * 3];
pdata = &priv->pdata[devno];
cell->name = name;
cell->resources = res;
cell->num_resources = 3;
/* Setup the subdevice ID -- must be unique */
cell->id = cmodio_id++;
/* Add platform data */
pdata->modno = modno;
cell->platform_data = pdata;
cell->data_size = sizeof(*pdata);
/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
res->flags = IORESOURCE_MEM;
res->parent = &pci->resource[3];
res->start = pci->resource[3].start + (CMODIO_MODULBUS_SIZE * modno);
res->end = res->start + CMODIO_MODULBUS_SIZE - 1;
res++;
/* PLX Control Registers -- PCI BAR4 is interrupt and other registers */
res->flags = IORESOURCE_MEM;
res->parent = &pci->resource[4];
res->start = pci->resource[4].start;
res->end = pci->resource[4].end;
res++;
/*
* IRQ
*
* The start and end fields are used as an offset to the irq_base
* parameter passed into the mfd_add_devices() function call. All
* devices share the same IRQ.
*/
res->flags = IORESOURCE_IRQ;
res->parent = NULL;
res->start = 0;
res->end = 0;
res++;
return 0;
}
/* Probe each submodule using kernel parameters */
static int __devinit cmodio_probe_submodules(struct cmodio_device *priv)
{
struct pci_dev *pdev = priv->pdev;
unsigned int num_probed = 0;
char *name;
int i;
for (i = 0; i < num_modules; i++) {
name = modules[i];
if (!strcmp(name, "") || !strcmp(name, "empty"))
continue;
dev_dbg(&priv->pdev->dev, "MODULbus %d: name %s\n", i, name);
cmodio_setup_subdevice(priv, name, num_probed, i);
num_probed++;
}
/* print an error message if no modules were probed */
if (num_probed == 0) {
dev_err(&priv->pdev->dev, "no MODULbus modules specified, "
"please set the ``modules'' kernel "
"parameter according to your "
"hardware configuration\n");
return -ENODEV;
}
return mfd_add_devices(&pdev->dev, 0, priv->cells,
num_probed, NULL, pdev->irq);
}
/*
* SYSFS Attributes
*/
static ssize_t mbus_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct cmodio_device *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%x\n", priv->hex);
}
static DEVICE_ATTR(modulbus_number, S_IRUGO, mbus_show, NULL);
static struct attribute *cmodio_sysfs_attrs[] = {
&dev_attr_modulbus_number.attr,
NULL,
};
static const struct attribute_group cmodio_sysfs_attr_group = {
.attrs = cmodio_sysfs_attrs,
};
/*
* PCI Driver
*/
static int __devinit cmodio_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct cmodio_device *priv;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&dev->dev, "unable to allocate private data\n");
ret = -ENOMEM;
goto out_return;
}
pci_set_drvdata(dev, priv);
priv->pdev = dev;
/* Hardware Initialization */
ret = pci_enable_device(dev);
if (ret) {
dev_err(&dev->dev, "unable to enable device\n");
goto out_free_priv;
}
pci_set_master(dev);
ret = pci_request_regions(dev, DRV_NAME);
if (ret) {
dev_err(&dev->dev, "unable to request regions\n");
goto out_pci_disable_device;
}
/* Onboard configuration registers */
priv->ctrl = pci_ioremap_bar(dev, 4);
if (!priv->ctrl) {
dev_err(&dev->dev, "unable to remap onboard regs\n");
ret = -ENOMEM;
goto out_pci_release_regions;
}
/* Read the hex switch on the carrier board */
priv->hex = ioread8(&priv->ctrl->int_enable);
/* Add the MODULbus number (hex switch value) to the device's sysfs */
ret = sysfs_create_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
if (ret) {
dev_err(&dev->dev, "unable to create sysfs attributes\n");
goto out_unmap_ctrl;
}
/*
* Disable all interrupt lines, each submodule will enable its
* own interrupt line if needed
*/
iowrite8(0xf, &priv->ctrl->int_disable);
/* Register drivers for all submodules */
ret = cmodio_probe_submodules(priv);
if (ret) {
dev_err(&dev->dev, "unable to probe submodules\n");
goto out_sysfs_remove_group;
}
return 0;
out_sysfs_remove_group:
sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
out_unmap_ctrl:
iounmap(priv->ctrl);
out_pci_release_regions:
pci_release_regions(dev);
out_pci_disable_device:
pci_disable_device(dev);
out_free_priv:
kfree(priv);
out_return:
return ret;
}
static void __devexit cmodio_pci_remove(struct pci_dev *dev)
{
struct cmodio_device *priv = pci_get_drvdata(dev);
mfd_remove_devices(&dev->dev);
sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
iounmap(priv->ctrl);
pci_release_regions(dev);
pci_disable_device(dev);
kfree(priv);
}
#define PCI_VENDOR_ID_JANZ 0x13c3
/* The list of devices that this module will support */
static DEFINE_PCI_DEVICE_TABLE(cmodio_pci_ids) = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
static struct pci_driver cmodio_pci_driver = {
.name = DRV_NAME,
.id_table = cmodio_pci_ids,
.probe = cmodio_pci_probe,
.remove = __devexit_p(cmodio_pci_remove),
};
/*
* Module Init / Exit
*/
static int __init cmodio_init(void)
{
return pci_register_driver(&cmodio_pci_driver);
}
static void __exit cmodio_exit(void)
{
pci_unregister_driver(&cmodio_pci_driver);
}
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
MODULE_LICENSE("GPL");
module_init(cmodio_init);
module_exit(cmodio_exit);
...@@ -508,7 +508,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, ...@@ -508,7 +508,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2); max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2);
max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ); max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ);
max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); max8925_reg_read(chip->adc, MAX8925_TSC_IRQ);
/* mask all interrupts */ /* mask all interrupts except for TSC */
max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0); max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0);
max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0); max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0);
max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff); max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff);
...@@ -516,7 +516,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, ...@@ -516,7 +516,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff); max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff);
max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff); max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff);
max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff); max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff);
max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0xff);
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
chip->core_irq = irq; chip->core_irq = irq;
...@@ -547,7 +546,11 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, ...@@ -547,7 +546,11 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq,
dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret);
chip->core_irq = 0; chip->core_irq = 0;
} }
tsc_irq: tsc_irq:
/* mask TSC interrupt */
max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0x0f);
if (!pdata->tsc_irq) { if (!pdata->tsc_irq) {
dev_warn(chip->dev, "No interrupt support on TSC IRQ\n"); dev_warn(chip->dev, "No interrupt support on TSC IRQ\n");
return 0; return 0;
......
...@@ -173,8 +173,6 @@ static int __devexit max8925_remove(struct i2c_client *client) ...@@ -173,8 +173,6 @@ static int __devexit max8925_remove(struct i2c_client *client)
max8925_device_exit(chip); max8925_device_exit(chip);
i2c_unregister_device(chip->adc); i2c_unregister_device(chip->adc);
i2c_unregister_device(chip->rtc); i2c_unregister_device(chip->rtc);
i2c_set_clientdata(chip->adc, NULL);
i2c_set_clientdata(chip->rtc, NULL);
i2c_set_clientdata(chip->i2c, NULL); i2c_set_clientdata(chip->i2c, NULL);
kfree(chip); kfree(chip);
return 0; return 0;
......
...@@ -1228,6 +1228,7 @@ static int menelaus_probe(struct i2c_client *client, ...@@ -1228,6 +1228,7 @@ static int menelaus_probe(struct i2c_client *client,
free_irq(client->irq, menelaus); free_irq(client->irq, menelaus);
flush_scheduled_work(); flush_scheduled_work();
fail1: fail1:
i2c_set_clientdata(client, NULL);
kfree(menelaus); kfree(menelaus);
return err; return err;
} }
...@@ -1237,8 +1238,8 @@ static int __exit menelaus_remove(struct i2c_client *client) ...@@ -1237,8 +1238,8 @@ static int __exit menelaus_remove(struct i2c_client *client)
struct menelaus_chip *menelaus = i2c_get_clientdata(client); struct menelaus_chip *menelaus = i2c_get_clientdata(client);
free_irq(client->irq, menelaus); free_irq(client->irq, menelaus);
kfree(menelaus);
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(menelaus);
the_menelaus = NULL; the_menelaus = NULL;
return 0; return 0;
} }
......
...@@ -48,7 +48,7 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -48,7 +48,7 @@ static int mfd_add_device(struct device *parent, int id,
res[r].flags = cell->resources[r].flags; res[r].flags = cell->resources[r].flags;
/* Find out base to use */ /* Find out base to use */
if (cell->resources[r].flags & IORESOURCE_MEM) { if ((cell->resources[r].flags & IORESOURCE_MEM) && mem_base) {
res[r].parent = mem_base; res[r].parent = mem_base;
res[r].start = mem_base->start + res[r].start = mem_base->start +
cell->resources[r].start; cell->resources[r].start;
......
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
struct pcf50633_adc_request { struct pcf50633_adc_request {
int mux; int mux;
int avg; int avg;
int result;
void (*callback)(struct pcf50633 *, void *, int); void (*callback)(struct pcf50633 *, void *, int);
void *callback_param; void *callback_param;
};
/* Used in case of sync requests */ struct pcf50633_adc_sync_request {
int result;
struct completion completion; struct completion completion;
}; };
#define PCF50633_MAX_ADC_FIFO_DEPTH 8 #define PCF50633_MAX_ADC_FIFO_DEPTH 8
...@@ -109,10 +109,10 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) ...@@ -109,10 +109,10 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
return 0; return 0;
} }
static void static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param,
pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) int result)
{ {
struct pcf50633_adc_request *req = param; struct pcf50633_adc_sync_request *req = param;
req->result = result; req->result = result;
complete(&req->completion); complete(&req->completion);
...@@ -120,28 +120,19 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) ...@@ -120,28 +120,19 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result)
int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
{ {
struct pcf50633_adc_request *req; struct pcf50633_adc_sync_request req;
int err; int ret;
/* req is freed when the result is ready, in interrupt handler */ init_completion(&req.completion);
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
req->mux = mux;
req->avg = avg;
req->callback = pcf50633_adc_sync_read_callback;
req->callback_param = req;
init_completion(&req->completion); ret = pcf50633_adc_async_read(pcf, mux, avg,
err = adc_enqueue_request(pcf, req); pcf50633_adc_sync_read_callback, &req);
if (err) if (ret)
return err; return ret;
wait_for_completion(&req->completion); wait_for_completion(&req.completion);
/* FIXME by this time req might be already freed */ return req.result;
return req->result;
} }
EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
......
...@@ -21,16 +21,16 @@ ...@@ -21,16 +21,16 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/pcf50633/core.h> #include <linux/mfd/pcf50633/core.h>
/* Two MBCS registers used during cold start */ int pcf50633_irq_init(struct pcf50633 *pcf, int irq);
#define PCF50633_REG_MBCS1 0x4b void pcf50633_irq_free(struct pcf50633 *pcf);
#define PCF50633_REG_MBCS2 0x4c #ifdef CONFIG_PM
#define PCF50633_MBCS1_USBPRES 0x01 int pcf50633_irq_suspend(struct pcf50633 *pcf);
#define PCF50633_MBCS1_ADAPTPRES 0x01 int pcf50633_irq_resume(struct pcf50633 *pcf);
#endif
static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
{ {
...@@ -215,244 +215,6 @@ static struct attribute_group pcf_attr_group = { ...@@ -215,244 +215,6 @@ static struct attribute_group pcf_attr_group = {
.attrs = pcf_sysfs_entries, .attrs = pcf_sysfs_entries,
}; };
int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
void (*handler) (int, void *), void *data)
{
if (irq < 0 || irq > PCF50633_NUM_IRQ || !handler)
return -EINVAL;
if (WARN_ON(pcf->irq_handler[irq].handler))
return -EBUSY;
mutex_lock(&pcf->lock);
pcf->irq_handler[irq].handler = handler;
pcf->irq_handler[irq].data = data;
mutex_unlock(&pcf->lock);
return 0;
}
EXPORT_SYMBOL_GPL(pcf50633_register_irq);
int pcf50633_free_irq(struct pcf50633 *pcf, int irq)
{
if (irq < 0 || irq > PCF50633_NUM_IRQ)
return -EINVAL;
mutex_lock(&pcf->lock);
pcf->irq_handler[irq].handler = NULL;
mutex_unlock(&pcf->lock);
return 0;
}
EXPORT_SYMBOL_GPL(pcf50633_free_irq);
static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)
{
u8 reg, bits, tmp;
int ret = 0, idx;
idx = irq >> 3;
reg = PCF50633_REG_INT1M + idx;
bits = 1 << (irq & 0x07);
mutex_lock(&pcf->lock);
if (mask) {
ret = __pcf50633_read(pcf, reg, 1, &tmp);
if (ret < 0)
goto out;
tmp |= bits;
ret = __pcf50633_write(pcf, reg, 1, &tmp);
if (ret < 0)
goto out;
pcf->mask_regs[idx] &= ~bits;
pcf->mask_regs[idx] |= bits;
} else {
ret = __pcf50633_read(pcf, reg, 1, &tmp);
if (ret < 0)
goto out;
tmp &= ~bits;
ret = __pcf50633_write(pcf, reg, 1, &tmp);
if (ret < 0)
goto out;
pcf->mask_regs[idx] &= ~bits;
}
out:
mutex_unlock(&pcf->lock);
return ret;
}
int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
{
dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 1);
}
EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
{
dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 0);
}
EXPORT_SYMBOL_GPL(pcf50633_irq_unmask);
int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq)
{
u8 reg, bits;
reg = irq >> 3;
bits = 1 << (irq & 0x07);
return pcf->mask_regs[reg] & bits;
}
EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get);
static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq)
{
if (pcf->irq_handler[irq].handler)
pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data);
}
/* Maximum amount of time ONKEY is held before emergency action is taken */
#define PCF50633_ONKEY1S_TIMEOUT 8
static void pcf50633_irq_worker(struct work_struct *work)
{
struct pcf50633 *pcf;
int ret, i, j;
u8 pcf_int[5], chgstat;
pcf = container_of(work, struct pcf50633, irq_work);
/* Read the 5 INT regs in one transaction */
ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
ARRAY_SIZE(pcf_int), pcf_int);
if (ret != ARRAY_SIZE(pcf_int)) {
dev_err(pcf->dev, "Error reading INT registers\n");
/*
* If this doesn't ACK the interrupt to the chip, we'll be
* called once again as we're level triggered.
*/
goto out;
}
/* defeat 8s death from lowsys on A5 */
pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04);
/* We immediately read the usb and adapter status. We thus make sure
* only of USBINS/USBREM IRQ handlers are called */
if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
if (chgstat & (0x3 << 4))
pcf_int[0] &= ~(1 << PCF50633_INT1_USBREM);
else
pcf_int[0] &= ~(1 << PCF50633_INT1_USBINS);
}
/* Make sure only one of ADPINS or ADPREM is set */
if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
if (chgstat & (0x3 << 4))
pcf_int[0] &= ~(1 << PCF50633_INT1_ADPREM);
else
pcf_int[0] &= ~(1 << PCF50633_INT1_ADPINS);
}
dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
"INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);
/* Some revisions of the chip don't have a 8s standby mode on
* ONKEY1S press. We try to manually do it in such cases. */
if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
pcf->onkey1s_held);
if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
if (pcf->pdata->force_shutdown)
pcf->pdata->force_shutdown(pcf);
}
if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
dev_info(pcf->dev, "ONKEY1S held\n");
pcf->onkey1s_held = 1 ;
/* Unmask IRQ_SECOND */
pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
PCF50633_INT1_SECOND);
/* Unmask IRQ_ONKEYR */
pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
PCF50633_INT2_ONKEYR);
}
if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
pcf->onkey1s_held = 0;
/* Mask SECOND and ONKEYR interrupts */
if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
pcf50633_reg_set_bit_mask(pcf,
PCF50633_REG_INT1M,
PCF50633_INT1_SECOND,
PCF50633_INT1_SECOND);
if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
pcf50633_reg_set_bit_mask(pcf,
PCF50633_REG_INT2M,
PCF50633_INT2_ONKEYR,
PCF50633_INT2_ONKEYR);
}
/* Have we just resumed ? */
if (pcf->is_suspended) {
pcf->is_suspended = 0;
/* Set the resume reason filtering out non resumers */
for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
pcf->resume_reason[i] = pcf_int[i] &
pcf->pdata->resumers[i];
/* Make sure we don't pass on any ONKEY events to
* userspace now */
pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
}
for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
/* Unset masked interrupts */
pcf_int[i] &= ~pcf->mask_regs[i];
for (j = 0; j < 8 ; j++)
if (pcf_int[i] & (1 << j))
pcf50633_irq_call_handler(pcf, (i * 8) + j);
}
out:
put_device(pcf->dev);
enable_irq(pcf->irq);
}
static irqreturn_t pcf50633_irq(int irq, void *data)
{
struct pcf50633 *pcf = data;
dev_dbg(pcf->dev, "pcf50633_irq\n");
get_device(pcf->dev);
disable_irq_nosync(pcf->irq);
queue_work(pcf->work_queue, &pcf->irq_work);
return IRQ_HANDLED;
}
static void static void
pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
struct platform_device **pdev) struct platform_device **pdev)
...@@ -479,70 +241,17 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, ...@@ -479,70 +241,17 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
{ {
struct pcf50633 *pcf; struct pcf50633 *pcf;
int ret = 0, i;
u8 res[5];
pcf = i2c_get_clientdata(client); pcf = i2c_get_clientdata(client);
/* Make sure our interrupt handlers are not called return pcf50633_irq_suspend(pcf);
* henceforth */
disable_irq(pcf->irq);
/* Make sure that any running IRQ worker has quit */
cancel_work_sync(&pcf->irq_work);
/* Save the masks */
ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(pcf->suspend_irq_masks),
pcf->suspend_irq_masks);
if (ret < 0) {
dev_err(pcf->dev, "error saving irq masks\n");
goto out;
}
/* Write wakeup irq masks */
for (i = 0; i < ARRAY_SIZE(res); i++)
res[i] = ~pcf->pdata->resumers[i];
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(res), &res[0]);
if (ret < 0) {
dev_err(pcf->dev, "error writing wakeup irq masks\n");
goto out;
}
pcf->is_suspended = 1;
out:
return ret;
} }
static int pcf50633_resume(struct i2c_client *client) static int pcf50633_resume(struct i2c_client *client)
{ {
struct pcf50633 *pcf; struct pcf50633 *pcf;
int ret;
pcf = i2c_get_clientdata(client); pcf = i2c_get_clientdata(client);
/* Write the saved mask registers */ return pcf50633_irq_resume(pcf);
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(pcf->suspend_irq_masks),
pcf->suspend_irq_masks);
if (ret < 0)
dev_err(pcf->dev, "Error restoring saved suspend masks\n");
/* Restore regulators' state */
get_device(pcf->dev);
/*
* Clear any pending interrupts and set resume reason if any.
* This will leave with enable_irq()
*/
pcf50633_irq_worker(&pcf->irq_work);
return 0;
} }
#else #else
#define pcf50633_suspend NULL #define pcf50633_suspend NULL
...@@ -573,43 +282,19 @@ static int __devinit pcf50633_probe(struct i2c_client *client, ...@@ -573,43 +282,19 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
i2c_set_clientdata(client, pcf); i2c_set_clientdata(client, pcf);
pcf->dev = &client->dev; pcf->dev = &client->dev;
pcf->i2c_client = client; pcf->i2c_client = client;
pcf->irq = client->irq;
pcf->work_queue = create_singlethread_workqueue("pcf50633");
if (!pcf->work_queue) {
dev_err(&client->dev, "Failed to alloc workqueue\n");
ret = -ENOMEM;
goto err_free;
}
INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
version = pcf50633_reg_read(pcf, 0); version = pcf50633_reg_read(pcf, 0);
variant = pcf50633_reg_read(pcf, 1); variant = pcf50633_reg_read(pcf, 1);
if (version < 0 || variant < 0) { if (version < 0 || variant < 0) {
dev_err(pcf->dev, "Unable to probe pcf50633\n"); dev_err(pcf->dev, "Unable to probe pcf50633\n");
ret = -ENODEV; ret = -ENODEV;
goto err_destroy_workqueue; goto err_free;
} }
dev_info(pcf->dev, "Probed device version %d variant %d\n", dev_info(pcf->dev, "Probed device version %d variant %d\n",
version, variant); version, variant);
/* Enable all interrupts except RTC SECOND */ pcf50633_irq_init(pcf, client->irq);
pcf->mask_regs[0] = 0x80;
pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);
pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
ret = request_irq(client->irq, pcf50633_irq,
IRQF_TRIGGER_LOW, "pcf50633", pcf);
if (ret) {
dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
goto err_destroy_workqueue;
}
/* Create sub devices */ /* Create sub devices */
pcf50633_client_dev_register(pcf, "pcf50633-input", pcf50633_client_dev_register(pcf, "pcf50633-input",
...@@ -641,10 +326,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client, ...@@ -641,10 +326,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
platform_device_add(pdev); platform_device_add(pdev);
} }
if (enable_irq_wake(client->irq) < 0)
dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
"in this hardware revision", client->irq);
ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group); ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
if (ret) if (ret)
dev_err(pcf->dev, "error creating sysfs entries\n"); dev_err(pcf->dev, "error creating sysfs entries\n");
...@@ -654,8 +335,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client, ...@@ -654,8 +335,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
return 0; return 0;
err_destroy_workqueue:
destroy_workqueue(pcf->work_queue);
err_free: err_free:
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(pcf); kfree(pcf);
...@@ -668,8 +347,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) ...@@ -668,8 +347,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
struct pcf50633 *pcf = i2c_get_clientdata(client); struct pcf50633 *pcf = i2c_get_clientdata(client);
int i; int i;
free_irq(pcf->irq, pcf); pcf50633_irq_free(pcf);
destroy_workqueue(pcf->work_queue);
platform_device_unregister(pcf->input_pdev); platform_device_unregister(pcf->input_pdev);
platform_device_unregister(pcf->rtc_pdev); platform_device_unregister(pcf->rtc_pdev);
...@@ -679,6 +357,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) ...@@ -679,6 +357,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
for (i = 0; i < PCF50633_NUM_REGULATORS; i++) for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
platform_device_unregister(pcf->regulator_pdev[i]); platform_device_unregister(pcf->regulator_pdev[i]);
i2c_set_clientdata(client, NULL);
kfree(pcf); kfree(pcf);
return 0; return 0;
......
/* NXP PCF50633 Power Management Unit (PMU) driver
*
* (C) 2006-2008 by Openmoko, Inc.
* Author: Harald Welte <laforge@openmoko.org>
* Balaji Rao <balajirrao@openmoko.org>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/mfd/pcf50633/core.h>
/* Two MBCS registers used during cold start */
#define PCF50633_REG_MBCS1 0x4b
#define PCF50633_REG_MBCS2 0x4c
#define PCF50633_MBCS1_USBPRES 0x01
#define PCF50633_MBCS1_ADAPTPRES 0x01
int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
void (*handler) (int, void *), void *data)
{
if (irq < 0 || irq >= PCF50633_NUM_IRQ || !handler)
return -EINVAL;
if (WARN_ON(pcf->irq_handler[irq].handler))
return -EBUSY;
mutex_lock(&pcf->lock);
pcf->irq_handler[irq].handler = handler;
pcf->irq_handler[irq].data = data;
mutex_unlock(&pcf->lock);
return 0;
}
EXPORT_SYMBOL_GPL(pcf50633_register_irq);
int pcf50633_free_irq(struct pcf50633 *pcf, int irq)
{
if (irq < 0 || irq >= PCF50633_NUM_IRQ)
return -EINVAL;
mutex_lock(&pcf->lock);
pcf->irq_handler[irq].handler = NULL;
mutex_unlock(&pcf->lock);
return 0;
}
EXPORT_SYMBOL_GPL(pcf50633_free_irq);
static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)
{
u8 reg, bit;
int ret = 0, idx;
idx = irq >> 3;
reg = PCF50633_REG_INT1M + idx;
bit = 1 << (irq & 0x07);
pcf50633_reg_set_bit_mask(pcf, reg, bit, mask ? bit : 0);
mutex_lock(&pcf->lock);
if (mask)
pcf->mask_regs[idx] |= bit;
else
pcf->mask_regs[idx] &= ~bit;
mutex_unlock(&pcf->lock);
return ret;
}
int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
{
dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 1);
}
EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
{
dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
return __pcf50633_irq_mask_set(pcf, irq, 0);
}
EXPORT_SYMBOL_GPL(pcf50633_irq_unmask);
int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq)
{
u8 reg, bits;
reg = irq >> 3;
bits = 1 << (irq & 0x07);
return pcf->mask_regs[reg] & bits;
}
EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get);
static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq)
{
if (pcf->irq_handler[irq].handler)
pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data);
}
/* Maximum amount of time ONKEY is held before emergency action is taken */
#define PCF50633_ONKEY1S_TIMEOUT 8
static irqreturn_t pcf50633_irq(int irq, void *data)
{
struct pcf50633 *pcf = data;
int ret, i, j;
u8 pcf_int[5], chgstat;
/* Read the 5 INT regs in one transaction */
ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
ARRAY_SIZE(pcf_int), pcf_int);
if (ret != ARRAY_SIZE(pcf_int)) {
dev_err(pcf->dev, "Error reading INT registers\n");
/*
* If this doesn't ACK the interrupt to the chip, we'll be
* called once again as we're level triggered.
*/
goto out;
}
/* defeat 8s death from lowsys on A5 */
pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04);
/* We immediately read the usb and adapter status. We thus make sure
* only of USBINS/USBREM IRQ handlers are called */
if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
if (chgstat & (0x3 << 4))
pcf_int[0] &= ~PCF50633_INT1_USBREM;
else
pcf_int[0] &= ~PCF50633_INT1_USBINS;
}
/* Make sure only one of ADPINS or ADPREM is set */
if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
if (chgstat & (0x3 << 4))
pcf_int[0] &= ~PCF50633_INT1_ADPREM;
else
pcf_int[0] &= ~PCF50633_INT1_ADPINS;
}
dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
"INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);
/* Some revisions of the chip don't have a 8s standby mode on
* ONKEY1S press. We try to manually do it in such cases. */
if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
pcf->onkey1s_held);
if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
if (pcf->pdata->force_shutdown)
pcf->pdata->force_shutdown(pcf);
}
if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
dev_info(pcf->dev, "ONKEY1S held\n");
pcf->onkey1s_held = 1 ;
/* Unmask IRQ_SECOND */
pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
PCF50633_INT1_SECOND);
/* Unmask IRQ_ONKEYR */
pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
PCF50633_INT2_ONKEYR);
}
if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
pcf->onkey1s_held = 0;
/* Mask SECOND and ONKEYR interrupts */
if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
pcf50633_reg_set_bit_mask(pcf,
PCF50633_REG_INT1M,
PCF50633_INT1_SECOND,
PCF50633_INT1_SECOND);
if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
pcf50633_reg_set_bit_mask(pcf,
PCF50633_REG_INT2M,
PCF50633_INT2_ONKEYR,
PCF50633_INT2_ONKEYR);
}
/* Have we just resumed ? */
if (pcf->is_suspended) {
pcf->is_suspended = 0;
/* Set the resume reason filtering out non resumers */
for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
pcf->resume_reason[i] = pcf_int[i] &
pcf->pdata->resumers[i];
/* Make sure we don't pass on any ONKEY events to
* userspace now */
pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
}
for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
/* Unset masked interrupts */
pcf_int[i] &= ~pcf->mask_regs[i];
for (j = 0; j < 8 ; j++)
if (pcf_int[i] & (1 << j))
pcf50633_irq_call_handler(pcf, (i * 8) + j);
}
out:
return IRQ_HANDLED;
}
#ifdef CONFIG_PM
int pcf50633_irq_suspend(struct pcf50633 *pcf)
{
int ret;
int i;
u8 res[5];
/* Make sure our interrupt handlers are not called
* henceforth */
disable_irq(pcf->irq);
/* Save the masks */
ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(pcf->suspend_irq_masks),
pcf->suspend_irq_masks);
if (ret < 0) {
dev_err(pcf->dev, "error saving irq masks\n");
goto out;
}
/* Write wakeup irq masks */
for (i = 0; i < ARRAY_SIZE(res); i++)
res[i] = ~pcf->pdata->resumers[i];
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(res), &res[0]);
if (ret < 0) {
dev_err(pcf->dev, "error writing wakeup irq masks\n");
goto out;
}
pcf->is_suspended = 1;
out:
return ret;
}
int pcf50633_irq_resume(struct pcf50633 *pcf)
{
int ret;
/* Write the saved mask registers */
ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
ARRAY_SIZE(pcf->suspend_irq_masks),
pcf->suspend_irq_masks);
if (ret < 0)
dev_err(pcf->dev, "Error restoring saved suspend masks\n");
enable_irq(pcf->irq);
return ret;
}
#endif
int pcf50633_irq_init(struct pcf50633 *pcf, int irq)
{
int ret;
pcf->irq = irq;
/* Enable all interrupts except RTC SECOND */
pcf->mask_regs[0] = 0x80;
pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);
pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
ret = request_threaded_irq(irq, NULL, pcf50633_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"pcf50633", pcf);
if (ret)
dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
if (enable_irq_wake(irq) < 0)
dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
"in this hardware revision", irq);
return ret;
}
void pcf50633_irq_free(struct pcf50633 *pcf)
{
free_irq(pcf->irq, pcf);
}
/*
* RDC321x MFD southbrige driver
*
* Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
* Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rdc321x.h>
static struct rdc321x_wdt_pdata rdc321x_wdt_pdata;
static struct resource rdc321x_wdt_resource[] = {
{
.name = "wdt-reg",
.start = RDC321X_WDT_CTRL,
.end = RDC321X_WDT_CTRL + 0x3,
.flags = IORESOURCE_IO,
}
};
static struct rdc321x_gpio_pdata rdc321x_gpio_pdata = {
.max_gpios = RDC321X_MAX_GPIO,
};
static struct resource rdc321x_gpio_resources[] = {
{
.name = "gpio-reg1",
.start = RDC321X_GPIO_CTRL_REG1,
.end = RDC321X_GPIO_CTRL_REG1 + 0x7,
.flags = IORESOURCE_IO,
}, {
.name = "gpio-reg2",
.start = RDC321X_GPIO_CTRL_REG2,
.end = RDC321X_GPIO_CTRL_REG2 + 0x7,
.flags = IORESOURCE_IO,
}
};
static struct mfd_cell rdc321x_sb_cells[] = {
{
.name = "rdc321x-wdt",
.resources = rdc321x_wdt_resource,
.num_resources = ARRAY_SIZE(rdc321x_wdt_resource),
.driver_data = &rdc321x_wdt_pdata,
}, {
.name = "rdc321x-gpio",
.resources = rdc321x_gpio_resources,
.num_resources = ARRAY_SIZE(rdc321x_gpio_resources),
.driver_data = &rdc321x_gpio_pdata,
},
};
static int __devinit rdc321x_sb_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err;
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "failed to enable device\n");
return err;
}
rdc321x_gpio_pdata.sb_pdev = pdev;
rdc321x_wdt_pdata.sb_pdev = pdev;
return mfd_add_devices(&pdev->dev, -1,
rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), NULL, 0);
}
static void __devexit rdc321x_sb_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
}
static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) },
{}
};
static struct pci_driver rdc321x_sb_driver = {
.name = "RDC321x Southbridge",
.id_table = rdc321x_sb_table,
.probe = rdc321x_sb_probe,
.remove = __devexit_p(rdc321x_sb_remove),
};
static int __init rdc321x_sb_init(void)
{
return pci_register_driver(&rdc321x_sb_driver);
}
static void __exit rdc321x_sb_exit(void)
{
pci_unregister_driver(&rdc321x_sb_driver);
}
module_init(rdc321x_sb_init);
module_exit(rdc321x_sb_exit);
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RDC R-321x MFD southbridge driver");
...@@ -318,6 +318,9 @@ static int t7l66xb_probe(struct platform_device *dev) ...@@ -318,6 +318,9 @@ static int t7l66xb_probe(struct platform_device *dev)
struct resource *iomem, *rscr; struct resource *iomem, *rscr;
int ret; int ret;
if (pdata == NULL)
return -EINVAL;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem) if (!iomem)
return -EINVAL; return -EINVAL;
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tc35892.h>
/**
* tc35892_reg_read() - read a single TC35892 register
* @tc35892: Device to read from
* @reg: Register to read
*/
int tc35892_reg_read(struct tc35892 *tc35892, u8 reg)
{
int ret;
ret = i2c_smbus_read_byte_data(tc35892->i2c, reg);
if (ret < 0)
dev_err(tc35892->dev, "failed to read reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_reg_read);
/**
* tc35892_reg_read() - write a single TC35892 register
* @tc35892: Device to write to
* @reg: Register to read
* @data: Value to write
*/
int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data)
{
int ret;
ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data);
if (ret < 0)
dev_err(tc35892->dev, "failed to write reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_reg_write);
/**
* tc35892_block_read() - read multiple TC35892 registers
* @tc35892: Device to read from
* @reg: First register
* @length: Number of registers
* @values: Buffer to write to
*/
int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values)
{
int ret;
ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values);
if (ret < 0)
dev_err(tc35892->dev, "failed to read regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_block_read);
/**
* tc35892_block_write() - write multiple TC35892 registers
* @tc35892: Device to write to
* @reg: First register
* @length: Number of registers
* @values: Values to write
*/
int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length,
const u8 *values)
{
int ret;
ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length,
values);
if (ret < 0)
dev_err(tc35892->dev, "failed to write regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_block_write);
/**
* tc35892_set_bits() - set the value of a bitfield in a TC35892 register
* @tc35892: Device to write to
* @reg: Register to write
* @mask: Mask of bits to set
* @values: Value to set
*/
int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val)
{
int ret;
mutex_lock(&tc35892->lock);
ret = tc35892_reg_read(tc35892, reg);
if (ret < 0)
goto out;
ret &= ~mask;
ret |= val;
ret = tc35892_reg_write(tc35892, reg, ret);
out:
mutex_unlock(&tc35892->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_set_bits);
static struct resource gpio_resources[] = {
{
.start = TC35892_INT_GPIIRQ,
.end = TC35892_INT_GPIIRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell tc35892_devs[] = {
{
.name = "tc35892-gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = &gpio_resources[0],
},
};
static irqreturn_t tc35892_irq(int irq, void *data)
{
struct tc35892 *tc35892 = data;
int status;
status = tc35892_reg_read(tc35892, TC35892_IRQST);
if (status < 0)
return IRQ_NONE;
while (status) {
int bit = __ffs(status);
handle_nested_irq(tc35892->irq_base + bit);
status &= ~(1 << bit);
}
/*
* A dummy read or write (to any register) appears to be necessary to
* have the last interrupt clear (for example, GPIO IC write) take
* effect.
*/
tc35892_reg_read(tc35892, TC35892_IRQST);
return IRQ_HANDLED;
}
static void tc35892_irq_dummy(unsigned int irq)
{
/* No mask/unmask at this level */
}
static struct irq_chip tc35892_irq_chip = {
.name = "tc35892",
.mask = tc35892_irq_dummy,
.unmask = tc35892_irq_dummy,
};
static int tc35892_irq_init(struct tc35892 *tc35892)
{
int base = tc35892->irq_base;
int irq;
for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
set_irq_chip_data(irq, tc35892);
set_irq_chip_and_handler(irq, &tc35892_irq_chip,
handle_edge_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void tc35892_irq_remove(struct tc35892 *tc35892)
{
int base = tc35892->irq_base;
int irq;
for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static int tc35892_chip_init(struct tc35892 *tc35892)
{
int manf, ver, ret;
manf = tc35892_reg_read(tc35892, TC35892_MANFCODE);
if (manf < 0)
return manf;
ver = tc35892_reg_read(tc35892, TC35892_VERSION);
if (ver < 0)
return ver;
if (manf != TC35892_MANFCODE_MAGIC) {
dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf);
return -EINVAL;
}
dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
/* Put everything except the IRQ module into reset */
ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL,
TC35892_RSTCTRL_TIMRST
| TC35892_RSTCTRL_ROTRST
| TC35892_RSTCTRL_KBDRST
| TC35892_RSTCTRL_GPIRST);
if (ret < 0)
return ret;
/* Clear the reset interrupt. */
return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1);
}
static int __devinit tc35892_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tc35892_platform_data *pdata = i2c->dev.platform_data;
struct tc35892 *tc35892;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL);
if (!tc35892)
return -ENOMEM;
mutex_init(&tc35892->lock);
tc35892->dev = &i2c->dev;
tc35892->i2c = i2c;
tc35892->pdata = pdata;
tc35892->irq_base = pdata->irq_base;
tc35892->num_gpio = id->driver_data;
i2c_set_clientdata(i2c, tc35892);
ret = tc35892_chip_init(tc35892);
if (ret)
goto out_free;
ret = tc35892_irq_init(tc35892);
if (ret)
goto out_free;
ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tc35892", tc35892);
if (ret) {
dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
}
ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs,
ARRAY_SIZE(tc35892_devs), NULL,
tc35892->irq_base);
if (ret) {
dev_err(tc35892->dev, "failed to add children\n");
goto out_freeirq;
}
return 0;
out_freeirq:
free_irq(tc35892->i2c->irq, tc35892);
out_removeirq:
tc35892_irq_remove(tc35892);
out_free:
i2c_set_clientdata(i2c, NULL);
kfree(tc35892);
return ret;
}
static int __devexit tc35892_remove(struct i2c_client *client)
{
struct tc35892 *tc35892 = i2c_get_clientdata(client);
mfd_remove_devices(tc35892->dev);
free_irq(tc35892->i2c->irq, tc35892);
tc35892_irq_remove(tc35892);
i2c_set_clientdata(client, NULL);
kfree(tc35892);
return 0;
}
static const struct i2c_device_id tc35892_id[] = {
{ "tc35892", 24 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc35892_id);
static struct i2c_driver tc35892_driver = {
.driver.name = "tc35892",
.driver.owner = THIS_MODULE,
.probe = tc35892_probe,
.remove = __devexit_p(tc35892_remove),
.id_table = tc35892_id,
};
static int __init tc35892_init(void)
{
return i2c_add_driver(&tc35892_driver);
}
subsys_initcall(tc35892_init);
static void __exit tc35892_exit(void)
{
i2c_del_driver(&tc35892_driver);
}
module_exit(tc35892_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC35892 MFD core driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-ocores.h> #include <linux/i2c-ocores.h>
#include <linux/i2c-xiic.h>
#include <linux/i2c/tsc2007.h> #include <linux/i2c/tsc2007.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -40,6 +41,8 @@ ...@@ -40,6 +41,8 @@
#include <media/timb_radio.h> #include <media/timb_radio.h>
#include <linux/timb_dma.h>
#include "timberdale.h" #include "timberdale.h"
#define DRIVER_NAME "timberdale" #define DRIVER_NAME "timberdale"
...@@ -69,6 +72,12 @@ static struct i2c_board_info timberdale_i2c_board_info[] = { ...@@ -69,6 +72,12 @@ static struct i2c_board_info timberdale_i2c_board_info[] = {
}, },
}; };
static __devinitdata struct xiic_i2c_platform_data
timberdale_xiic_platform_data = {
.devices = timberdale_i2c_board_info,
.num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
};
static __devinitdata struct ocores_i2c_platform_data static __devinitdata struct ocores_i2c_platform_data
timberdale_ocores_platform_data = { timberdale_ocores_platform_data = {
.regstep = 4, .regstep = 4,
...@@ -77,7 +86,20 @@ timberdale_ocores_platform_data = { ...@@ -77,7 +86,20 @@ timberdale_ocores_platform_data = {
.num_devices = ARRAY_SIZE(timberdale_i2c_board_info) .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
}; };
const static __devinitconst struct resource timberdale_ocores_resources[] = { static const __devinitconst struct resource timberdale_xiic_resources[] = {
{
.start = XIICOFFSET,
.end = XIICEND,
.flags = IORESOURCE_MEM,
},
{
.start = IRQ_TIMBERDALE_I2C,
.end = IRQ_TIMBERDALE_I2C,
.flags = IORESOURCE_IRQ,
},
};
static const __devinitconst struct resource timberdale_ocores_resources[] = {
{ {
.start = OCORESOFFSET, .start = OCORESOFFSET,
.end = OCORESEND, .end = OCORESEND,
...@@ -126,7 +148,7 @@ static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = { ...@@ -126,7 +148,7 @@ static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
*/ */
}; };
const static __devinitconst struct resource timberdale_spi_resources[] = { static const __devinitconst struct resource timberdale_spi_resources[] = {
{ {
.start = SPIOFFSET, .start = SPIOFFSET,
.end = SPIEND, .end = SPIEND,
...@@ -139,7 +161,7 @@ const static __devinitconst struct resource timberdale_spi_resources[] = { ...@@ -139,7 +161,7 @@ const static __devinitconst struct resource timberdale_spi_resources[] = {
}, },
}; };
const static __devinitconst struct resource timberdale_eth_resources[] = { static const __devinitconst struct resource timberdale_eth_resources[] = {
{ {
.start = ETHOFFSET, .start = ETHOFFSET,
.end = ETHEND, .end = ETHEND,
...@@ -159,7 +181,7 @@ static __devinitdata struct timbgpio_platform_data ...@@ -159,7 +181,7 @@ static __devinitdata struct timbgpio_platform_data
.irq_base = 200, .irq_base = 200,
}; };
const static __devinitconst struct resource timberdale_gpio_resources[] = { static const __devinitconst struct resource timberdale_gpio_resources[] = {
{ {
.start = GPIOOFFSET, .start = GPIOOFFSET,
.end = GPIOEND, .end = GPIOEND,
...@@ -172,7 +194,7 @@ const static __devinitconst struct resource timberdale_gpio_resources[] = { ...@@ -172,7 +194,7 @@ const static __devinitconst struct resource timberdale_gpio_resources[] = {
}, },
}; };
const static __devinitconst struct resource timberdale_mlogicore_resources[] = { static const __devinitconst struct resource timberdale_mlogicore_resources[] = {
{ {
.start = MLCOREOFFSET, .start = MLCOREOFFSET,
.end = MLCOREEND, .end = MLCOREEND,
...@@ -190,7 +212,7 @@ const static __devinitconst struct resource timberdale_mlogicore_resources[] = { ...@@ -190,7 +212,7 @@ const static __devinitconst struct resource timberdale_mlogicore_resources[] = {
}, },
}; };
const static __devinitconst struct resource timberdale_uart_resources[] = { static const __devinitconst struct resource timberdale_uart_resources[] = {
{ {
.start = UARTOFFSET, .start = UARTOFFSET,
.end = UARTEND, .end = UARTEND,
...@@ -203,7 +225,7 @@ const static __devinitconst struct resource timberdale_uart_resources[] = { ...@@ -203,7 +225,7 @@ const static __devinitconst struct resource timberdale_uart_resources[] = {
}, },
}; };
const static __devinitconst struct resource timberdale_uartlite_resources[] = { static const __devinitconst struct resource timberdale_uartlite_resources[] = {
{ {
.start = UARTLITEOFFSET, .start = UARTLITEOFFSET,
.end = UARTLITEEND, .end = UARTLITEEND,
...@@ -216,7 +238,7 @@ const static __devinitconst struct resource timberdale_uartlite_resources[] = { ...@@ -216,7 +238,7 @@ const static __devinitconst struct resource timberdale_uartlite_resources[] = {
}, },
}; };
const static __devinitconst struct resource timberdale_radio_resources[] = { static const __devinitconst struct resource timberdale_radio_resources[] = {
{ {
.start = RDSOFFSET, .start = RDSOFFSET,
.end = RDSEND, .end = RDSEND,
...@@ -250,7 +272,66 @@ static __devinitdata struct timb_radio_platform_data ...@@ -250,7 +272,66 @@ static __devinitdata struct timb_radio_platform_data
} }
}; };
const static __devinitconst struct resource timberdale_dma_resources[] = { static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = {
.nr_channels = 10,
.channels = {
{
/* UART RX */
.rx = true,
.descriptors = 2,
.descriptor_elements = 1
},
{
/* UART TX */
.rx = false,
.descriptors = 2,
.descriptor_elements = 1
},
{
/* MLB RX */
.rx = true,
.descriptors = 2,
.descriptor_elements = 1
},
{
/* MLB TX */
.rx = false,
.descriptors = 2,
.descriptor_elements = 1
},
{
/* Video RX */
.rx = true,
.bytes_per_line = 1440,
.descriptors = 2,
.descriptor_elements = 16
},
{
/* Video framedrop */
},
{
/* SDHCI RX */
.rx = true,
},
{
/* SDHCI TX */
},
{
/* ETH RX */
.rx = true,
.descriptors = 2,
.descriptor_elements = 1
},
{
/* ETH TX */
.rx = false,
.descriptors = 2,
.descriptor_elements = 1
},
}
};
static const __devinitconst struct resource timberdale_dma_resources[] = {
{ {
.start = DMAOFFSET, .start = DMAOFFSET,
.end = DMAEND, .end = DMAEND,
...@@ -264,11 +345,25 @@ const static __devinitconst struct resource timberdale_dma_resources[] = { ...@@ -264,11 +345,25 @@ const static __devinitconst struct resource timberdale_dma_resources[] = {
}; };
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
{
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
.platform_data = &timb_dma_platform_data,
.data_size = sizeof(timb_dma_platform_data),
},
{ {
.name = "timb-uart", .name = "timb-uart",
.num_resources = ARRAY_SIZE(timberdale_uart_resources), .num_resources = ARRAY_SIZE(timberdale_uart_resources),
.resources = timberdale_uart_resources, .resources = timberdale_uart_resources,
}, },
{
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
.platform_data = &timberdale_xiic_platform_data,
.data_size = sizeof(timberdale_xiic_platform_data),
},
{ {
.name = "timb-gpio", .name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources), .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
...@@ -295,14 +390,16 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { ...@@ -295,14 +390,16 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
.num_resources = ARRAY_SIZE(timberdale_eth_resources), .num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources, .resources = timberdale_eth_resources,
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
{ {
.name = "timb-dma", .name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources), .num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources, .resources = timberdale_dma_resources,
.platform_data = &timb_dma_platform_data,
.data_size = sizeof(timb_dma_platform_data),
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
{ {
.name = "timb-uart", .name = "timb-uart",
.num_resources = ARRAY_SIZE(timberdale_uart_resources), .num_resources = ARRAY_SIZE(timberdale_uart_resources),
...@@ -313,6 +410,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { ...@@ -313,6 +410,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.num_resources = ARRAY_SIZE(timberdale_uartlite_resources), .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
.resources = timberdale_uartlite_resources, .resources = timberdale_uartlite_resources,
}, },
{
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
.platform_data = &timberdale_xiic_platform_data,
.data_size = sizeof(timberdale_xiic_platform_data),
},
{ {
.name = "timb-gpio", .name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources), .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
...@@ -344,19 +448,28 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { ...@@ -344,19 +448,28 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.num_resources = ARRAY_SIZE(timberdale_eth_resources), .num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources, .resources = timberdale_eth_resources,
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
{ {
.name = "timb-dma", .name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources), .num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources, .resources = timberdale_dma_resources,
.platform_data = &timb_dma_platform_data,
.data_size = sizeof(timb_dma_platform_data),
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
{ {
.name = "timb-uart", .name = "timb-uart",
.num_resources = ARRAY_SIZE(timberdale_uart_resources), .num_resources = ARRAY_SIZE(timberdale_uart_resources),
.resources = timberdale_uart_resources, .resources = timberdale_uart_resources,
}, },
{
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
.platform_data = &timberdale_xiic_platform_data,
.data_size = sizeof(timberdale_xiic_platform_data),
},
{ {
.name = "timb-gpio", .name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources), .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
...@@ -378,14 +491,16 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { ...@@ -378,14 +491,16 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
.platform_data = &timberdale_xspi_platform_data, .platform_data = &timberdale_xspi_platform_data,
.data_size = sizeof(timberdale_xspi_platform_data), .data_size = sizeof(timberdale_xspi_platform_data),
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
{ {
.name = "timb-dma", .name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources), .num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources, .resources = timberdale_dma_resources,
.platform_data = &timb_dma_platform_data,
.data_size = sizeof(timb_dma_platform_data),
}, },
};
static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
{ {
.name = "timb-uart", .name = "timb-uart",
.num_resources = ARRAY_SIZE(timberdale_uart_resources), .num_resources = ARRAY_SIZE(timberdale_uart_resources),
...@@ -424,11 +539,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { ...@@ -424,11 +539,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
.num_resources = ARRAY_SIZE(timberdale_eth_resources), .num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources, .resources = timberdale_eth_resources,
}, },
{
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
},
}; };
static const __devinitconst struct resource timberdale_sdhc_resources[] = { static const __devinitconst struct resource timberdale_sdhc_resources[] = {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#ifndef MFD_TIMBERDALE_H #ifndef MFD_TIMBERDALE_H
#define MFD_TIMBERDALE_H #define MFD_TIMBERDALE_H
#define DRV_VERSION "0.1" #define DRV_VERSION "0.2"
/* This driver only support versions >= 3.8 and < 4.0 */ /* This driver only support versions >= 3.8 and < 4.0 */
#define TIMB_SUPPORTED_MAJOR 3 #define TIMB_SUPPORTED_MAJOR 3
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
#define CHIPCTLOFFSET 0x800 #define CHIPCTLOFFSET 0x800
#define CHIPCTLEND 0x8ff #define CHIPCTLEND 0x8ff
#define CHIPCTLSIZE (CHIPCTLEND - CHIPCTLOFFSET) #define CHIPCTLSIZE (CHIPCTLEND - CHIPCTLOFFSET + 1)
#define INTCOFFSET 0xc00 #define INTCOFFSET 0xc00
#define INTCEND 0xfff #define INTCEND 0xfff
...@@ -127,4 +127,16 @@ ...@@ -127,4 +127,16 @@
#define GPIO_PIN_BT_RST 15 #define GPIO_PIN_BT_RST 15
#define GPIO_NR_PINS 16 #define GPIO_NR_PINS 16
/* DMA Channels */
#define DMA_UART_RX 0
#define DMA_UART_TX 1
#define DMA_MLB_RX 2
#define DMA_MLB_TX 3
#define DMA_VIDEO_RX 4
#define DMA_VIDEO_DROP 5
#define DMA_SDHCI_RX 6
#define DMA_SDHCI_TX 7
#define DMA_ETH_RX 8
#define DMA_ETH_TX 9
#endif #endif
...@@ -530,8 +530,8 @@ static int __exit tps65010_remove(struct i2c_client *client) ...@@ -530,8 +530,8 @@ static int __exit tps65010_remove(struct i2c_client *client)
cancel_delayed_work(&tps->work); cancel_delayed_work(&tps->work);
flush_scheduled_work(); flush_scheduled_work();
debugfs_remove(tps->file); debugfs_remove(tps->file);
kfree(tps);
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(tps);
the_tps = NULL; the_tps = NULL;
return 0; return 0;
} }
......
/*
* tps6507x.c -- TPS6507x chip family multi-function driver
*
* Copyright (c) 2010 RidgeRun (todd.fischer@ridgerun.com)
*
* Author: Todd Fischer
* todd.fischer@ridgerun.com
*
* Credits:
*
* Using code from wm831x-*.c, wm8400-core, Wolfson Microelectronics PLC.
*
* For licencing details see kernel-base/COPYING
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6507x.h>
static struct mfd_cell tps6507x_devs[] = {
{
.name = "tps6507x-pmic",
},
{
.name = "tps6507x-ts",
},
};
static int tps6507x_i2c_read_device(struct tps6507x_dev *tps6507x, char reg,
int bytes, void *dest)
{
struct i2c_client *i2c = tps6507x->i2c_client;
struct i2c_msg xfer[2];
int ret;
/* Write register */
xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = bytes;
xfer[1].buf = dest;
ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret == 2)
ret = 0;
else if (ret >= 0)
ret = -EIO;
return ret;
}
static int tps6507x_i2c_write_device(struct tps6507x_dev *tps6507x, char reg,
int bytes, void *src)
{
struct i2c_client *i2c = tps6507x->i2c_client;
/* we add 1 byte for device register */
u8 msg[TPS6507X_MAX_REGISTER + 1];
int ret;
if (bytes > (TPS6507X_MAX_REGISTER + 1))
return -EINVAL;
msg[0] = reg;
memcpy(&msg[1], src, bytes);
ret = i2c_master_send(i2c, msg, bytes + 1);
if (ret < 0)
return ret;
if (ret != bytes + 1)
return -EIO;
return 0;
}
static int tps6507x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tps6507x_dev *tps6507x;
int ret = 0;
tps6507x = kzalloc(sizeof(struct tps6507x_dev), GFP_KERNEL);
if (tps6507x == NULL) {
kfree(i2c);
return -ENOMEM;
}
i2c_set_clientdata(i2c, tps6507x);
tps6507x->dev = &i2c->dev;
tps6507x->i2c_client = i2c;
tps6507x->read_dev = tps6507x_i2c_read_device;
tps6507x->write_dev = tps6507x_i2c_write_device;
ret = mfd_add_devices(tps6507x->dev, -1,
tps6507x_devs, ARRAY_SIZE(tps6507x_devs),
NULL, 0);
if (ret < 0)
goto err;
return ret;
err:
mfd_remove_devices(tps6507x->dev);
kfree(tps6507x);
return ret;
}
static int tps6507x_i2c_remove(struct i2c_client *i2c)
{
struct tps6507x_dev *tps6507x = i2c_get_clientdata(i2c);
mfd_remove_devices(tps6507x->dev);
kfree(tps6507x);
return 0;
}
static const struct i2c_device_id tps6507x_i2c_id[] = {
{ "tps6507x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
static struct i2c_driver tps6507x_i2c_driver = {
.driver = {
.name = "tps6507x",
.owner = THIS_MODULE,
},
.probe = tps6507x_i2c_probe,
.remove = tps6507x_i2c_remove,
.id_table = tps6507x_i2c_id,
};
static int __init tps6507x_i2c_init(void)
{
return i2c_add_driver(&tps6507x_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(tps6507x_i2c_init);
static void __exit tps6507x_i2c_exit(void)
{
i2c_del_driver(&tps6507x_i2c_driver);
}
module_exit(tps6507x_i2c_exit);
MODULE_DESCRIPTION("TPS6507x chip family multi-function driver");
MODULE_LICENSE("GPL");
...@@ -232,10 +232,11 @@ static const struct sih sih_modules_twl5031[8] = { ...@@ -232,10 +232,11 @@ static const struct sih sih_modules_twl5031[8] = {
}, },
[6] = { [6] = {
/* /*
* ACI doesn't use the same SIH organization. * ECI/DBI doesn't use the same SIH organization.
* For example, it supports only one interrupt line * For example, it supports only one interrupt output line.
* That is, the interrupts are seen on both INT1 and INT2 lines.
*/ */
.name = "aci", .name = "eci_dbi",
.module = TWL5031_MODULE_ACCESSORY, .module = TWL5031_MODULE_ACCESSORY,
.bits = 9, .bits = 9,
.bytes_ixr = 2, .bytes_ixr = 2,
...@@ -247,8 +248,8 @@ static const struct sih sih_modules_twl5031[8] = { ...@@ -247,8 +248,8 @@ static const struct sih sih_modules_twl5031[8] = {
}, },
[7] = { [7] = {
/* Accessory */ /* Audio accessory */
.name = "acc", .name = "audio",
.module = TWL5031_MODULE_ACCESSORY, .module = TWL5031_MODULE_ACCESSORY,
.control_offset = TWL5031_ACCSIHCTRL, .control_offset = TWL5031_ACCSIHCTRL,
.bits = 2, .bits = 2,
......
...@@ -322,7 +322,11 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits); ...@@ -322,7 +322,11 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits);
*/ */
int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
{ {
int ret, src; int ret, src, irq_masked, timeout;
/* Are we using the interrupt? */
irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK);
irq_masked &= WM831X_AUXADC_DATA_EINT;
mutex_lock(&wm831x->auxadc_lock); mutex_lock(&wm831x->auxadc_lock);
...@@ -342,6 +346,9 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) ...@@ -342,6 +346,9 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
goto out; goto out;
} }
/* Clear any notification from a very late arriving interrupt */
try_wait_for_completion(&wm831x->auxadc_done);
ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
if (ret < 0) { if (ret < 0) {
...@@ -349,23 +356,47 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) ...@@ -349,23 +356,47 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
goto disable; goto disable;
} }
/* If an interrupt arrived late clean up after it */ if (irq_masked) {
try_wait_for_completion(&wm831x->auxadc_done); /* If we're not using interrupts then poll the
* interrupt status register */
timeout = 5;
while (timeout) {
msleep(1);
/* Ignore the result to allow us to soldier on without IRQ hookup */ ret = wm831x_reg_read(wm831x,
wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5)); WM831X_INTERRUPT_STATUS_1);
ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
if (ret < 0) { if (ret < 0) {
dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret); dev_err(wm831x->dev,
"ISR 1 read failed: %d\n", ret);
goto disable; goto disable;
} }
if (ret & WM831X_AUX_CVT_ENA) { /* Did it complete? */
dev_err(wm831x->dev, "Timed out reading AUXADC\n"); if (ret & WM831X_AUXADC_DATA_EINT) {
wm831x_reg_write(wm831x,
WM831X_INTERRUPT_STATUS_1,
WM831X_AUXADC_DATA_EINT);
break;
} else {
dev_err(wm831x->dev,
"AUXADC conversion timeout\n");
ret = -EBUSY; ret = -EBUSY;
goto disable; goto disable;
} }
}
} else {
/* If we are using interrupts then wait for the
* interrupt to complete. Use an extremely long
* timeout to handle situations with heavy load where
* the notification of the interrupt may be delayed by
* threaded IRQ handling. */
if (!wait_for_completion_timeout(&wm831x->auxadc_done,
msecs_to_jiffies(500))) {
dev_err(wm831x->dev, "Timed out waiting for AUXADC\n");
ret = -EBUSY;
goto disable;
}
}
ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
if (ret < 0) { if (ret < 0) {
...@@ -1463,6 +1494,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ...@@ -1463,6 +1494,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8310: case WM8310:
parent = WM8310; parent = WM8310;
wm831x->num_gpio = 16; wm831x->num_gpio = 16;
wm831x->charger_irq_wake = 1;
if (rev > 0) { if (rev > 0) {
wm831x->has_gpio_ena = 1; wm831x->has_gpio_ena = 1;
wm831x->has_cs_sts = 1; wm831x->has_cs_sts = 1;
...@@ -1474,6 +1506,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ...@@ -1474,6 +1506,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8311: case WM8311:
parent = WM8311; parent = WM8311;
wm831x->num_gpio = 16; wm831x->num_gpio = 16;
wm831x->charger_irq_wake = 1;
if (rev > 0) { if (rev > 0) {
wm831x->has_gpio_ena = 1; wm831x->has_gpio_ena = 1;
wm831x->has_cs_sts = 1; wm831x->has_cs_sts = 1;
...@@ -1485,6 +1518,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) ...@@ -1485,6 +1518,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8312: case WM8312:
parent = WM8312; parent = WM8312;
wm831x->num_gpio = 16; wm831x->num_gpio = 16;
wm831x->charger_irq_wake = 1;
if (rev > 0) { if (rev > 0) {
wm831x->has_gpio_ena = 1; wm831x->has_gpio_ena = 1;
wm831x->has_cs_sts = 1; wm831x->has_cs_sts = 1;
...@@ -1623,6 +1657,42 @@ static void wm831x_device_exit(struct wm831x *wm831x) ...@@ -1623,6 +1657,42 @@ static void wm831x_device_exit(struct wm831x *wm831x)
kfree(wm831x); kfree(wm831x);
} }
static int wm831x_device_suspend(struct wm831x *wm831x)
{
int reg, mask;
/* If the charger IRQs are a wake source then make sure we ack
* them even if they're not actively being used (eg, no power
* driver or no IRQ line wired up) then acknowledge the
* interrupts otherwise suspend won't last very long.
*/
if (wm831x->charger_irq_wake) {
reg = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_2_MASK);
mask = WM831X_CHG_BATT_HOT_EINT |
WM831X_CHG_BATT_COLD_EINT |
WM831X_CHG_BATT_FAIL_EINT |
WM831X_CHG_OV_EINT | WM831X_CHG_END_EINT |
WM831X_CHG_TO_EINT | WM831X_CHG_MODE_EINT |
WM831X_CHG_START_EINT;
/* If any of the interrupts are masked read the statuses */
if (reg & mask)
reg = wm831x_reg_read(wm831x,
WM831X_INTERRUPT_STATUS_2);
if (reg & mask) {
dev_info(wm831x->dev,
"Acknowledging masked charger IRQs: %x\n",
reg & mask);
wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_2,
reg & mask);
}
}
return 0;
}
static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg, static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
int bytes, void *dest) int bytes, void *dest)
{ {
...@@ -1697,6 +1767,13 @@ static int wm831x_i2c_remove(struct i2c_client *i2c) ...@@ -1697,6 +1767,13 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
return 0; return 0;
} }
static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
{
struct wm831x *wm831x = i2c_get_clientdata(i2c);
return wm831x_device_suspend(wm831x);
}
static const struct i2c_device_id wm831x_i2c_id[] = { static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8310", WM8310 }, { "wm8310", WM8310 },
{ "wm8311", WM8311 }, { "wm8311", WM8311 },
...@@ -1714,6 +1791,7 @@ static struct i2c_driver wm831x_i2c_driver = { ...@@ -1714,6 +1791,7 @@ static struct i2c_driver wm831x_i2c_driver = {
}, },
.probe = wm831x_i2c_probe, .probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove, .remove = wm831x_i2c_remove,
.suspend = wm831x_i2c_suspend,
.id_table = wm831x_i2c_id, .id_table = wm831x_i2c_id,
}; };
......
...@@ -39,8 +39,6 @@ struct wm831x_irq_data { ...@@ -39,8 +39,6 @@ struct wm831x_irq_data {
int primary; int primary;
int reg; int reg;
int mask; int mask;
irq_handler_t handler;
void *handler_data;
}; };
static struct wm831x_irq_data wm831x_irqs[] = { static struct wm831x_irq_data wm831x_irqs[] = {
...@@ -492,6 +490,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) ...@@ -492,6 +490,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
mutex_init(&wm831x->irq_lock); mutex_init(&wm831x->irq_lock);
/* Mask the individual interrupt sources */
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
wm831x->irq_masks_cur[i] = 0xffff;
wm831x->irq_masks_cache[i] = 0xffff;
wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i,
0xffff);
}
if (!irq) { if (!irq) {
dev_warn(wm831x->dev, dev_warn(wm831x->dev,
"No interrupt specified - functionality limited\n"); "No interrupt specified - functionality limited\n");
...@@ -507,14 +513,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) ...@@ -507,14 +513,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
wm831x->irq = irq; wm831x->irq = irq;
wm831x->irq_base = pdata->irq_base; wm831x->irq_base = pdata->irq_base;
/* Mask the individual interrupt sources */
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
wm831x->irq_masks_cur[i] = 0xffff;
wm831x->irq_masks_cache[i] = 0xffff;
wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i,
0xffff);
}
/* Register them with genirq */ /* Register them with genirq */
for (cur_irq = wm831x->irq_base; for (cur_irq = wm831x->irq_base;
cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
......
...@@ -64,10 +64,8 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, ...@@ -64,10 +64,8 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
int ret = 0; int ret = 0;
wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL); wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
if (wm8350 == NULL) { if (wm8350 == NULL)
kfree(i2c);
return -ENOMEM; return -ENOMEM;
}
i2c_set_clientdata(i2c, wm8350); i2c_set_clientdata(i2c, wm8350);
wm8350->dev = &i2c->dev; wm8350->dev = &i2c->dev;
...@@ -82,6 +80,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, ...@@ -82,6 +80,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
return ret; return ret;
err: err:
i2c_set_clientdata(i2c, NULL);
kfree(wm8350); kfree(wm8350);
return ret; return ret;
} }
...@@ -91,6 +90,7 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) ...@@ -91,6 +90,7 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
struct wm8350 *wm8350 = i2c_get_clientdata(i2c); struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
wm8350_device_exit(wm8350); wm8350_device_exit(wm8350);
i2c_set_clientdata(i2c, NULL);
kfree(wm8350); kfree(wm8350);
return 0; return 0;
......
...@@ -118,7 +118,7 @@ static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest) ...@@ -118,7 +118,7 @@ static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
{ {
int i, ret = 0; int i, ret = 0;
BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); BUG_ON(reg + num_regs > ARRAY_SIZE(wm8400->reg_cache));
/* If there are any volatile reads then read back the entire block */ /* If there are any volatile reads then read back the entire block */
for (i = reg; i < reg + num_regs; i++) for (i = reg; i < reg + num_regs; i++)
...@@ -144,7 +144,7 @@ static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs, ...@@ -144,7 +144,7 @@ static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
{ {
int ret, i; int ret, i;
BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache)); BUG_ON(reg + num_regs > ARRAY_SIZE(wm8400->reg_cache));
for (i = 0; i < num_regs; i++) { for (i = 0; i < num_regs; i++) {
BUG_ON(!reg_data[reg + i].writable); BUG_ON(!reg_data[reg + i].writable);
......
...@@ -63,6 +63,16 @@ config CAN_BFIN ...@@ -63,6 +63,16 @@ config CAN_BFIN
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called bfin_can. module will be called bfin_can.
config CAN_JANZ_ICAN3
tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
depends on CAN_DEV && MFD_JANZ_CMODIO
---help---
Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
connects to a MODULbus carrier board.
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
source "drivers/net/can/mscan/Kconfig" source "drivers/net/can/mscan/Kconfig"
source "drivers/net/can/sja1000/Kconfig" source "drivers/net/can/sja1000/Kconfig"
......
...@@ -15,5 +15,6 @@ obj-$(CONFIG_CAN_AT91) += at91_can.o ...@@ -15,5 +15,6 @@ obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
/*
* Janz MODULbus VMOD-ICAN3 CAN Interface Driver
*
* Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/mfd/janz.h>
/* the DPM has 64k of memory, organized into 256x 256 byte pages */
#define DPM_NUM_PAGES 256
#define DPM_PAGE_SIZE 256
#define DPM_PAGE_ADDR(p) ((p) * DPM_PAGE_SIZE)
/* JANZ ICAN3 "old-style" host interface queue page numbers */
#define QUEUE_OLD_CONTROL 0
#define QUEUE_OLD_RB0 1
#define QUEUE_OLD_RB1 2
#define QUEUE_OLD_WB0 3
#define QUEUE_OLD_WB1 4
/* Janz ICAN3 "old-style" host interface control registers */
#define MSYNC_PEER 0x00 /* ICAN only */
#define MSYNC_LOCL 0x01 /* host only */
#define TARGET_RUNNING 0x02
#define MSYNC_RB0 0x01
#define MSYNC_RB1 0x02
#define MSYNC_RBLW 0x04
#define MSYNC_RB_MASK (MSYNC_RB0 | MSYNC_RB1)
#define MSYNC_WB0 0x10
#define MSYNC_WB1 0x20
#define MSYNC_WBLW 0x40
#define MSYNC_WB_MASK (MSYNC_WB0 | MSYNC_WB1)
/* Janz ICAN3 "new-style" host interface queue page numbers */
#define QUEUE_TOHOST 5
#define QUEUE_FROMHOST_MID 6
#define QUEUE_FROMHOST_HIGH 7
#define QUEUE_FROMHOST_LOW 8
/* The first free page in the DPM is #9 */
#define DPM_FREE_START 9
/* Janz ICAN3 "new-style" and "fast" host interface descriptor flags */
#define DESC_VALID 0x80
#define DESC_WRAP 0x40
#define DESC_INTERRUPT 0x20
#define DESC_IVALID 0x10
#define DESC_LEN(len) (len)
/* Janz ICAN3 Firmware Messages */
#define MSG_CONNECTI 0x02
#define MSG_DISCONNECT 0x03
#define MSG_IDVERS 0x04
#define MSG_MSGLOST 0x05
#define MSG_NEWHOSTIF 0x08
#define MSG_INQUIRY 0x0a
#define MSG_SETAFILMASK 0x10
#define MSG_INITFDPMQUEUE 0x11
#define MSG_HWCONF 0x12
#define MSG_FMSGLOST 0x15
#define MSG_CEVTIND 0x37
#define MSG_CBTRREQ 0x41
#define MSG_COFFREQ 0x42
#define MSG_CONREQ 0x43
#define MSG_CCONFREQ 0x47
/*
* Janz ICAN3 CAN Inquiry Message Types
*
* NOTE: there appears to be a firmware bug here. You must send
* NOTE: INQUIRY_STATUS and expect to receive an INQUIRY_EXTENDED
* NOTE: response. The controller never responds to a message with
* NOTE: the INQUIRY_EXTENDED subspec :(
*/
#define INQUIRY_STATUS 0x00
#define INQUIRY_TERMINATION 0x01
#define INQUIRY_EXTENDED 0x04
/* Janz ICAN3 CAN Set Acceptance Filter Mask Message Types */
#define SETAFILMASK_REJECT 0x00
#define SETAFILMASK_FASTIF 0x02
/* Janz ICAN3 CAN Hardware Configuration Message Types */
#define HWCONF_TERMINATE_ON 0x01
#define HWCONF_TERMINATE_OFF 0x00
/* Janz ICAN3 CAN Event Indication Message Types */
#define CEVTIND_EI 0x01
#define CEVTIND_DOI 0x02
#define CEVTIND_LOST 0x04
#define CEVTIND_FULL 0x08
#define CEVTIND_BEI 0x10
#define CEVTIND_CHIP_SJA1000 0x02
#define ICAN3_BUSERR_QUOTA_MAX 255
/* Janz ICAN3 CAN Frame Conversion */
#define ICAN3_ECHO 0x10
#define ICAN3_EFF_RTR 0x40
#define ICAN3_SFF_RTR 0x10
#define ICAN3_EFF 0x80
#define ICAN3_CAN_TYPE_MASK 0x0f
#define ICAN3_CAN_TYPE_SFF 0x00
#define ICAN3_CAN_TYPE_EFF 0x01
#define ICAN3_CAN_DLC_MASK 0x0f
/*
* SJA1000 Status and Error Register Definitions
*
* Copied from drivers/net/can/sja1000/sja1000.h
*/
/* status register content */
#define SR_BS 0x80
#define SR_ES 0x40
#define SR_TS 0x20
#define SR_RS 0x10
#define SR_TCS 0x08
#define SR_TBS 0x04
#define SR_DOS 0x02
#define SR_RBS 0x01
#define SR_CRIT (SR_BS|SR_ES)
/* ECC register */
#define ECC_SEG 0x1F
#define ECC_DIR 0x20
#define ECC_ERR 6
#define ECC_BIT 0x00
#define ECC_FORM 0x40
#define ECC_STUFF 0x80
#define ECC_MASK 0xc0
/* Number of buffers for use in the "new-style" host interface */
#define ICAN3_NEW_BUFFERS 16
/* Number of buffers for use in the "fast" host interface */
#define ICAN3_TX_BUFFERS 512
#define ICAN3_RX_BUFFERS 1024
/* SJA1000 Clock Input */
#define ICAN3_CAN_CLOCK 8000000
/* Driver Name */
#define DRV_NAME "janz-ican3"
/* DPM Control Registers -- starts at offset 0x100 in the MODULbus registers */
struct ican3_dpm_control {
/* window address register */
u8 window_address;
u8 unused1;
/*
* Read access: clear interrupt from microcontroller
* Write access: send interrupt to microcontroller
*/
u8 interrupt;
u8 unused2;
/* write-only: reset all hardware on the module */
u8 hwreset;
u8 unused3;
/* write-only: generate an interrupt to the TPU */
u8 tpuinterrupt;
};
struct ican3_dev {
/* must be the first member */
struct can_priv can;
/* CAN network device */
struct net_device *ndev;
struct napi_struct napi;
/* Device for printing */
struct device *dev;
/* module number */
unsigned int num;
/* base address of registers and IRQ */
struct janz_cmodio_onboard_regs __iomem *ctrl;
struct ican3_dpm_control __iomem *dpmctrl;
void __iomem *dpm;
int irq;
/* CAN bus termination status */
struct completion termination_comp;
bool termination_enabled;
/* CAN bus error status registers */
struct completion buserror_comp;
struct can_berr_counter bec;
/* old and new style host interface */
unsigned int iftype;
/*
* Any function which changes the current DPM page must hold this
* lock while it is performing data accesses. This ensures that the
* function will not be preempted and end up reading data from a
* different DPM page than it expects.
*/
spinlock_t lock;
/* new host interface */
unsigned int rx_int;
unsigned int rx_num;
unsigned int tx_num;
/* fast host interface */
unsigned int fastrx_start;
unsigned int fastrx_int;
unsigned int fastrx_num;
unsigned int fasttx_start;
unsigned int fasttx_num;
/* first free DPM page */
unsigned int free_page;
};
struct ican3_msg {
u8 control;
u8 spec;
__le16 len;
u8 data[252];
};
struct ican3_new_desc {
u8 control;
u8 pointer;
};
struct ican3_fast_desc {
u8 control;
u8 command;
u8 data[14];
};
/* write to the window basic address register */
static inline void ican3_set_page(struct ican3_dev *mod, unsigned int page)
{
BUG_ON(page >= DPM_NUM_PAGES);
iowrite8(page, &mod->dpmctrl->window_address);
}
/*
* ICAN3 "old-style" host interface
*/
/*
* Recieve a message from the ICAN3 "old-style" firmware interface
*
* LOCKING: must hold mod->lock
*
* returns 0 on success, -ENOMEM when no message exists
*/
static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
unsigned int mbox, mbox_page;
u8 locl, peer, xord;
/* get the MSYNC registers */
ican3_set_page(mod, QUEUE_OLD_CONTROL);
peer = ioread8(mod->dpm + MSYNC_PEER);
locl = ioread8(mod->dpm + MSYNC_LOCL);
xord = locl ^ peer;
if ((xord & MSYNC_RB_MASK) == 0x00) {
dev_dbg(mod->dev, "no mbox for reading\n");
return -ENOMEM;
}
/* find the first free mbox to read */
if ((xord & MSYNC_RB_MASK) == MSYNC_RB_MASK)
mbox = (xord & MSYNC_RBLW) ? MSYNC_RB0 : MSYNC_RB1;
else
mbox = (xord & MSYNC_RB0) ? MSYNC_RB0 : MSYNC_RB1;
/* copy the message */
mbox_page = (mbox == MSYNC_RB0) ? QUEUE_OLD_RB0 : QUEUE_OLD_RB1;
ican3_set_page(mod, mbox_page);
memcpy_fromio(msg, mod->dpm, sizeof(*msg));
/*
* notify the firmware that the read buffer is available
* for it to fill again
*/
locl ^= mbox;
ican3_set_page(mod, QUEUE_OLD_CONTROL);
iowrite8(locl, mod->dpm + MSYNC_LOCL);
return 0;
}
/*
* Send a message through the "old-style" firmware interface
*
* LOCKING: must hold mod->lock
*
* returns 0 on success, -ENOMEM when no free space exists
*/
static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
unsigned int mbox, mbox_page;
u8 locl, peer, xord;
/* get the MSYNC registers */
ican3_set_page(mod, QUEUE_OLD_CONTROL);
peer = ioread8(mod->dpm + MSYNC_PEER);
locl = ioread8(mod->dpm + MSYNC_LOCL);
xord = locl ^ peer;
if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
dev_err(mod->dev, "no mbox for writing\n");
return -ENOMEM;
}
/* calculate a free mbox to use */
mbox = (xord & MSYNC_WB0) ? MSYNC_WB1 : MSYNC_WB0;
/* copy the message to the DPM */
mbox_page = (mbox == MSYNC_WB0) ? QUEUE_OLD_WB0 : QUEUE_OLD_WB1;
ican3_set_page(mod, mbox_page);
memcpy_toio(mod->dpm, msg, sizeof(*msg));
locl ^= mbox;
if (mbox == MSYNC_WB1)
locl |= MSYNC_WBLW;
ican3_set_page(mod, QUEUE_OLD_CONTROL);
iowrite8(locl, mod->dpm + MSYNC_LOCL);
return 0;
}
/*
* ICAN3 "new-style" Host Interface Setup
*/
static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod)
{
struct ican3_new_desc desc;
unsigned long flags;
void __iomem *dst;
int i;
spin_lock_irqsave(&mod->lock, flags);
/* setup the internal datastructures for RX */
mod->rx_num = 0;
mod->rx_int = 0;
/* tohost queue descriptors are in page 5 */
ican3_set_page(mod, QUEUE_TOHOST);
dst = mod->dpm;
/* initialize the tohost (rx) queue descriptors: pages 9-24 */
for (i = 0; i < ICAN3_NEW_BUFFERS; i++) {
desc.control = DESC_INTERRUPT | DESC_LEN(1); /* I L=1 */
desc.pointer = mod->free_page;
/* set wrap flag on last buffer */
if (i == ICAN3_NEW_BUFFERS - 1)
desc.control |= DESC_WRAP;
memcpy_toio(dst, &desc, sizeof(desc));
dst += sizeof(desc);
mod->free_page++;
}
/* fromhost (tx) mid queue descriptors are in page 6 */
ican3_set_page(mod, QUEUE_FROMHOST_MID);
dst = mod->dpm;
/* setup the internal datastructures for TX */
mod->tx_num = 0;
/* initialize the fromhost mid queue descriptors: pages 25-40 */
for (i = 0; i < ICAN3_NEW_BUFFERS; i++) {
desc.control = DESC_VALID | DESC_LEN(1); /* V L=1 */
desc.pointer = mod->free_page;
/* set wrap flag on last buffer */
if (i == ICAN3_NEW_BUFFERS - 1)
desc.control |= DESC_WRAP;
memcpy_toio(dst, &desc, sizeof(desc));
dst += sizeof(desc);
mod->free_page++;
}
/* fromhost hi queue descriptors are in page 7 */
ican3_set_page(mod, QUEUE_FROMHOST_HIGH);
dst = mod->dpm;
/* initialize only a single buffer in the fromhost hi queue (unused) */
desc.control = DESC_VALID | DESC_WRAP | DESC_LEN(1); /* VW L=1 */
desc.pointer = mod->free_page;
memcpy_toio(dst, &desc, sizeof(desc));
mod->free_page++;
/* fromhost low queue descriptors are in page 8 */
ican3_set_page(mod, QUEUE_FROMHOST_LOW);
dst = mod->dpm;
/* initialize only a single buffer in the fromhost low queue (unused) */
desc.control = DESC_VALID | DESC_WRAP | DESC_LEN(1); /* VW L=1 */
desc.pointer = mod->free_page;
memcpy_toio(dst, &desc, sizeof(desc));
mod->free_page++;
spin_unlock_irqrestore(&mod->lock, flags);
}
/*
* ICAN3 Fast Host Interface Setup
*/
static void __devinit ican3_init_fast_host_interface(struct ican3_dev *mod)
{
struct ican3_fast_desc desc;
unsigned long flags;
unsigned int addr;
void __iomem *dst;
int i;
spin_lock_irqsave(&mod->lock, flags);
/* save the start recv page */
mod->fastrx_start = mod->free_page;
mod->fastrx_num = 0;
mod->fastrx_int = 0;
/* build a single fast tohost queue descriptor */
memset(&desc, 0, sizeof(desc));
desc.control = 0x00;
desc.command = 1;
/* build the tohost queue descriptor ring in memory */
addr = 0;
for (i = 0; i < ICAN3_RX_BUFFERS; i++) {
/* set the wrap bit on the last buffer */
if (i == ICAN3_RX_BUFFERS - 1)
desc.control |= DESC_WRAP;
/* switch to the correct page */
ican3_set_page(mod, mod->free_page);
/* copy the descriptor to the DPM */
dst = mod->dpm + addr;
memcpy_toio(dst, &desc, sizeof(desc));
addr += sizeof(desc);
/* move to the next page if necessary */
if (addr >= DPM_PAGE_SIZE) {
addr = 0;
mod->free_page++;
}
}
/* make sure we page-align the next queue */
if (addr != 0)
mod->free_page++;
/* save the start xmit page */
mod->fasttx_start = mod->free_page;
mod->fasttx_num = 0;
/* build a single fast fromhost queue descriptor */
memset(&desc, 0, sizeof(desc));
desc.control = DESC_VALID;
desc.command = 1;
/* build the fromhost queue descriptor ring in memory */
addr = 0;
for (i = 0; i < ICAN3_TX_BUFFERS; i++) {
/* set the wrap bit on the last buffer */
if (i == ICAN3_TX_BUFFERS - 1)
desc.control |= DESC_WRAP;
/* switch to the correct page */
ican3_set_page(mod, mod->free_page);
/* copy the descriptor to the DPM */
dst = mod->dpm + addr;
memcpy_toio(dst, &desc, sizeof(desc));
addr += sizeof(desc);
/* move to the next page if necessary */
if (addr >= DPM_PAGE_SIZE) {
addr = 0;
mod->free_page++;
}
}
spin_unlock_irqrestore(&mod->lock, flags);
}
/*
* ICAN3 "new-style" Host Interface Message Helpers
*/
/*
* LOCKING: must hold mod->lock
*/
static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
struct ican3_new_desc desc;
void __iomem *desc_addr = mod->dpm + (mod->tx_num * sizeof(desc));
/* switch to the fromhost mid queue, and read the buffer descriptor */
ican3_set_page(mod, QUEUE_FROMHOST_MID);
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
return -ENOMEM;
}
/* switch to the data page, copy the data */
ican3_set_page(mod, desc.pointer);
memcpy_toio(mod->dpm, msg, sizeof(*msg));
/* switch back to the descriptor, set the valid bit, write it back */
ican3_set_page(mod, QUEUE_FROMHOST_MID);
desc.control ^= DESC_VALID;
memcpy_toio(desc_addr, &desc, sizeof(desc));
/* update the tx number */
mod->tx_num = (desc.control & DESC_WRAP) ? 0 : (mod->tx_num + 1);
return 0;
}
/*
* LOCKING: must hold mod->lock
*/
static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
struct ican3_new_desc desc;
void __iomem *desc_addr = mod->dpm + (mod->rx_num * sizeof(desc));
/* switch to the tohost queue, and read the buffer descriptor */
ican3_set_page(mod, QUEUE_TOHOST);
memcpy_fromio(&desc, desc_addr, sizeof(desc));
if (!(desc.control & DESC_VALID)) {
dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
return -ENOMEM;
}
/* switch to the data page, copy the data */
ican3_set_page(mod, desc.pointer);
memcpy_fromio(msg, mod->dpm, sizeof(*msg));
/* switch back to the descriptor, toggle the valid bit, write it back */
ican3_set_page(mod, QUEUE_TOHOST);
desc.control ^= DESC_VALID;
memcpy_toio(desc_addr, &desc, sizeof(desc));
/* update the rx number */
mod->rx_num = (desc.control & DESC_WRAP) ? 0 : (mod->rx_num + 1);
return 0;
}
/*
* Message Send / Recv Helpers
*/
static int ican3_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&mod->lock, flags);
if (mod->iftype == 0)
ret = ican3_old_send_msg(mod, msg);
else
ret = ican3_new_send_msg(mod, msg);
spin_unlock_irqrestore(&mod->lock, flags);
return ret;
}
static int ican3_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&mod->lock, flags);
if (mod->iftype == 0)
ret = ican3_old_recv_msg(mod, msg);
else
ret = ican3_new_recv_msg(mod, msg);
spin_unlock_irqrestore(&mod->lock, flags);
return ret;
}
/*
* Quick Pre-constructed Messages
*/
static int __devinit ican3_msg_connect(struct ican3_dev *mod)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_CONNECTI;
msg.len = cpu_to_le16(0);
return ican3_send_msg(mod, &msg);
}
static int __devexit ican3_msg_disconnect(struct ican3_dev *mod)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_DISCONNECT;
msg.len = cpu_to_le16(0);
return ican3_send_msg(mod, &msg);
}
static int __devinit ican3_msg_newhostif(struct ican3_dev *mod)
{
struct ican3_msg msg;
int ret;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_NEWHOSTIF;
msg.len = cpu_to_le16(0);
/* If we're not using the old interface, switching seems bogus */
WARN_ON(mod->iftype != 0);
ret = ican3_send_msg(mod, &msg);
if (ret)
return ret;
/* mark the module as using the new host interface */
mod->iftype = 1;
return 0;
}
static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod)
{
struct ican3_msg msg;
unsigned int addr;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_INITFDPMQUEUE;
msg.len = cpu_to_le16(8);
/* write the tohost queue start address */
addr = DPM_PAGE_ADDR(mod->fastrx_start);
msg.data[0] = addr & 0xff;
msg.data[1] = (addr >> 8) & 0xff;
msg.data[2] = (addr >> 16) & 0xff;
msg.data[3] = (addr >> 24) & 0xff;
/* write the fromhost queue start address */
addr = DPM_PAGE_ADDR(mod->fasttx_start);
msg.data[4] = addr & 0xff;
msg.data[5] = (addr >> 8) & 0xff;
msg.data[6] = (addr >> 16) & 0xff;
msg.data[7] = (addr >> 24) & 0xff;
/* If we're not using the new interface yet, we cannot do this */
WARN_ON(mod->iftype != 1);
return ican3_send_msg(mod, &msg);
}
/*
* Setup the CAN filter to either accept or reject all
* messages from the CAN bus.
*/
static int __devinit ican3_set_id_filter(struct ican3_dev *mod, bool accept)
{
struct ican3_msg msg;
int ret;
/* Standard Frame Format */
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_SETAFILMASK;
msg.len = cpu_to_le16(5);
msg.data[0] = 0x00; /* IDLo LSB */
msg.data[1] = 0x00; /* IDLo MSB */
msg.data[2] = 0xff; /* IDHi LSB */
msg.data[3] = 0x07; /* IDHi MSB */
/* accept all frames for fast host if, or reject all frames */
msg.data[4] = accept ? SETAFILMASK_FASTIF : SETAFILMASK_REJECT;
ret = ican3_send_msg(mod, &msg);
if (ret)
return ret;
/* Extended Frame Format */
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_SETAFILMASK;
msg.len = cpu_to_le16(13);
msg.data[0] = 0; /* MUX = 0 */
msg.data[1] = 0x00; /* IDLo LSB */
msg.data[2] = 0x00;
msg.data[3] = 0x00;
msg.data[4] = 0x20; /* IDLo MSB */
msg.data[5] = 0xff; /* IDHi LSB */
msg.data[6] = 0xff;
msg.data[7] = 0xff;
msg.data[8] = 0x3f; /* IDHi MSB */
/* accept all frames for fast host if, or reject all frames */
msg.data[9] = accept ? SETAFILMASK_FASTIF : SETAFILMASK_REJECT;
return ican3_send_msg(mod, &msg);
}
/*
* Bring the CAN bus online or offline
*/
static int ican3_set_bus_state(struct ican3_dev *mod, bool on)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = on ? MSG_CONREQ : MSG_COFFREQ;
msg.len = cpu_to_le16(0);
return ican3_send_msg(mod, &msg);
}
static int ican3_set_termination(struct ican3_dev *mod, bool on)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_HWCONF;
msg.len = cpu_to_le16(2);
msg.data[0] = 0x00;
msg.data[1] = on ? HWCONF_TERMINATE_ON : HWCONF_TERMINATE_OFF;
return ican3_send_msg(mod, &msg);
}
static int ican3_send_inquiry(struct ican3_dev *mod, u8 subspec)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_INQUIRY;
msg.len = cpu_to_le16(2);
msg.data[0] = subspec;
msg.data[1] = 0x00;
return ican3_send_msg(mod, &msg);
}
static int ican3_set_buserror(struct ican3_dev *mod, u8 quota)
{
struct ican3_msg msg;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_CCONFREQ;
msg.len = cpu_to_le16(2);
msg.data[0] = 0x00;
msg.data[1] = quota;
return ican3_send_msg(mod, &msg);
}
/*
* ICAN3 to Linux CAN Frame Conversion
*/
static void ican3_to_can_frame(struct ican3_dev *mod,
struct ican3_fast_desc *desc,
struct can_frame *cf)
{
if ((desc->command & ICAN3_CAN_TYPE_MASK) == ICAN3_CAN_TYPE_SFF) {
if (desc->data[1] & ICAN3_SFF_RTR)
cf->can_id |= CAN_RTR_FLAG;
cf->can_id |= desc->data[0] << 3;
cf->can_id |= (desc->data[1] & 0xe0) >> 5;
cf->can_dlc = desc->data[1] & ICAN3_CAN_DLC_MASK;
memcpy(cf->data, &desc->data[2], sizeof(cf->data));
} else {
cf->can_dlc = desc->data[0] & ICAN3_CAN_DLC_MASK;
if (desc->data[0] & ICAN3_EFF_RTR)
cf->can_id |= CAN_RTR_FLAG;
if (desc->data[0] & ICAN3_EFF) {
cf->can_id |= CAN_EFF_FLAG;
cf->can_id |= desc->data[2] << 21; /* 28-21 */
cf->can_id |= desc->data[3] << 13; /* 20-13 */
cf->can_id |= desc->data[4] << 5; /* 12-5 */
cf->can_id |= (desc->data[5] & 0xf8) >> 3;
} else {
cf->can_id |= desc->data[2] << 3; /* 10-3 */
cf->can_id |= desc->data[3] >> 5; /* 2-0 */
}
memcpy(cf->data, &desc->data[6], sizeof(cf->data));
}
}
static void can_frame_to_ican3(struct ican3_dev *mod,
struct can_frame *cf,
struct ican3_fast_desc *desc)
{
/* clear out any stale data in the descriptor */
memset(desc->data, 0, sizeof(desc->data));
/* we always use the extended format, with the ECHO flag set */
desc->command = ICAN3_CAN_TYPE_EFF;
desc->data[0] |= cf->can_dlc;
desc->data[1] |= ICAN3_ECHO;
if (cf->can_id & CAN_RTR_FLAG)
desc->data[0] |= ICAN3_EFF_RTR;
/* pack the id into the correct places */
if (cf->can_id & CAN_EFF_FLAG) {
desc->data[0] |= ICAN3_EFF;
desc->data[2] = (cf->can_id & 0x1fe00000) >> 21; /* 28-21 */
desc->data[3] = (cf->can_id & 0x001fe000) >> 13; /* 20-13 */
desc->data[4] = (cf->can_id & 0x00001fe0) >> 5; /* 12-5 */
desc->data[5] = (cf->can_id & 0x0000001f) << 3; /* 4-0 */
} else {
desc->data[2] = (cf->can_id & 0x7F8) >> 3; /* bits 10-3 */
desc->data[3] = (cf->can_id & 0x007) << 5; /* bits 2-0 */
}
/* copy the data bits into the descriptor */
memcpy(&desc->data[6], cf->data, sizeof(cf->data));
}
/*
* Interrupt Handling
*/
/*
* Handle an ID + Version message response from the firmware. We never generate
* this message in production code, but it is very useful when debugging to be
* able to display this message.
*/
static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
{
dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
}
static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
{
struct net_device *dev = mod->ndev;
struct net_device_stats *stats = &dev->stats;
struct can_frame *cf;
struct sk_buff *skb;
/*
* Report that communication messages with the microcontroller firmware
* are being lost. These are never CAN frames, so we do not generate an
* error frame for userspace
*/
if (msg->spec == MSG_MSGLOST) {
dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
return;
}
/*
* Oops, this indicates that we have lost messages in the fast queue,
* which are exclusively CAN messages. Our driver isn't reading CAN
* frames fast enough.
*
* We'll pretend that the SJA1000 told us that it ran out of buffer
* space, because there is not a better message for this.
*/
skb = alloc_can_err_skb(dev, &cf);
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_errors++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
}
}
/*
* Handle CAN Event Indication Messages from the firmware
*
* The ICAN3 firmware provides the values of some SJA1000 registers when it
* generates this message. The code below is largely copied from the
* drivers/net/can/sja1000/sja1000.c file, and adapted as necessary
*/
static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
{
struct net_device *dev = mod->ndev;
struct net_device_stats *stats = &dev->stats;
enum can_state state = mod->can.state;
u8 status, isrc, rxerr, txerr;
struct can_frame *cf;
struct sk_buff *skb;
/* we can only handle the SJA1000 part */
if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
return -ENODEV;
}
/* check the message length for sanity */
if (le16_to_cpu(msg->len) < 6) {
dev_err(mod->dev, "error message too short\n");
return -EINVAL;
}
skb = alloc_can_err_skb(dev, &cf);
if (skb == NULL)
return -ENOMEM;
isrc = msg->data[0];
status = msg->data[3];
rxerr = msg->data[4];
txerr = msg->data[5];
/* data overrun interrupt */
if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
dev_dbg(mod->dev, "data overrun interrupt\n");
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_over_errors++;
stats->rx_errors++;
}
/* error warning + passive interrupt */
if (isrc == CEVTIND_EI) {
dev_dbg(mod->dev, "error warning + passive interrupt\n");
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
can_bus_off(dev);
} else if (status & SR_ES) {
if (rxerr >= 128 || txerr >= 128)
state = CAN_STATE_ERROR_PASSIVE;
else
state = CAN_STATE_ERROR_WARNING;
} else {
state = CAN_STATE_ERROR_ACTIVE;
}
}
/* bus error interrupt */
if (isrc == CEVTIND_BEI) {
u8 ecc = msg->data[2];
dev_dbg(mod->dev, "bus error interrupt\n");
mod->can.can_stats.bus_error++;
stats->rx_errors++;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
switch (ecc & ECC_MASK) {
case ECC_BIT:
cf->data[2] |= CAN_ERR_PROT_BIT;
break;
case ECC_FORM:
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case ECC_STUFF:
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & ECC_SEG;
break;
}
if ((ecc & ECC_DIR) == 0)
cf->data[2] |= CAN_ERR_PROT_TX;
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
if (state != mod->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
cf->can_id |= CAN_ERR_CRTL;
if (state == CAN_STATE_ERROR_WARNING) {
mod->can.can_stats.error_warning++;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
} else {
mod->can.can_stats.error_passive++;
cf->data[1] = (txerr > rxerr) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE;
}
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
mod->can.state = state;
stats->rx_errors++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
return 0;
}
static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
{
switch (msg->data[0]) {
case INQUIRY_STATUS:
case INQUIRY_EXTENDED:
mod->bec.rxerr = msg->data[5];
mod->bec.txerr = msg->data[6];
complete(&mod->buserror_comp);
break;
case INQUIRY_TERMINATION:
mod->termination_enabled = msg->data[6] & HWCONF_TERMINATE_ON;
complete(&mod->termination_comp);
break;
default:
dev_err(mod->dev, "recieved an unknown inquiry response\n");
break;
}
}
static void ican3_handle_unknown_message(struct ican3_dev *mod,
struct ican3_msg *msg)
{
dev_warn(mod->dev, "recieved unknown message: spec 0x%.2x length %d\n",
msg->spec, le16_to_cpu(msg->len));
}
/*
* Handle a control message from the firmware
*/
static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
{
dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
mod->num, msg->spec, le16_to_cpu(msg->len));
switch (msg->spec) {
case MSG_IDVERS:
ican3_handle_idvers(mod, msg);
break;
case MSG_MSGLOST:
case MSG_FMSGLOST:
ican3_handle_msglost(mod, msg);
break;
case MSG_CEVTIND:
ican3_handle_cevtind(mod, msg);
break;
case MSG_INQUIRY:
ican3_handle_inquiry(mod, msg);
break;
default:
ican3_handle_unknown_message(mod, msg);
break;
}
}
/*
* Check that there is room in the TX ring to transmit another skb
*
* LOCKING: must hold mod->lock
*/
static bool ican3_txok(struct ican3_dev *mod)
{
struct ican3_fast_desc __iomem *desc;
u8 control;
/* copy the control bits of the descriptor */
ican3_set_page(mod, mod->fasttx_start + (mod->fasttx_num / 16));
desc = mod->dpm + ((mod->fasttx_num % 16) * sizeof(*desc));
control = ioread8(&desc->control);
/* if the control bits are not valid, then we have no more space */
if (!(control & DESC_VALID))
return false;
return true;
}
/*
* Recieve one CAN frame from the hardware
*
* This works like the core of a NAPI function, but is intended to be called
* from workqueue context instead. This driver already needs a workqueue to
* process control messages, so we use the workqueue instead of using NAPI.
* This was done to simplify locking.
*
* CONTEXT: must be called from user context
*/
static int ican3_recv_skb(struct ican3_dev *mod)
{
struct net_device *ndev = mod->ndev;
struct net_device_stats *stats = &ndev->stats;
struct ican3_fast_desc desc;
void __iomem *desc_addr;
struct can_frame *cf;
struct sk_buff *skb;
unsigned long flags;
spin_lock_irqsave(&mod->lock, flags);
/* copy the whole descriptor */
ican3_set_page(mod, mod->fastrx_start + (mod->fastrx_num / 16));
desc_addr = mod->dpm + ((mod->fastrx_num % 16) * sizeof(desc));
memcpy_fromio(&desc, desc_addr, sizeof(desc));
spin_unlock_irqrestore(&mod->lock, flags);
/* check that we actually have a CAN frame */
if (!(desc.control & DESC_VALID))
return -ENOBUFS;
/* allocate an skb */
skb = alloc_can_skb(ndev, &cf);
if (unlikely(skb == NULL)) {
stats->rx_dropped++;
goto err_noalloc;
}
/* convert the ICAN3 frame into Linux CAN format */
ican3_to_can_frame(mod, &desc, cf);
/* receive the skb, update statistics */
netif_receive_skb(skb);
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
err_noalloc:
/* toggle the valid bit and return the descriptor to the ring */
desc.control ^= DESC_VALID;
spin_lock_irqsave(&mod->lock, flags);
ican3_set_page(mod, mod->fastrx_start + (mod->fastrx_num / 16));
memcpy_toio(desc_addr, &desc, 1);
/* update the next buffer pointer */
mod->fastrx_num = (desc.control & DESC_WRAP) ? 0
: (mod->fastrx_num + 1);
/* there are still more buffers to process */
spin_unlock_irqrestore(&mod->lock, flags);
return 0;
}
static int ican3_napi(struct napi_struct *napi, int budget)
{
struct ican3_dev *mod = container_of(napi, struct ican3_dev, napi);
struct ican3_msg msg;
unsigned long flags;
int received = 0;
int ret;
/* process all communication messages */
while (true) {
ret = ican3_recv_msg(mod, &msg);
if (ret)
break;
ican3_handle_message(mod, &msg);
}
/* process all CAN frames from the fast interface */
while (received < budget) {
ret = ican3_recv_skb(mod);
if (ret)
break;
received++;
}
/* We have processed all packets that the adapter had, but it
* was less than our budget, stop polling */
if (received < budget)
napi_complete(napi);
spin_lock_irqsave(&mod->lock, flags);
/* Wake up the transmit queue if necessary */
if (netif_queue_stopped(mod->ndev) && ican3_txok(mod))
netif_wake_queue(mod->ndev);
spin_unlock_irqrestore(&mod->lock, flags);
/* re-enable interrupt generation */
iowrite8(1 << mod->num, &mod->ctrl->int_enable);
return received;
}
static irqreturn_t ican3_irq(int irq, void *dev_id)
{
struct ican3_dev *mod = dev_id;
u8 stat;
/*
* The interrupt status register on this device reports interrupts
* as zeroes instead of using ones like most other devices
*/
stat = ioread8(&mod->ctrl->int_disable) & (1 << mod->num);
if (stat == (1 << mod->num))
return IRQ_NONE;
/* clear the MODULbus interrupt from the microcontroller */
ioread8(&mod->dpmctrl->interrupt);
/* disable interrupt generation, schedule the NAPI poller */
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
napi_schedule(&mod->napi);
return IRQ_HANDLED;
}
/*
* Firmware reset, startup, and shutdown
*/
/*
* Reset an ICAN module to its power-on state
*
* CONTEXT: no network device registered
* LOCKING: work function disabled
*/
static int ican3_reset_module(struct ican3_dev *mod)
{
u8 val = 1 << mod->num;
unsigned long start;
u8 runold, runnew;
/* disable interrupts so no more work is scheduled */
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
/* flush any pending work */
flush_scheduled_work();
/* the first unallocated page in the DPM is #9 */
mod->free_page = DPM_FREE_START;
ican3_set_page(mod, QUEUE_OLD_CONTROL);
runold = ioread8(mod->dpm + TARGET_RUNNING);
/* reset the module */
iowrite8(val, &mod->ctrl->reset_assert);
iowrite8(val, &mod->ctrl->reset_deassert);
/* wait until the module has finished resetting and is running */
start = jiffies;
do {
ican3_set_page(mod, QUEUE_OLD_CONTROL);
runnew = ioread8(mod->dpm + TARGET_RUNNING);
if (runnew == (runold ^ 0xff))
return 0;
msleep(10);
} while (time_before(jiffies, start + HZ / 4));
dev_err(mod->dev, "failed to reset CAN module\n");
return -ETIMEDOUT;
}
static void __devexit ican3_shutdown_module(struct ican3_dev *mod)
{
ican3_msg_disconnect(mod);
ican3_reset_module(mod);
}
/*
* Startup an ICAN module, bringing it into fast mode
*/
static int __devinit ican3_startup_module(struct ican3_dev *mod)
{
int ret;
ret = ican3_reset_module(mod);
if (ret) {
dev_err(mod->dev, "unable to reset module\n");
return ret;
}
/* re-enable interrupts so we can send messages */
iowrite8(1 << mod->num, &mod->ctrl->int_enable);
ret = ican3_msg_connect(mod);
if (ret) {
dev_err(mod->dev, "unable to connect to module\n");
return ret;
}
ican3_init_new_host_interface(mod);
ret = ican3_msg_newhostif(mod);
if (ret) {
dev_err(mod->dev, "unable to switch to new-style interface\n");
return ret;
}
/* default to "termination on" */
ret = ican3_set_termination(mod, true);
if (ret) {
dev_err(mod->dev, "unable to enable termination\n");
return ret;
}
/* default to "bus errors enabled" */
ret = ican3_set_buserror(mod, ICAN3_BUSERR_QUOTA_MAX);
if (ret) {
dev_err(mod->dev, "unable to set bus-error\n");
return ret;
}
ican3_init_fast_host_interface(mod);
ret = ican3_msg_fasthostif(mod);
if (ret) {
dev_err(mod->dev, "unable to switch to fast host interface\n");
return ret;
}
ret = ican3_set_id_filter(mod, true);
if (ret) {
dev_err(mod->dev, "unable to set acceptance filter\n");
return ret;
}
return 0;
}
/*
* CAN Network Device
*/
static int ican3_open(struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
u8 quota;
int ret;
/* open the CAN layer */
ret = open_candev(ndev);
if (ret) {
dev_err(mod->dev, "unable to start CAN layer\n");
return ret;
}
/* set the bus error generation state appropriately */
if (mod->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
quota = ICAN3_BUSERR_QUOTA_MAX;
else
quota = 0;
ret = ican3_set_buserror(mod, quota);
if (ret) {
dev_err(mod->dev, "unable to set bus-error\n");
close_candev(ndev);
return ret;
}
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
dev_err(mod->dev, "unable to set bus-on\n");
close_candev(ndev);
return ret;
}
/* start up the network device */
mod->can.state = CAN_STATE_ERROR_ACTIVE;
netif_start_queue(ndev);
return 0;
}
static int ican3_stop(struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
int ret;
/* stop the network device xmit routine */
netif_stop_queue(ndev);
mod->can.state = CAN_STATE_STOPPED;
/* bring the bus offline, stop receiving packets */
ret = ican3_set_bus_state(mod, false);
if (ret) {
dev_err(mod->dev, "unable to set bus-off\n");
return ret;
}
/* close the CAN layer */
close_candev(ndev);
return 0;
}
static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf = (struct can_frame *)skb->data;
struct ican3_fast_desc desc;
void __iomem *desc_addr;
unsigned long flags;
spin_lock_irqsave(&mod->lock, flags);
/* check that we can actually transmit */
if (!ican3_txok(mod)) {
dev_err(mod->dev, "no free descriptors, stopping queue\n");
netif_stop_queue(ndev);
spin_unlock_irqrestore(&mod->lock, flags);
return NETDEV_TX_BUSY;
}
/* copy the control bits of the descriptor */
ican3_set_page(mod, mod->fasttx_start + (mod->fasttx_num / 16));
desc_addr = mod->dpm + ((mod->fasttx_num % 16) * sizeof(desc));
memset(&desc, 0, sizeof(desc));
memcpy_fromio(&desc, desc_addr, 1);
/* convert the Linux CAN frame into ICAN3 format */
can_frame_to_ican3(mod, cf, &desc);
/*
* the programming manual says that you must set the IVALID bit, then
* interrupt, then set the valid bit. Quite weird, but it seems to be
* required for this to work
*/
desc.control |= DESC_IVALID;
memcpy_toio(desc_addr, &desc, sizeof(desc));
/* generate a MODULbus interrupt to the microcontroller */
iowrite8(0x01, &mod->dpmctrl->interrupt);
desc.control ^= DESC_VALID;
memcpy_toio(desc_addr, &desc, sizeof(desc));
/* update the next buffer pointer */
mod->fasttx_num = (desc.control & DESC_WRAP) ? 0
: (mod->fasttx_num + 1);
/* update statistics */
stats->tx_packets++;
stats->tx_bytes += cf->can_dlc;
kfree_skb(skb);
/*
* This hardware doesn't have TX-done notifications, so we'll try and
* emulate it the best we can using ECHO skbs. Get the next TX
* descriptor, and see if we have room to send. If not, stop the queue.
* It will be woken when the ECHO skb for the current packet is recv'd.
*/
/* copy the control bits of the descriptor */
if (!ican3_txok(mod))
netif_stop_queue(ndev);
spin_unlock_irqrestore(&mod->lock, flags);
return NETDEV_TX_OK;
}
static const struct net_device_ops ican3_netdev_ops = {
.ndo_open = ican3_open,
.ndo_stop = ican3_stop,
.ndo_start_xmit = ican3_xmit,
};
/*
* Low-level CAN Device
*/
/* This structure was stolen from drivers/net/can/sja1000/sja1000.c */
static struct can_bittiming_const ican3_bittiming_const = {
.name = DRV_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
};
/*
* This routine was stolen from drivers/net/can/sja1000/sja1000.c
*
* The bittiming register command for the ICAN3 just sets the bit timing
* registers on the SJA1000 chip directly
*/
static int ican3_set_bittiming(struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
struct can_bittiming *bt = &mod->can.bittiming;
struct ican3_msg msg;
u8 btr0, btr1;
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
(((bt->phase_seg2 - 1) & 0x7) << 4);
if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
memset(&msg, 0, sizeof(msg));
msg.spec = MSG_CBTRREQ;
msg.len = cpu_to_le16(4);
msg.data[0] = 0x00;
msg.data[1] = 0x00;
msg.data[2] = btr0;
msg.data[3] = btr1;
return ican3_send_msg(mod, &msg);
}
static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
{
struct ican3_dev *mod = netdev_priv(ndev);
int ret;
if (mode != CAN_MODE_START)
return -ENOTSUPP;
/* bring the bus online */
ret = ican3_set_bus_state(mod, true);
if (ret) {
dev_err(mod->dev, "unable to set bus-on\n");
return ret;
}
/* start up the network device */
mod->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_queue_stopped(ndev))
netif_wake_queue(ndev);
return 0;
}
static int ican3_get_berr_counter(const struct net_device *ndev,
struct can_berr_counter *bec)
{
struct ican3_dev *mod = netdev_priv(ndev);
int ret;
ret = ican3_send_inquiry(mod, INQUIRY_STATUS);
if (ret)
return ret;
ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
if (ret <= 0) {
dev_info(mod->dev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
bec->rxerr = mod->bec.rxerr;
bec->txerr = mod->bec.txerr;
return 0;
}
/*
* Sysfs Attributes
*/
static ssize_t ican3_sysfs_show_term(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
int ret;
ret = ican3_send_inquiry(mod, INQUIRY_TERMINATION);
if (ret)
return ret;
ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
if (ret <= 0) {
dev_info(mod->dev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
return snprintf(buf, PAGE_SIZE, "%u\n", mod->termination_enabled);
}
static ssize_t ican3_sysfs_set_term(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
unsigned long enable;
int ret;
if (strict_strtoul(buf, 0, &enable))
return -EINVAL;
ret = ican3_set_termination(mod, enable);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR(termination, S_IWUGO | S_IRUGO, ican3_sysfs_show_term,
ican3_sysfs_set_term);
static struct attribute *ican3_sysfs_attrs[] = {
&dev_attr_termination.attr,
NULL,
};
static struct attribute_group ican3_sysfs_attr_group = {
.attrs = ican3_sysfs_attrs,
};
/*
* PCI Subsystem
*/
static int __devinit ican3_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
struct net_device *ndev;
struct ican3_dev *mod;
struct resource *res;
struct device *dev;
int ret;
pdata = pdev->dev.platform_data;
if (!pdata)
return -ENXIO;
dev_dbg(&pdev->dev, "probe: module number %d\n", pdata->modno);
/* save the struct device for printing */
dev = &pdev->dev;
/* allocate the CAN device and private data */
ndev = alloc_candev(sizeof(*mod), 0);
if (!ndev) {
dev_err(dev, "unable to allocate CANdev\n");
ret = -ENOMEM;
goto out_return;
}
platform_set_drvdata(pdev, ndev);
mod = netdev_priv(ndev);
mod->ndev = ndev;
mod->dev = &pdev->dev;
mod->num = pdata->modno;
netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
spin_lock_init(&mod->lock);
init_completion(&mod->termination_comp);
init_completion(&mod->buserror_comp);
/* setup device-specific sysfs attributes */
ndev->sysfs_groups[0] = &ican3_sysfs_attr_group;
/* the first unallocated page in the DPM is 9 */
mod->free_page = DPM_FREE_START;
ndev->netdev_ops = &ican3_netdev_ops;
ndev->flags |= IFF_ECHO;
SET_NETDEV_DEV(ndev, &pdev->dev);
mod->can.clock.freq = ICAN3_CAN_CLOCK;
mod->can.bittiming_const = &ican3_bittiming_const;
mod->can.do_set_bittiming = ican3_set_bittiming;
mod->can.do_set_mode = ican3_set_mode;
mod->can.do_get_berr_counter = ican3_get_berr_counter;
mod->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES
| CAN_CTRLMODE_BERR_REPORTING;
/* find our IRQ number */
mod->irq = platform_get_irq(pdev, 0);
if (mod->irq < 0) {
dev_err(dev, "IRQ line not found\n");
ret = -ENODEV;
goto out_free_ndev;
}
ndev->irq = mod->irq;
/* get access to the MODULbus registers for this module */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "MODULbus registers not found\n");
ret = -ENODEV;
goto out_free_ndev;
}
mod->dpm = ioremap(res->start, resource_size(res));
if (!mod->dpm) {
dev_err(dev, "MODULbus registers not ioremap\n");
ret = -ENOMEM;
goto out_free_ndev;
}
mod->dpmctrl = mod->dpm + DPM_PAGE_SIZE;
/* get access to the control registers for this module */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(dev, "CONTROL registers not found\n");
ret = -ENODEV;
goto out_iounmap_dpm;
}
mod->ctrl = ioremap(res->start, resource_size(res));
if (!mod->ctrl) {
dev_err(dev, "CONTROL registers not ioremap\n");
ret = -ENOMEM;
goto out_iounmap_dpm;
}
/* disable our IRQ, then hookup the IRQ handler */
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
ret = request_irq(mod->irq, ican3_irq, IRQF_SHARED, DRV_NAME, mod);
if (ret) {
dev_err(dev, "unable to request IRQ\n");
goto out_iounmap_ctrl;
}
/* reset and initialize the CAN controller into fast mode */
napi_enable(&mod->napi);
ret = ican3_startup_module(mod);
if (ret) {
dev_err(dev, "%s: unable to start CANdev\n", __func__);
goto out_free_irq;
}
/* register with the Linux CAN layer */
ret = register_candev(ndev);
if (ret) {
dev_err(dev, "%s: unable to register CANdev\n", __func__);
goto out_free_irq;
}
dev_info(dev, "module %d: registered CAN device\n", pdata->modno);
return 0;
out_free_irq:
napi_disable(&mod->napi);
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
free_irq(mod->irq, mod);
out_iounmap_ctrl:
iounmap(mod->ctrl);
out_iounmap_dpm:
iounmap(mod->dpm);
out_free_ndev:
free_candev(ndev);
out_return:
return ret;
}
static int __devexit ican3_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ican3_dev *mod = netdev_priv(ndev);
/* unregister the netdevice, stop interrupts */
unregister_netdev(ndev);
napi_disable(&mod->napi);
iowrite8(1 << mod->num, &mod->ctrl->int_disable);
free_irq(mod->irq, mod);
/* put the module into reset */
ican3_shutdown_module(mod);
/* unmap all registers */
iounmap(mod->ctrl);
iounmap(mod->dpm);
free_candev(ndev);
return 0;
}
static struct platform_driver ican3_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = ican3_probe,
.remove = __devexit_p(ican3_remove),
};
static int __init ican3_init(void)
{
return platform_driver_register(&ican3_driver);
}
static void __exit ican3_exit(void)
{
platform_driver_unregister(&ican3_driver);
}
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
MODULE_DESCRIPTION("Janz MODULbus VMOD-ICAN3 Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:janz-ican3");
module_init(ican3_init);
module_exit(ican3_exit);
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h>
/* LDO registers and some handy masking definitions for AB3100 */ /* LDO registers and some handy masking definitions for AB3100 */
#define AB3100_LDO_A 0x40 #define AB3100_LDO_A 0x40
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
* struct ab3100_regulator * struct ab3100_regulator
* A struct passed around the individual regulator functions * A struct passed around the individual regulator functions
* @platform_device: platform device holding this regulator * @platform_device: platform device holding this regulator
* @ab3100: handle to the AB3100 parent chip * @dev: handle to the device
* @plfdata: AB3100 platform data passed in at probe time * @plfdata: AB3100 platform data passed in at probe time
* @regreg: regulator register number in the AB3100 * @regreg: regulator register number in the AB3100
* @fixed_voltage: a fixed voltage for this regulator, if this * @fixed_voltage: a fixed voltage for this regulator, if this
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
*/ */
struct ab3100_regulator { struct ab3100_regulator {
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct ab3100 *ab3100; struct device *dev;
struct ab3100_platform_data *plfdata; struct ab3100_platform_data *plfdata;
u8 regreg; u8 regreg;
int fixed_voltage; int fixed_voltage;
...@@ -183,7 +183,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg) ...@@ -183,7 +183,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg)
int err; int err;
u8 regval; u8 regval;
err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
&regval); &regval);
if (err) { if (err) {
dev_warn(&reg->dev, "failed to get regid %d value\n", dev_warn(&reg->dev, "failed to get regid %d value\n",
...@@ -197,7 +197,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg) ...@@ -197,7 +197,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg)
regval |= AB3100_REG_ON_MASK; regval |= AB3100_REG_ON_MASK;
err = ab3100_set_register_interruptible(abreg->ab3100, abreg->regreg, err = abx500_set_register_interruptible(abreg->dev, 0, abreg->regreg,
regval); regval);
if (err) { if (err) {
dev_warn(&reg->dev, "failed to set regid %d value\n", dev_warn(&reg->dev, "failed to set regid %d value\n",
...@@ -245,14 +245,14 @@ static int ab3100_disable_regulator(struct regulator_dev *reg) ...@@ -245,14 +245,14 @@ static int ab3100_disable_regulator(struct regulator_dev *reg)
if (abreg->regreg == AB3100_LDO_D) { if (abreg->regreg == AB3100_LDO_D) {
dev_info(&reg->dev, "disabling LDO D - shut down system\n"); dev_info(&reg->dev, "disabling LDO D - shut down system\n");
/* Setting LDO D to 0x00 cuts the power to the SoC */ /* Setting LDO D to 0x00 cuts the power to the SoC */
return ab3100_set_register_interruptible(abreg->ab3100, return abx500_set_register_interruptible(abreg->dev, 0,
AB3100_LDO_D, 0x00U); AB3100_LDO_D, 0x00U);
} }
/* /*
* All other regulators are handled here * All other regulators are handled here
*/ */
err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
&regval); &regval);
if (err) { if (err) {
dev_err(&reg->dev, "unable to get register 0x%x\n", dev_err(&reg->dev, "unable to get register 0x%x\n",
...@@ -260,7 +260,7 @@ static int ab3100_disable_regulator(struct regulator_dev *reg) ...@@ -260,7 +260,7 @@ static int ab3100_disable_regulator(struct regulator_dev *reg)
return err; return err;
} }
regval &= ~AB3100_REG_ON_MASK; regval &= ~AB3100_REG_ON_MASK;
return ab3100_set_register_interruptible(abreg->ab3100, abreg->regreg, return abx500_set_register_interruptible(abreg->dev, 0, abreg->regreg,
regval); regval);
} }
...@@ -270,7 +270,7 @@ static int ab3100_is_enabled_regulator(struct regulator_dev *reg) ...@@ -270,7 +270,7 @@ static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
u8 regval; u8 regval;
int err; int err;
err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
&regval); &regval);
if (err) { if (err) {
dev_err(&reg->dev, "unable to get register 0x%x\n", dev_err(&reg->dev, "unable to get register 0x%x\n",
...@@ -305,7 +305,7 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg) ...@@ -305,7 +305,7 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
* For variable types, read out setting and index into * For variable types, read out setting and index into
* supplied voltage list. * supplied voltage list.
*/ */
err = ab3100_get_register_interruptible(abreg->ab3100, err = abx500_get_register_interruptible(abreg->dev, 0,
abreg->regreg, &regval); abreg->regreg, &regval);
if (err) { if (err) {
dev_warn(&reg->dev, dev_warn(&reg->dev,
...@@ -373,7 +373,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, ...@@ -373,7 +373,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
if (bestindex < 0) if (bestindex < 0)
return bestindex; return bestindex;
err = ab3100_get_register_interruptible(abreg->ab3100, err = abx500_get_register_interruptible(abreg->dev, 0,
abreg->regreg, &regval); abreg->regreg, &regval);
if (err) { if (err) {
dev_warn(&reg->dev, dev_warn(&reg->dev,
...@@ -386,7 +386,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, ...@@ -386,7 +386,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
regval &= ~0xE0; regval &= ~0xE0;
regval |= (bestindex << 5); regval |= (bestindex << 5);
err = ab3100_set_register_interruptible(abreg->ab3100, err = abx500_set_register_interruptible(abreg->dev, 0,
abreg->regreg, regval); abreg->regreg, regval);
if (err) if (err)
dev_warn(&reg->dev, "failed to set regulator register %02x\n", dev_warn(&reg->dev, "failed to set regulator register %02x\n",
...@@ -414,7 +414,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, ...@@ -414,7 +414,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
/* LDO E and BUCK have special suspend voltages you can set */ /* LDO E and BUCK have special suspend voltages you can set */
bestindex = ab3100_get_best_voltage_index(reg, uV, uV); bestindex = ab3100_get_best_voltage_index(reg, uV, uV);
err = ab3100_get_register_interruptible(abreg->ab3100, err = abx500_get_register_interruptible(abreg->dev, 0,
targetreg, &regval); targetreg, &regval);
if (err) { if (err) {
dev_warn(&reg->dev, dev_warn(&reg->dev,
...@@ -427,7 +427,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, ...@@ -427,7 +427,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
regval &= ~0xE0; regval &= ~0xE0;
regval |= (bestindex << 5); regval |= (bestindex << 5);
err = ab3100_set_register_interruptible(abreg->ab3100, err = abx500_set_register_interruptible(abreg->dev, 0,
targetreg, regval); targetreg, regval);
if (err) if (err)
dev_warn(&reg->dev, "failed to set regulator register %02x\n", dev_warn(&reg->dev, "failed to set regulator register %02x\n",
...@@ -574,13 +574,12 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { ...@@ -574,13 +574,12 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
static int __devinit ab3100_regulators_probe(struct platform_device *pdev) static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
{ {
struct ab3100_platform_data *plfdata = pdev->dev.platform_data; struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
struct ab3100 *ab3100 = platform_get_drvdata(pdev);
int err = 0; int err = 0;
u8 data; u8 data;
int i; int i;
/* Check chip state */ /* Check chip state */
err = ab3100_get_register_interruptible(ab3100, err = abx500_get_register_interruptible(&pdev->dev, 0,
AB3100_LDO_D, &data); AB3100_LDO_D, &data);
if (err) { if (err) {
dev_err(&pdev->dev, "could not read initial status of LDO_D\n"); dev_err(&pdev->dev, "could not read initial status of LDO_D\n");
...@@ -595,7 +594,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) ...@@ -595,7 +594,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
/* Set up regulators */ /* Set up regulators */
for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) { for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
err = ab3100_set_register_interruptible(ab3100, err = abx500_set_register_interruptible(&pdev->dev, 0,
ab3100_reg_init_order[i], ab3100_reg_init_order[i],
plfdata->reg_initvals[i]); plfdata->reg_initvals[i]);
if (err) { if (err) {
...@@ -617,7 +616,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) ...@@ -617,7 +616,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
* see what it looks like for a certain machine, go * see what it looks like for a certain machine, go
* into the machine I2C setup. * into the machine I2C setup.
*/ */
reg->ab3100 = ab3100; reg->dev = &pdev->dev;
reg->plfdata = plfdata; reg->plfdata = plfdata;
/* /*
......
...@@ -22,68 +22,9 @@ ...@@ -22,68 +22,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/i2c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/tps6507x.h>
/* Register definitions */
#define TPS6507X_REG_PPATH1 0X01
#define TPS6507X_REG_INT 0X02
#define TPS6507X_REG_CHGCONFIG0 0X03
#define TPS6507X_REG_CHGCONFIG1 0X04
#define TPS6507X_REG_CHGCONFIG2 0X05
#define TPS6507X_REG_CHGCONFIG3 0X06
#define TPS6507X_REG_REG_ADCONFIG 0X07
#define TPS6507X_REG_TSCMODE 0X08
#define TPS6507X_REG_ADRESULT_1 0X09
#define TPS6507X_REG_ADRESULT_2 0X0A
#define TPS6507X_REG_PGOOD 0X0B
#define TPS6507X_REG_PGOODMASK 0X0C
#define TPS6507X_REG_CON_CTRL1 0X0D
#define TPS6507X_REG_CON_CTRL2 0X0E
#define TPS6507X_REG_CON_CTRL3 0X0F
#define TPS6507X_REG_DEFDCDC1 0X10
#define TPS6507X_REG_DEFDCDC2_LOW 0X11
#define TPS6507X_REG_DEFDCDC2_HIGH 0X12
#define TPS6507X_REG_DEFDCDC3_LOW 0X13
#define TPS6507X_REG_DEFDCDC3_HIGH 0X14
#define TPS6507X_REG_DEFSLEW 0X15
#define TPS6507X_REG_LDO_CTRL1 0X16
#define TPS6507X_REG_DEFLDO2 0X17
#define TPS6507X_REG_WLED_CTRL1 0X18
#define TPS6507X_REG_WLED_CTRL2 0X19
/* CON_CTRL1 bitfields */
#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4)
#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3)
#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2)
#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1)
#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0)
/* DEFDCDC1 bitfields */
#define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN BIT(7)
#define TPS6507X_DEFDCDC1_DCDC1_MASK 0X3F
/* DEFDCDC2_LOW bitfields */
#define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK 0X3F
/* DEFDCDC2_HIGH bitfields */
#define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK 0X3F
/* DEFDCDC3_LOW bitfields */
#define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK 0X3F
/* DEFDCDC3_HIGH bitfields */
#define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK 0X3F
/* TPS6507X_REG_LDO_CTRL1 bitfields */
#define TPS6507X_REG_LDO_CTRL1_LDO1_MASK 0X0F
/* TPS6507X_REG_DEFLDO2 bitfields */
#define TPS6507X_REG_DEFLDO2_LDO2_MASK 0X3F
/* VDCDC MASK */
#define TPS6507X_DEFDCDCX_DCDC_MASK 0X3F
/* DCDC's */ /* DCDC's */
#define TPS6507X_DCDC_1 0 #define TPS6507X_DCDC_1 0
...@@ -162,101 +103,146 @@ struct tps_info { ...@@ -162,101 +103,146 @@ struct tps_info {
const u16 *table; const u16 *table;
}; };
struct tps_pmic { static const struct tps_info tps6507x_pmic_regs[] = {
{
.name = "VDCDC1",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC3",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
.table = LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table),
.table = LDO2_VSEL_table,
},
};
struct tps6507x_pmic {
struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
struct i2c_client *client; struct tps6507x_dev *mfd;
struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
const struct tps_info *info[TPS6507X_NUM_REGULATOR]; const struct tps_info *info[TPS6507X_NUM_REGULATOR];
struct mutex io_lock; struct mutex io_lock;
}; };
static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
static inline int tps_6507x_read(struct tps_pmic *tps, u8 reg)
{ {
return i2c_smbus_read_byte_data(tps->client, reg); u8 val;
int err;
err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
if (err)
return err;
return val;
} }
static inline int tps_6507x_write(struct tps_pmic *tps, u8 reg, u8 val) static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
{ {
return i2c_smbus_write_byte_data(tps->client, reg, val); return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
} }
static int tps_6507x_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
{ {
int err, data; int err, data;
mutex_lock(&tps->io_lock); mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg); data = tps6507x_pmic_read(tps, reg);
if (data < 0) { if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
err = data; err = data;
goto out; goto out;
} }
data |= mask; data |= mask;
err = tps_6507x_write(tps, reg, data); err = tps6507x_pmic_write(tps, reg, data);
if (err) if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
out: out:
mutex_unlock(&tps->io_lock); mutex_unlock(&tps->io_lock);
return err; return err;
} }
static int tps_6507x_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
{ {
int err, data; int err, data;
mutex_lock(&tps->io_lock); mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg); data = tps6507x_pmic_read(tps, reg);
if (data < 0) { if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
err = data; err = data;
goto out; goto out;
} }
data &= ~mask; data &= ~mask;
err = tps_6507x_write(tps, reg, data); err = tps6507x_pmic_write(tps, reg, data);
if (err) if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
out: out:
mutex_unlock(&tps->io_lock); mutex_unlock(&tps->io_lock);
return err; return err;
} }
static int tps_6507x_reg_read(struct tps_pmic *tps, u8 reg) static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
{ {
int data; int data;
mutex_lock(&tps->io_lock); mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg); data = tps6507x_pmic_read(tps, reg);
if (data < 0) if (data < 0)
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock); mutex_unlock(&tps->io_lock);
return data; return data;
} }
static int tps_6507x_reg_write(struct tps_pmic *tps, u8 reg, u8 val) static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
{ {
int err; int err;
mutex_lock(&tps->io_lock); mutex_lock(&tps->io_lock);
err = tps_6507x_write(tps, reg, val); err = tps6507x_pmic_write(tps, reg, val);
if (err < 0) if (err < 0)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg); dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock); mutex_unlock(&tps->io_lock);
return err; return err;
} }
static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev) static int tps6507x_pmic_dcdc_is_enabled(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev); int data, dcdc = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -264,7 +250,7 @@ static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev) ...@@ -264,7 +250,7 @@ static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc; shift = TPS6507X_MAX_REG_ID - dcdc;
data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1); data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
if (data < 0) if (data < 0)
return data; return data;
...@@ -272,9 +258,9 @@ static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev) ...@@ -272,9 +258,9 @@ static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev)
return (data & 1<<shift) ? 1 : 0; return (data & 1<<shift) ? 1 : 0;
} }
static int tps6507x_ldo_is_enabled(struct regulator_dev *dev) static int tps6507x_pmic_ldo_is_enabled(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev); int data, ldo = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -282,7 +268,7 @@ static int tps6507x_ldo_is_enabled(struct regulator_dev *dev) ...@@ -282,7 +268,7 @@ static int tps6507x_ldo_is_enabled(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo; shift = TPS6507X_MAX_REG_ID - ldo;
data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1); data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
if (data < 0) if (data < 0)
return data; return data;
...@@ -290,9 +276,9 @@ static int tps6507x_ldo_is_enabled(struct regulator_dev *dev) ...@@ -290,9 +276,9 @@ static int tps6507x_ldo_is_enabled(struct regulator_dev *dev)
return (data & 1<<shift) ? 1 : 0; return (data & 1<<shift) ? 1 : 0;
} }
static int tps6507x_dcdc_enable(struct regulator_dev *dev) static int tps6507x_pmic_dcdc_enable(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev); int dcdc = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -300,12 +286,12 @@ static int tps6507x_dcdc_enable(struct regulator_dev *dev) ...@@ -300,12 +286,12 @@ static int tps6507x_dcdc_enable(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc; shift = TPS6507X_MAX_REG_ID - dcdc;
return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
} }
static int tps6507x_dcdc_disable(struct regulator_dev *dev) static int tps6507x_pmic_dcdc_disable(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev); int dcdc = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -313,12 +299,13 @@ static int tps6507x_dcdc_disable(struct regulator_dev *dev) ...@@ -313,12 +299,13 @@ static int tps6507x_dcdc_disable(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc; shift = TPS6507X_MAX_REG_ID - dcdc;
return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
1 << shift);
} }
static int tps6507x_ldo_enable(struct regulator_dev *dev) static int tps6507x_pmic_ldo_enable(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev); int ldo = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -326,12 +313,12 @@ static int tps6507x_ldo_enable(struct regulator_dev *dev) ...@@ -326,12 +313,12 @@ static int tps6507x_ldo_enable(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo; shift = TPS6507X_MAX_REG_ID - ldo;
return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
} }
static int tps6507x_ldo_disable(struct regulator_dev *dev) static int tps6507x_pmic_ldo_disable(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev); int ldo = rdev_get_id(dev);
u8 shift; u8 shift;
...@@ -339,12 +326,13 @@ static int tps6507x_ldo_disable(struct regulator_dev *dev) ...@@ -339,12 +326,13 @@ static int tps6507x_ldo_disable(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo; shift = TPS6507X_MAX_REG_ID - ldo;
return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
1 << shift);
} }
static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev) static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev); int data, dcdc = rdev_get_id(dev);
u8 reg; u8 reg;
...@@ -362,7 +350,7 @@ static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev) ...@@ -362,7 +350,7 @@ static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev)
return -EINVAL; return -EINVAL;
} }
data = tps_6507x_reg_read(tps, reg); data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0) if (data < 0)
return data; return data;
...@@ -370,10 +358,10 @@ static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev) ...@@ -370,10 +358,10 @@ static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev)
return tps->info[dcdc]->table[data] * 1000; return tps->info[dcdc]->table[data] * 1000;
} }
static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev, static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV) int min_uV, int max_uV)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, dcdc = rdev_get_id(dev); int data, vsel, dcdc = rdev_get_id(dev);
u8 reg; u8 reg;
...@@ -411,19 +399,19 @@ static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev, ...@@ -411,19 +399,19 @@ static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev,
if (vsel == tps->info[dcdc]->table_len) if (vsel == tps->info[dcdc]->table_len)
return -EINVAL; return -EINVAL;
data = tps_6507x_reg_read(tps, reg); data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0) if (data < 0)
return data; return data;
data &= ~TPS6507X_DEFDCDCX_DCDC_MASK; data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
data |= vsel; data |= vsel;
return tps_6507x_reg_write(tps, reg, data); return tps6507x_pmic_reg_write(tps, reg, data);
} }
static int tps6507x_ldo_get_voltage(struct regulator_dev *dev) static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev); int data, ldo = rdev_get_id(dev);
u8 reg, mask; u8 reg, mask;
...@@ -437,7 +425,7 @@ static int tps6507x_ldo_get_voltage(struct regulator_dev *dev) ...@@ -437,7 +425,7 @@ static int tps6507x_ldo_get_voltage(struct regulator_dev *dev)
TPS6507X_REG_DEFLDO2_LDO2_MASK); TPS6507X_REG_DEFLDO2_LDO2_MASK);
} }
data = tps_6507x_reg_read(tps, reg); data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0) if (data < 0)
return data; return data;
...@@ -445,10 +433,10 @@ static int tps6507x_ldo_get_voltage(struct regulator_dev *dev) ...@@ -445,10 +433,10 @@ static int tps6507x_ldo_get_voltage(struct regulator_dev *dev)
return tps->info[ldo]->table[data] * 1000; return tps->info[ldo]->table[data] * 1000;
} }
static int tps6507x_ldo_set_voltage(struct regulator_dev *dev, static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV) int min_uV, int max_uV)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, ldo = rdev_get_id(dev); int data, vsel, ldo = rdev_get_id(dev);
u8 reg, mask; u8 reg, mask;
...@@ -479,20 +467,20 @@ static int tps6507x_ldo_set_voltage(struct regulator_dev *dev, ...@@ -479,20 +467,20 @@ static int tps6507x_ldo_set_voltage(struct regulator_dev *dev,
if (vsel == tps->info[ldo]->table_len) if (vsel == tps->info[ldo]->table_len)
return -EINVAL; return -EINVAL;
data = tps_6507x_reg_read(tps, reg); data = tps6507x_pmic_reg_read(tps, reg);
if (data < 0) if (data < 0)
return data; return data;
data &= ~mask; data &= ~mask;
data |= vsel; data |= vsel;
return tps_6507x_reg_write(tps, reg, data); return tps6507x_pmic_reg_write(tps, reg, data);
} }
static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev, static int tps6507x_pmic_dcdc_list_voltage(struct regulator_dev *dev,
unsigned selector) unsigned selector)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev); int dcdc = rdev_get_id(dev);
if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
...@@ -504,10 +492,10 @@ static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev, ...@@ -504,10 +492,10 @@ static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev,
return tps->info[dcdc]->table[selector] * 1000; return tps->info[dcdc]->table[selector] * 1000;
} }
static int tps6507x_ldo_list_voltage(struct regulator_dev *dev, static int tps6507x_pmic_ldo_list_voltage(struct regulator_dev *dev,
unsigned selector) unsigned selector)
{ {
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev); int ldo = rdev_get_id(dev);
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
...@@ -520,47 +508,54 @@ static int tps6507x_ldo_list_voltage(struct regulator_dev *dev, ...@@ -520,47 +508,54 @@ static int tps6507x_ldo_list_voltage(struct regulator_dev *dev,
} }
/* Operations permitted on VDCDCx */ /* Operations permitted on VDCDCx */
static struct regulator_ops tps6507x_dcdc_ops = { static struct regulator_ops tps6507x_pmic_dcdc_ops = {
.is_enabled = tps6507x_dcdc_is_enabled, .is_enabled = tps6507x_pmic_dcdc_is_enabled,
.enable = tps6507x_dcdc_enable, .enable = tps6507x_pmic_dcdc_enable,
.disable = tps6507x_dcdc_disable, .disable = tps6507x_pmic_dcdc_disable,
.get_voltage = tps6507x_dcdc_get_voltage, .get_voltage = tps6507x_pmic_dcdc_get_voltage,
.set_voltage = tps6507x_dcdc_set_voltage, .set_voltage = tps6507x_pmic_dcdc_set_voltage,
.list_voltage = tps6507x_dcdc_list_voltage, .list_voltage = tps6507x_pmic_dcdc_list_voltage,
}; };
/* Operations permitted on LDOx */ /* Operations permitted on LDOx */
static struct regulator_ops tps6507x_ldo_ops = { static struct regulator_ops tps6507x_pmic_ldo_ops = {
.is_enabled = tps6507x_ldo_is_enabled, .is_enabled = tps6507x_pmic_ldo_is_enabled,
.enable = tps6507x_ldo_enable, .enable = tps6507x_pmic_ldo_enable,
.disable = tps6507x_ldo_disable, .disable = tps6507x_pmic_ldo_disable,
.get_voltage = tps6507x_ldo_get_voltage, .get_voltage = tps6507x_pmic_ldo_get_voltage,
.set_voltage = tps6507x_ldo_set_voltage, .set_voltage = tps6507x_pmic_ldo_set_voltage,
.list_voltage = tps6507x_ldo_list_voltage, .list_voltage = tps6507x_pmic_ldo_list_voltage,
}; };
static int __devinit tps_6507x_probe(struct i2c_client *client, static __devinit
const struct i2c_device_id *id) int tps6507x_pmic_probe(struct platform_device *pdev)
{ {
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
static int desc_id; static int desc_id;
const struct tps_info *info = (void *)id->driver_data; const struct tps_info *info = &tps6507x_pmic_regs[0];
struct regulator_init_data *init_data; struct regulator_init_data *init_data;
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct tps_pmic *tps; struct tps6507x_pmic *tps;
struct tps6507x_board *tps_board;
int i; int i;
int error; int error;
if (!i2c_check_functionality(client->adapter, /**
I2C_FUNC_SMBUS_BYTE_DATA)) * tps_board points to pmic related constants
return -EIO; * coming from the board-evm file.
*/
tps_board = dev_get_platdata(tps6507x_dev->dev);
if (!tps_board)
return -EINVAL;
/** /**
* init_data points to array of regulator_init structures * init_data points to array of regulator_init structures
* coming from the board-evm file. * coming from the board-evm file.
*/ */
init_data = client->dev.platform_data; init_data = tps_board->tps6507x_pmic_init_data;
if (!init_data) if (!init_data)
return -EIO; return -EINVAL;
tps = kzalloc(sizeof(*tps), GFP_KERNEL); tps = kzalloc(sizeof(*tps), GFP_KERNEL);
if (!tps) if (!tps)
...@@ -569,7 +564,7 @@ static int __devinit tps_6507x_probe(struct i2c_client *client, ...@@ -569,7 +564,7 @@ static int __devinit tps_6507x_probe(struct i2c_client *client,
mutex_init(&tps->io_lock); mutex_init(&tps->io_lock);
/* common for all regulators */ /* common for all regulators */
tps->client = client; tps->mfd = tps6507x_dev;
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
/* Register the regulators */ /* Register the regulators */
...@@ -578,15 +573,16 @@ static int __devinit tps_6507x_probe(struct i2c_client *client, ...@@ -578,15 +573,16 @@ static int __devinit tps_6507x_probe(struct i2c_client *client,
tps->desc[i].id = desc_id++; tps->desc[i].id = desc_id++;
tps->desc[i].n_voltages = num_voltages[i]; tps->desc[i].n_voltages = num_voltages[i];
tps->desc[i].ops = (i > TPS6507X_DCDC_3 ? tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
&tps6507x_ldo_ops : &tps6507x_dcdc_ops); &tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE; tps->desc[i].owner = THIS_MODULE;
rdev = regulator_register(&tps->desc[i], rdev = regulator_register(&tps->desc[i],
&client->dev, init_data, tps); tps6507x_dev->dev, init_data, tps);
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n", dev_err(tps6507x_dev->dev,
id->name); "failed to register %s regulator\n",
pdev->name);
error = PTR_ERR(rdev); error = PTR_ERR(rdev);
goto fail; goto fail;
} }
...@@ -595,7 +591,7 @@ static int __devinit tps_6507x_probe(struct i2c_client *client, ...@@ -595,7 +591,7 @@ static int __devinit tps_6507x_probe(struct i2c_client *client,
tps->rdev[i] = rdev; tps->rdev[i] = rdev;
} }
i2c_set_clientdata(client, tps); tps6507x_dev->pmic = tps;
return 0; return 0;
...@@ -608,19 +604,17 @@ static int __devinit tps_6507x_probe(struct i2c_client *client, ...@@ -608,19 +604,17 @@ static int __devinit tps_6507x_probe(struct i2c_client *client,
} }
/** /**
* tps_6507x_remove - TPS6507x driver i2c remove handler * tps6507x_remove - TPS6507x driver i2c remove handler
* @client: i2c driver client device structure * @client: i2c driver client device structure
* *
* Unregister TPS driver as an i2c client device driver * Unregister TPS driver as an i2c client device driver
*/ */
static int __devexit tps_6507x_remove(struct i2c_client *client) static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
{ {
struct tps_pmic *tps = i2c_get_clientdata(client); struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
struct tps6507x_pmic *tps = tps6507x_dev->pmic;
int i; int i;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]); regulator_unregister(tps->rdev[i]);
...@@ -629,83 +623,38 @@ static int __devexit tps_6507x_remove(struct i2c_client *client) ...@@ -629,83 +623,38 @@ static int __devexit tps_6507x_remove(struct i2c_client *client)
return 0; return 0;
} }
static const struct tps_info tps6507x_regs[] = { static struct platform_driver tps6507x_pmic_driver = {
{
.name = "VDCDC1",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC3",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
.table = LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table),
.table = LDO2_VSEL_table,
},
};
static const struct i2c_device_id tps_6507x_id[] = {
{.name = "tps6507x",
.driver_data = (unsigned long) tps6507x_regs,},
{ },
};
MODULE_DEVICE_TABLE(i2c, tps_6507x_id);
static struct i2c_driver tps_6507x_i2c_driver = {
.driver = { .driver = {
.name = "tps6507x", .name = "tps6507x-pmic",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = tps_6507x_probe, .probe = tps6507x_pmic_probe,
.remove = __devexit_p(tps_6507x_remove), .remove = __devexit_p(tps6507x_pmic_remove),
.id_table = tps_6507x_id,
}; };
/** /**
* tps_6507x_init * tps6507x_pmic_init
* *
* Module init function * Module init function
*/ */
static int __init tps_6507x_init(void) static int __init tps6507x_pmic_init(void)
{ {
return i2c_add_driver(&tps_6507x_i2c_driver); return platform_driver_register(&tps6507x_pmic_driver);
} }
subsys_initcall(tps_6507x_init); subsys_initcall(tps6507x_pmic_init);
/** /**
* tps_6507x_cleanup * tps6507x_pmic_cleanup
* *
* Module exit function * Module exit function
*/ */
static void __exit tps_6507x_cleanup(void) static void __exit tps6507x_pmic_cleanup(void)
{ {
i2c_del_driver(&tps_6507x_i2c_driver); platform_driver_unregister(&tps6507x_pmic_driver);
} }
module_exit(tps_6507x_cleanup); module_exit(tps6507x_pmic_cleanup);
MODULE_AUTHOR("Texas Instruments"); MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tps6507x-pmic");
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h>
/* Clock rate in Hz */ /* Clock rate in Hz */
#define AB3100_RTC_CLOCK_RATE 32768 #define AB3100_RTC_CLOCK_RATE 32768
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
*/ */
static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs) static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
{ {
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2, u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2,
AB3100_TI3, AB3100_TI4, AB3100_TI5}; AB3100_TI3, AB3100_TI4, AB3100_TI5};
unsigned char buf[6]; unsigned char buf[6];
...@@ -61,27 +60,26 @@ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs) ...@@ -61,27 +60,26 @@ static int ab3100_rtc_set_mmss(struct device *dev, unsigned long secs)
buf[5] = (fat_time >> 40) & 0xFF; buf[5] = (fat_time >> 40) & 0xFF;
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
err = ab3100_set_register_interruptible(ab3100_data, err = abx500_set_register_interruptible(dev, 0,
regs[i], buf[i]); regs[i], buf[i]);
if (err) if (err)
return err; return err;
} }
/* Set the flag to mark that the clock is now set */ /* Set the flag to mark that the clock is now set */
return ab3100_mask_and_set_register_interruptible(ab3100_data, return abx500_mask_and_set_register_interruptible(dev, 0,
AB3100_RTC, AB3100_RTC,
0xFE, 0x01); 0x01, 0x01);
} }
static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
unsigned long time; unsigned long time;
u8 rtcval; u8 rtcval;
int err; int err;
err = ab3100_get_register_interruptible(ab3100_data, err = abx500_get_register_interruptible(dev, 0,
AB3100_RTC, &rtcval); AB3100_RTC, &rtcval);
if (err) if (err)
return err; return err;
...@@ -94,7 +92,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -94,7 +92,7 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
u8 buf[6]; u8 buf[6];
/* Read out time registers */ /* Read out time registers */
err = ab3100_get_register_page_interruptible(ab3100_data, err = abx500_get_register_page_interruptible(dev, 0,
AB3100_TI0, AB3100_TI0,
buf, 6); buf, 6);
if (err != 0) if (err != 0)
...@@ -114,7 +112,6 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -114,7 +112,6 @@ static int ab3100_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{ {
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
unsigned long time; unsigned long time;
u64 fat_time; u64 fat_time;
u8 buf[6]; u8 buf[6];
...@@ -122,7 +119,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -122,7 +119,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
int err; int err;
/* Figure out if alarm is enabled or not */ /* Figure out if alarm is enabled or not */
err = ab3100_get_register_interruptible(ab3100_data, err = abx500_get_register_interruptible(dev, 0,
AB3100_RTC, &rtcval); AB3100_RTC, &rtcval);
if (err) if (err)
return err; return err;
...@@ -133,7 +130,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -133,7 +130,7 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
/* No idea how this could be represented */ /* No idea how this could be represented */
alarm->pending = 0; alarm->pending = 0;
/* Read out alarm registers, only 4 bytes */ /* Read out alarm registers, only 4 bytes */
err = ab3100_get_register_page_interruptible(ab3100_data, err = abx500_get_register_page_interruptible(dev, 0,
AB3100_AL0, buf, 4); AB3100_AL0, buf, 4);
if (err) if (err)
return err; return err;
...@@ -148,7 +145,6 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -148,7 +145,6 @@ static int ab3100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{ {
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3}; u8 regs[] = {AB3100_AL0, AB3100_AL1, AB3100_AL2, AB3100_AL3};
unsigned char buf[4]; unsigned char buf[4];
unsigned long secs; unsigned long secs;
...@@ -165,21 +161,19 @@ static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ...@@ -165,21 +161,19 @@ static int ab3100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
/* Set the alarm */ /* Set the alarm */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
err = ab3100_set_register_interruptible(ab3100_data, err = abx500_set_register_interruptible(dev, 0,
regs[i], buf[i]); regs[i], buf[i]);
if (err) if (err)
return err; return err;
} }
/* Then enable the alarm */ /* Then enable the alarm */
return ab3100_mask_and_set_register_interruptible(ab3100_data, return abx500_mask_and_set_register_interruptible(dev, 0,
AB3100_RTC, ~(1 << 2), AB3100_RTC, (1 << 2),
alarm->enabled << 2); alarm->enabled << 2);
} }
static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
{ {
struct ab3100 *ab3100_data = dev_get_drvdata(dev);
/* /*
* It's not possible to enable/disable the alarm IRQ for this RTC. * It's not possible to enable/disable the alarm IRQ for this RTC.
* It does not actually trigger any IRQ: instead its only function is * It does not actually trigger any IRQ: instead its only function is
...@@ -188,12 +182,12 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled) ...@@ -188,12 +182,12 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
* and need to be handled there instead. * and need to be handled there instead.
*/ */
if (enabled) if (enabled)
return ab3100_mask_and_set_register_interruptible(ab3100_data, return abx500_mask_and_set_register_interruptible(dev, 0,
AB3100_RTC, ~(1 << 2), AB3100_RTC, (1 << 2),
1 << 2); 1 << 2);
else else
return ab3100_mask_and_set_register_interruptible(ab3100_data, return abx500_mask_and_set_register_interruptible(dev, 0,
AB3100_RTC, ~(1 << 2), AB3100_RTC, (1 << 2),
0); 0);
} }
...@@ -210,10 +204,9 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) ...@@ -210,10 +204,9 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
int err; int err;
u8 regval; u8 regval;
struct rtc_device *rtc; struct rtc_device *rtc;
struct ab3100 *ab3100_data = platform_get_drvdata(pdev);
/* The first RTC register needs special treatment */ /* The first RTC register needs special treatment */
err = ab3100_get_register_interruptible(ab3100_data, err = abx500_get_register_interruptible(&pdev->dev, 0,
AB3100_RTC, &regval); AB3100_RTC, &regval);
if (err) { if (err) {
dev_err(&pdev->dev, "unable to read RTC register\n"); dev_err(&pdev->dev, "unable to read RTC register\n");
...@@ -231,7 +224,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) ...@@ -231,7 +224,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
* This bit remains until RTC power is lost. * This bit remains until RTC power is lost.
*/ */
regval = 1 | RTC_SETTING; regval = 1 | RTC_SETTING;
err = ab3100_set_register_interruptible(ab3100_data, err = abx500_set_register_interruptible(&pdev->dev, 0,
AB3100_RTC, regval); AB3100_RTC, regval);
/* Ignore any error on this write */ /* Ignore any error on this write */
} }
......
/* /*
* RDC321x watchdog driver * RDC321x watchdog driver
* *
* Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
* *
* This driver is highly inspired from the cpu5_wdt driver * This driver is highly inspired from the cpu5_wdt driver
* *
...@@ -36,8 +36,7 @@ ...@@ -36,8 +36,7 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/mfd/rdc321x.h>
#include <asm/rdc321x_defs.h>
#define RDC_WDT_MASK 0x80000000 /* Mask */ #define RDC_WDT_MASK 0x80000000 /* Mask */
#define RDC_WDT_EN 0x00800000 /* Enable bit */ #define RDC_WDT_EN 0x00800000 /* Enable bit */
...@@ -63,6 +62,8 @@ static struct { ...@@ -63,6 +62,8 @@ static struct {
int default_ticks; int default_ticks;
unsigned long inuse; unsigned long inuse;
spinlock_t lock; spinlock_t lock;
struct pci_dev *sb_pdev;
int base_reg;
} rdc321x_wdt_device; } rdc321x_wdt_device;
/* generic helper functions */ /* generic helper functions */
...@@ -70,14 +71,18 @@ static struct { ...@@ -70,14 +71,18 @@ static struct {
static void rdc321x_wdt_trigger(unsigned long unused) static void rdc321x_wdt_trigger(unsigned long unused)
{ {
unsigned long flags; unsigned long flags;
u32 val;
if (rdc321x_wdt_device.running) if (rdc321x_wdt_device.running)
ticks--; ticks--;
/* keep watchdog alive */ /* keep watchdog alive */
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
outl(RDC_WDT_EN | inl(RDC3210_CFGREG_DATA), pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
RDC3210_CFGREG_DATA); rdc321x_wdt_device.base_reg, &val);
val |= RDC_WDT_EN;
pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
rdc321x_wdt_device.base_reg, val);
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
/* requeue?? */ /* requeue?? */
...@@ -105,10 +110,13 @@ static void rdc321x_wdt_start(void) ...@@ -105,10 +110,13 @@ static void rdc321x_wdt_start(void)
/* Clear the timer */ /* Clear the timer */
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR); pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
rdc321x_wdt_device.base_reg, RDC_CLS_TMR);
/* Enable watchdog and set the timeout to 81.92 us */ /* Enable watchdog and set the timeout to 81.92 us */
outl(RDC_WDT_EN | RDC_WDT_CNT, RDC3210_CFGREG_DATA); pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
rdc321x_wdt_device.base_reg,
RDC_WDT_EN | RDC_WDT_CNT);
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
mod_timer(&rdc321x_wdt_device.timer, mod_timer(&rdc321x_wdt_device.timer,
...@@ -148,7 +156,7 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -148,7 +156,7 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
unsigned int value; u32 value;
static const struct watchdog_info ident = { static const struct watchdog_info ident = {
.options = WDIOF_CARDRESET, .options = WDIOF_CARDRESET,
.identity = "RDC321x WDT", .identity = "RDC321x WDT",
...@@ -162,9 +170,10 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -162,9 +170,10 @@ static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
/* Read the value from the DATA register */ /* Read the value from the DATA register */
spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); spin_lock_irqsave(&rdc321x_wdt_device.lock, flags);
value = inl(RDC3210_CFGREG_DATA); pci_read_config_dword(rdc321x_wdt_device.sb_pdev,
rdc321x_wdt_device.base_reg, &value);
spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags);
if (copy_to_user(argp, &value, sizeof(int))) if (copy_to_user(argp, &value, sizeof(u32)))
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
...@@ -219,17 +228,35 @@ static struct miscdevice rdc321x_wdt_misc = { ...@@ -219,17 +228,35 @@ static struct miscdevice rdc321x_wdt_misc = {
static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
{ {
int err; int err;
struct resource *r;
struct rdc321x_wdt_pdata *pdata;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
}
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "wdt-reg");
if (!r) {
dev_err(&pdev->dev, "failed to get wdt-reg resource\n");
return -ENODEV;
}
rdc321x_wdt_device.sb_pdev = pdata->sb_pdev;
rdc321x_wdt_device.base_reg = r->start;
err = misc_register(&rdc321x_wdt_misc); err = misc_register(&rdc321x_wdt_misc);
if (err < 0) { if (err < 0) {
printk(KERN_ERR PFX "watchdog misc_register failed\n"); dev_err(&pdev->dev, "misc_register failed\n");
return err; return err;
} }
spin_lock_init(&rdc321x_wdt_device.lock); spin_lock_init(&rdc321x_wdt_device.lock);
/* Reset the watchdog */ /* Reset the watchdog */
outl(RDC_WDT_RST, RDC3210_CFGREG_DATA); pci_write_config_dword(rdc321x_wdt_device.sb_pdev,
rdc321x_wdt_device.base_reg, RDC_WDT_RST);
init_completion(&rdc321x_wdt_device.stop); init_completion(&rdc321x_wdt_device.stop);
rdc321x_wdt_device.queue = 0; rdc321x_wdt_device.queue = 0;
...@@ -240,7 +267,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) ...@@ -240,7 +267,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
rdc321x_wdt_device.default_ticks = ticks; rdc321x_wdt_device.default_ticks = ticks;
printk(KERN_INFO PFX "watchdog init success\n"); dev_info(&pdev->dev, "watchdog init success\n");
return 0; return 0;
} }
......
/* linux/i2c/tps6507x-ts.h
*
* Functions to access TPS65070 touch screen chip.
*
* Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com)
*
*
* For licencing details see kernel-base/COPYING
*/
#ifndef __LINUX_I2C_TPS6507X_TS_H
#define __LINUX_I2C_TPS6507X_TS_H
/* Board specific touch screen initial values */
struct touchscreen_init_data {
int poll_period; /* ms */
int vref; /* non-zero to leave vref on */
__u16 min_pressure; /* min reading to be treated as a touch */
__u16 vendor;
__u16 product;
__u16 version;
};
#endif /* __LINUX_I2C_TPS6507X_TS_H */
...@@ -370,7 +370,7 @@ extern int pm860x_set_bits(struct i2c_client *, int, unsigned char, ...@@ -370,7 +370,7 @@ extern int pm860x_set_bits(struct i2c_client *, int, unsigned char,
unsigned char); unsigned char);
extern int pm860x_device_init(struct pm860x_chip *chip, extern int pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata); struct pm860x_platform_data *pdata) __devinit ;
extern void pm860x_device_exit(struct pm860x_chip *chip); extern void pm860x_device_exit(struct pm860x_chip *chip) __devexit ;
#endif /* __LINUX_MFD_88PM860X_H */ #endif /* __LINUX_MFD_88PM860X_H */
/*
* Copyright (C) 2009 ST-Ericsson
*
* Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
*
* 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.
*
* AB4500 device core funtions, for client access
*/
#ifndef MFD_AB4500_H
#define MFD_AB4500_H
#include <linux/device.h>
/*
* AB4500 bank addresses
*/
#define AB4500_SYS_CTRL1_BLOCK 0x1
#define AB4500_SYS_CTRL2_BLOCK 0x2
#define AB4500_REGU_CTRL1 0x3
#define AB4500_REGU_CTRL2 0x4
#define AB4500_USB 0x5
#define AB4500_TVOUT 0x6
#define AB4500_DBI 0x7
#define AB4500_ECI_AV_ACC 0x8
#define AB4500_RESERVED 0x9
#define AB4500_GPADC 0xA
#define AB4500_CHARGER 0xB
#define AB4500_GAS_GAUGE 0xC
#define AB4500_AUDIO 0xD
#define AB4500_INTERRUPT 0xE
#define AB4500_RTC 0xF
#define AB4500_MISC 0x10
#define AB4500_DEBUG 0x12
#define AB4500_PROD_TEST 0x13
#define AB4500_OTP_EMUL 0x15
/*
* System control 1 register offsets.
* Bank = 0x01
*/
#define AB4500_TURNON_STAT_REG 0x0100
#define AB4500_RESET_STAT_REG 0x0101
#define AB4500_PONKEY1_PRESS_STAT_REG 0x0102
#define AB4500_FSM_STAT1_REG 0x0140
#define AB4500_FSM_STAT2_REG 0x0141
#define AB4500_SYSCLK_REQ_STAT_REG 0x0142
#define AB4500_USB_STAT1_REG 0x0143
#define AB4500_USB_STAT2_REG 0x0144
#define AB4500_STATUS_SPARE1_REG 0x0145
#define AB4500_STATUS_SPARE2_REG 0x0146
#define AB4500_CTRL1_REG 0x0180
#define AB4500_CTRL2_REG 0x0181
/*
* System control 2 register offsets.
* bank = 0x02
*/
#define AB4500_CTRL3_REG 0x0200
#define AB4500_MAIN_WDOG_CTRL_REG 0x0201
#define AB4500_MAIN_WDOG_TIMER_REG 0x0202
#define AB4500_LOW_BAT_REG 0x0203
#define AB4500_BATT_OK_REG 0x0204
#define AB4500_SYSCLK_TIMER_REG 0x0205
#define AB4500_SMPSCLK_CTRL_REG 0x0206
#define AB4500_SMPSCLK_SEL1_REG 0x0207
#define AB4500_SMPSCLK_SEL2_REG 0x0208
#define AB4500_SMPSCLK_SEL3_REG 0x0209
#define AB4500_SYSULPCLK_CONF_REG 0x020A
#define AB4500_SYSULPCLK_CTRL1_REG 0x020B
#define AB4500_SYSCLK_CTRL_REG 0x020C
#define AB4500_SYSCLK_REQ1_VALID_REG 0x020D
#define AB4500_SYSCLK_REQ_VALID_REG 0x020E
#define AB4500_SYSCTRL_SPARE_REG 0x020F
#define AB4500_PAD_CONF_REG 0x0210
/*
* Regu control1 register offsets
* Bank = 0x03
*/
#define AB4500_REGU_SERIAL_CTRL1_REG 0x0300
#define AB4500_REGU_SERIAL_CTRL2_REG 0x0301
#define AB4500_REGU_SERIAL_CTRL3_REG 0x0302
#define AB4500_REGU_REQ_CTRL1_REG 0x0303
#define AB4500_REGU_REQ_CTRL2_REG 0x0304
#define AB4500_REGU_REQ_CTRL3_REG 0x0305
#define AB4500_REGU_REQ_CTRL4_REG 0x0306
#define AB4500_REGU_MISC1_REG 0x0380
#define AB4500_REGU_OTGSUPPLY_CTRL_REG 0x0381
#define AB4500_REGU_VUSB_CTRL_REG 0x0382
#define AB4500_REGU_VAUDIO_SUPPLY_REG 0x0383
#define AB4500_REGU_CTRL1_SPARE_REG 0x0384
/*
* Regu control2 Vmod register offsets
*/
#define AB4500_REGU_VMOD_REGU_REG 0x0440
#define AB4500_REGU_VMOD_SEL1_REG 0x0441
#define AB4500_REGU_VMOD_SEL2_REG 0x0442
#define AB4500_REGU_CTRL_DISCH_REG 0x0443
#define AB4500_REGU_CTRL_DISCH2_REG 0x0444
/*
* USB/ULPI register offsets
* Bank : 0x5
*/
#define AB4500_USB_LINE_STAT_REG 0x0580
#define AB4500_USB_LINE_CTRL1_REG 0x0581
#define AB4500_USB_LINE_CTRL2_REG 0x0582
#define AB4500_USB_LINE_CTRL3_REG 0x0583
#define AB4500_USB_LINE_CTRL4_REG 0x0584
#define AB4500_USB_LINE_CTRL5_REG 0x0585
#define AB4500_USB_OTG_CTRL_REG 0x0587
#define AB4500_USB_OTG_STAT_REG 0x0588
#define AB4500_USB_OTG_STAT_REG 0x0588
#define AB4500_USB_CTRL_SPARE_REG 0x0589
#define AB4500_USB_PHY_CTRL_REG 0x058A
/*
* TVOUT / CTRL register offsets
* Bank : 0x06
*/
#define AB4500_TVOUT_CTRL_REG 0x0680
/*
* DBI register offsets
* Bank : 0x07
*/
#define AB4500_DBI_REG1_REG 0x0700
#define AB4500_DBI_REG2_REG 0x0701
/*
* ECI regsiter offsets
* Bank : 0x08
*/
#define AB4500_ECI_CTRL_REG 0x0800
#define AB4500_ECI_HOOKLEVEL_REG 0x0801
#define AB4500_ECI_DATAOUT_REG 0x0802
#define AB4500_ECI_DATAIN_REG 0x0803
/*
* AV Connector register offsets
* Bank : 0x08
*/
#define AB4500_AV_CONN_REG 0x0840
/*
* Accessory detection register offsets
* Bank : 0x08
*/
#define AB4500_ACC_DET_DB1_REG 0x0880
#define AB4500_ACC_DET_DB2_REG 0x0881
/*
* GPADC register offsets
* Bank : 0x0A
*/
#define AB4500_GPADC_CTRL1_REG 0x0A00
#define AB4500_GPADC_CTRL2_REG 0x0A01
#define AB4500_GPADC_CTRL3_REG 0x0A02
#define AB4500_GPADC_AUTO_TIMER_REG 0x0A03
#define AB4500_GPADC_STAT_REG 0x0A04
#define AB4500_GPADC_MANDATAL_REG 0x0A05
#define AB4500_GPADC_MANDATAH_REG 0x0A06
#define AB4500_GPADC_AUTODATAL_REG 0x0A07
#define AB4500_GPADC_AUTODATAH_REG 0x0A08
#define AB4500_GPADC_MUX_CTRL_REG 0x0A09
/*
* Charger / status register offfsets
* Bank : 0x0B
*/
#define AB4500_CH_STATUS1_REG 0x0B00
#define AB4500_CH_STATUS2_REG 0x0B01
#define AB4500_CH_USBCH_STAT1_REG 0x0B02
#define AB4500_CH_USBCH_STAT2_REG 0x0B03
#define AB4500_CH_FSM_STAT_REG 0x0B04
#define AB4500_CH_STAT_REG 0x0B05
/*
* Charger / control register offfsets
* Bank : 0x0B
*/
#define AB4500_CH_VOLT_LVL_REG 0x0B40
/*
* Charger / main control register offfsets
* Bank : 0x0B
*/
#define AB4500_MCH_CTRL1 0x0B80
#define AB4500_MCH_CTRL2 0x0B81
#define AB4500_MCH_IPT_CURLVL_REG 0x0B82
#define AB4500_CH_WD_REG 0x0B83
/*
* Charger / USB control register offsets
* Bank : 0x0B
*/
#define AB4500_USBCH_CTRL1_REG 0x0BC0
#define AB4500_USBCH_CTRL2_REG 0x0BC1
#define AB4500_USBCH_IPT_CRNTLVL_REG 0x0BC2
/*
* RTC bank register offsets
* Bank : 0xF
*/
#define AB4500_RTC_SOFF_STAT_REG 0x0F00
#define AB4500_RTC_CC_CONF_REG 0x0F01
#define AB4500_RTC_READ_REQ_REG 0x0F02
#define AB4500_RTC_WATCH_TSECMID_REG 0x0F03
#define AB4500_RTC_WATCH_TSECHI_REG 0x0F04
#define AB4500_RTC_WATCH_TMIN_LOW_REG 0x0F05
#define AB4500_RTC_WATCH_TMIN_MID_REG 0x0F06
#define AB4500_RTC_WATCH_TMIN_HI_REG 0x0F07
#define AB4500_RTC_ALRM_MIN_LOW_REG 0x0F08
#define AB4500_RTC_ALRM_MIN_MID_REG 0x0F09
#define AB4500_RTC_ALRM_MIN_HI_REG 0x0F0A
#define AB4500_RTC_STAT_REG 0x0F0B
#define AB4500_RTC_BKUP_CHG_REG 0x0F0C
#define AB4500_RTC_FORCE_BKUP_REG 0x0F0D
#define AB4500_RTC_CALIB_REG 0x0F0E
#define AB4500_RTC_SWITCH_STAT_REG 0x0F0F
/*
* PWM Out generators
* Bank: 0x10
*/
#define AB4500_PWM_OUT_CTRL1_REG 0x1060
#define AB4500_PWM_OUT_CTRL2_REG 0x1061
#define AB4500_PWM_OUT_CTRL3_REG 0x1062
#define AB4500_PWM_OUT_CTRL4_REG 0x1063
#define AB4500_PWM_OUT_CTRL5_REG 0x1064
#define AB4500_PWM_OUT_CTRL6_REG 0x1065
#define AB4500_PWM_OUT_CTRL7_REG 0x1066
#define AB4500_I2C_PAD_CTRL_REG 0x1067
#define AB4500_REV_REG 0x1080
/**
* struct ab4500
* @spi: spi device structure
* @tx_buf: transmit buffer
* @rx_buf: receive buffer
* @lock: sync primitive
*/
struct ab4500 {
struct spi_device *spi;
unsigned long tx_buf[4];
unsigned long rx_buf[4];
struct mutex lock;
};
int ab4500_write(struct ab4500 *ab4500, unsigned char block,
unsigned long addr, unsigned char data);
int ab4500_read(struct ab4500 *ab4500, unsigned char block,
unsigned long addr);
#endif /* MFD_AB4500_H */
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
*/
#ifndef MFD_AB8500_H
#define MFD_AB8500_H
#include <linux/device.h>
/*
* Interrupts
*/
#define AB8500_INT_MAIN_EXT_CH_NOT_OK 0
#define AB8500_INT_UN_PLUG_TV_DET 1
#define AB8500_INT_PLUG_TV_DET 2
#define AB8500_INT_TEMP_WARM 3
#define AB8500_INT_PON_KEY2DB_F 4
#define AB8500_INT_PON_KEY2DB_R 5
#define AB8500_INT_PON_KEY1DB_F 6
#define AB8500_INT_PON_KEY1DB_R 7
#define AB8500_INT_BATT_OVV 8
#define AB8500_INT_MAIN_CH_UNPLUG_DET 10
#define AB8500_INT_MAIN_CH_PLUG_DET 11
#define AB8500_INT_USB_ID_DET_F 12
#define AB8500_INT_USB_ID_DET_R 13
#define AB8500_INT_VBUS_DET_F 14
#define AB8500_INT_VBUS_DET_R 15
#define AB8500_INT_VBUS_CH_DROP_END 16
#define AB8500_INT_RTC_60S 17
#define AB8500_INT_RTC_ALARM 18
#define AB8500_INT_BAT_CTRL_INDB 20
#define AB8500_INT_CH_WD_EXP 21
#define AB8500_INT_VBUS_OVV 22
#define AB8500_INT_MAIN_CH_DROP_END 23
#define AB8500_INT_CCN_CONV_ACC 24
#define AB8500_INT_INT_AUD 25
#define AB8500_INT_CCEOC 26
#define AB8500_INT_CC_INT_CALIB 27
#define AB8500_INT_LOW_BAT_F 28
#define AB8500_INT_LOW_BAT_R 29
#define AB8500_INT_BUP_CHG_NOT_OK 30
#define AB8500_INT_BUP_CHG_OK 31
#define AB8500_INT_GP_HW_ADC_CONV_END 32
#define AB8500_INT_ACC_DETECT_1DB_F 33
#define AB8500_INT_ACC_DETECT_1DB_R 34
#define AB8500_INT_ACC_DETECT_22DB_F 35
#define AB8500_INT_ACC_DETECT_22DB_R 36
#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_NR_IRQS 104
#define AB8500_NUM_IRQ_REGS 13
/**
* struct ab8500 - ab8500 internal structure
* @dev: parent device
* @lock: read/write operations lock
* @irq_lock: genirq bus lock
* @revision: chip revision
* @irq: irq line
* @write: register write
* @read: register read
* @rx_buf: rx buf for SPI
* @tx_buf: tx buf for SPI
* @mask: cache of IRQ regs for bus lock
* @oldmask: cache of previous IRQ regs for bus lock
*/
struct ab8500 {
struct device *dev;
struct mutex lock;
struct mutex irq_lock;
int revision;
int irq_base;
int irq;
int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
int (*read) (struct ab8500 *a8500, u16 addr);
unsigned long tx_buf[4];
unsigned long rx_buf[4];
u8 mask[AB8500_NUM_IRQ_REGS];
u8 oldmask[AB8500_NUM_IRQ_REGS];
};
/**
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500
*/
struct ab8500_platform_data {
int irq_base;
void (*init) (struct ab8500 *);
};
extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
extern int ab8500_read(struct ab8500 *a8500, u16 addr);
extern int ab8500_set_bits(struct ab8500 *a8500, u16 addr, u8 mask, u8 data);
extern int __devinit ab8500_init(struct ab8500 *ab8500);
extern int __devexit ab8500_exit(struct ab8500 *ab8500);
#endif /* MFD_AB8500_H */
...@@ -3,17 +3,37 @@ ...@@ -3,17 +3,37 @@
* License terms: GNU General Public License (GPL) version 2 * License terms: GNU General Public License (GPL) version 2
* AB3100 core access functions * AB3100 core access functions
* Author: Linus Walleij <linus.walleij@stericsson.com> * Author: Linus Walleij <linus.walleij@stericsson.com>
*
* ABX500 core access functions.
* The abx500 interface is used for the Analog Baseband chip
* ab3100, ab3550, ab5500 and possibly comming. It is not used for
* ab4500 and ab8500 since they are another family of chip.
*
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
* Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
* Author: Rickard Andersson <rickard.andersson@stericsson.com>
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#ifndef MFD_AB3100_H #ifndef MFD_ABX500_H
#define MFD_AB3100_H #define MFD_ABX500_H
#define ABUNKNOWN 0 #define AB3100_P1A 0xc0
#define AB3000 1 #define AB3100_P1B 0xc1
#define AB3100 2 #define AB3100_P1C 0xc2
#define AB3100_P1D 0xc3
#define AB3100_P1E 0xc4
#define AB3100_P1F 0xc5
#define AB3100_P1G 0xc6
#define AB3100_R2A 0xc7
#define AB3100_R2B 0xc8
#define AB3550_P1A 0x10
#define AB5500_1_0 0x20
#define AB5500_2_0 0x21
#define AB5500_2_1 0x22
/* /*
* AB3100, EVENTA1, A2 and A3 event register flags * AB3100, EVENTA1, A2 and A3 event register flags
...@@ -89,7 +109,7 @@ struct ab3100 { ...@@ -89,7 +109,7 @@ struct ab3100 {
char chip_name[32]; char chip_name[32];
u8 chip_id; u8 chip_id;
struct blocking_notifier_head event_subscribers; struct blocking_notifier_head event_subscribers;
u32 startup_events; u8 startup_events[3];
bool startup_events_read; bool startup_events_read;
}; };
...@@ -112,18 +132,102 @@ struct ab3100_platform_data { ...@@ -112,18 +132,102 @@ struct ab3100_platform_data {
int external_voltage; int external_voltage;
}; };
int ab3100_set_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 regval);
int ab3100_get_register_interruptible(struct ab3100 *ab3100, u8 reg, u8 *regval);
int ab3100_get_register_page_interruptible(struct ab3100 *ab3100,
u8 first_reg, u8 *regvals, u8 numregs);
int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100,
u8 reg, u8 andmask, u8 ormask);
u8 ab3100_get_chip_type(struct ab3100 *ab3100);
int ab3100_event_register(struct ab3100 *ab3100, int ab3100_event_register(struct ab3100 *ab3100,
struct notifier_block *nb); struct notifier_block *nb);
int ab3100_event_unregister(struct ab3100 *ab3100, int ab3100_event_unregister(struct ab3100 *ab3100,
struct notifier_block *nb); struct notifier_block *nb);
int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100,
u32 *fatevent);
/* AB3550, STR register flags */
#define AB3550_STR_ONSWA (0x01)
#define AB3550_STR_ONSWB (0x02)
#define AB3550_STR_ONSWC (0x04)
#define AB3550_STR_DCIO (0x08)
#define AB3550_STR_BOOT_MODE (0x10)
#define AB3550_STR_SIM_OFF (0x20)
#define AB3550_STR_BATT_REMOVAL (0x40)
#define AB3550_STR_VBUS (0x80)
/* Interrupt mask registers */
#define AB3550_IMR1 0x29
#define AB3550_IMR2 0x2a
#define AB3550_IMR3 0x2b
#define AB3550_IMR4 0x2c
#define AB3550_IMR5 0x2d
enum ab3550_devid {
AB3550_DEVID_ADC,
AB3550_DEVID_DAC,
AB3550_DEVID_LEDS,
AB3550_DEVID_POWER,
AB3550_DEVID_REGULATORS,
AB3550_DEVID_SIM,
AB3550_DEVID_UART,
AB3550_DEVID_RTC,
AB3550_DEVID_CHARGER,
AB3550_DEVID_FUELGAUGE,
AB3550_DEVID_VIBRATOR,
AB3550_DEVID_CODEC,
AB3550_NUM_DEVICES,
};
/**
* struct abx500_init_setting
* Initial value of the registers for driver to use during setup.
*/
struct abx500_init_settings {
u8 bank;
u8 reg;
u8 setting;
};
/**
* struct ab3550_platform_data
* Data supplied to initialize board connections to the AB3550
*/
struct ab3550_platform_data {
struct {unsigned int base; unsigned int count; } irq;
void *dev_data[AB3550_NUM_DEVICES];
size_t dev_data_sz[AB3550_NUM_DEVICES];
struct abx500_init_settings *init_settings;
unsigned int init_settings_sz;
};
int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value);
int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 *value);
int abx500_get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs);
int abx500_set_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs);
/**
* abx500_mask_and_set_register_inerruptible() - Modifies selected bits of a
* target register
*
* @dev: The AB sub device.
* @bank: The i2c bank number.
* @bitmask: The bit mask to use.
* @bitvalues: The new bit values.
*
* Updates the value of an AB register:
* value -> ((value & ~bitmask) | (bitvalues & bitmask))
*/
int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues);
int abx500_get_chip_id(struct device *dev);
int abx500_event_registers_startup_state_get(struct device *dev, u8 *event);
int abx500_startup_irq_enabled(struct device *dev, unsigned int irq);
struct abx500_ops {
int (*get_chip_id) (struct device *);
int (*get_register) (struct device *, u8, u8, u8 *);
int (*set_register) (struct device *, u8, u8, u8);
int (*get_register_page) (struct device *, u8, u8, u8 *, u8);
int (*set_register_page) (struct device *, u8, u8, u8 *, u8);
int (*mask_and_set_register) (struct device *, u8, u8, u8, u8);
int (*event_registers_startup_state_get) (struct device *, u8 *);
int (*startup_irq_enabled) (struct device *, unsigned int);
};
int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
#endif #endif
/*
* Common Definitions for Janz MODULbus devices
*
* Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef JANZ_H
#define JANZ_H
struct janz_platform_data {
/* MODULbus Module Number */
unsigned int modno;
};
/* PLX bridge chip onboard registers */
struct janz_cmodio_onboard_regs {
u8 unused1;
/*
* Read access: interrupt status
* Write access: interrupt disable
*/
u8 int_disable;
u8 unused2;
/*
* Read access: MODULbus number (hex switch)
* Write access: interrupt enable
*/
u8 int_enable;
u8 unused3;
/* write-only */
u8 reset_assert;
u8 unused4;
/* write-only */
u8 reset_deassert;
u8 unused5;
/* read-write access to serial EEPROM */
u8 eep;
u8 unused6;
/* write-only access to EEPROM chip select */
u8 enid;
};
#endif /* JANZ_H */
#define PFX "rdc321x: " #ifndef __RDC321X_MFD_H
#define __RDC321X_MFD_H
/* General purpose configuration and data registers */ #include <linux/types.h>
#define RDC3210_CFGREG_ADDR 0x0CF8 #include <linux/pci.h>
#define RDC3210_CFGREG_DATA 0x0CFC
/* Offsets to be accessed in the southbridge PCI
* device configuration register */
#define RDC321X_WDT_CTRL 0x44
#define RDC321X_GPIO_CTRL_REG1 0x48 #define RDC321X_GPIO_CTRL_REG1 0x48
#define RDC321X_GPIO_CTRL_REG2 0x84
#define RDC321X_GPIO_DATA_REG1 0x4c #define RDC321X_GPIO_DATA_REG1 0x4c
#define RDC321X_GPIO_CTRL_REG2 0x84
#define RDC321X_GPIO_DATA_REG2 0x88 #define RDC321X_GPIO_DATA_REG2 0x88
#define RDC321X_MAX_GPIO 58 #define RDC321X_MAX_GPIO 58
struct rdc321x_gpio_pdata {
struct pci_dev *sb_pdev;
unsigned max_gpios;
};
struct rdc321x_wdt_pdata {
struct pci_dev *sb_pdev;
};
#endif /* __RDC321X_MFD_H */
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
*/
#ifndef __LINUX_MFD_TC35892_H
#define __LINUX_MFD_TC35892_H
#include <linux/device.h>
#define TC35892_RSTCTRL_IRQRST (1 << 4)
#define TC35892_RSTCTRL_TIMRST (1 << 3)
#define TC35892_RSTCTRL_ROTRST (1 << 2)
#define TC35892_RSTCTRL_KBDRST (1 << 1)
#define TC35892_RSTCTRL_GPIRST (1 << 0)
#define TC35892_IRQST 0x91
#define TC35892_MANFCODE_MAGIC 0x03
#define TC35892_MANFCODE 0x80
#define TC35892_VERSION 0x81
#define TC35892_IOCFG 0xA7
#define TC35892_CLKMODE 0x88
#define TC35892_CLKCFG 0x89
#define TC35892_CLKEN 0x8A
#define TC35892_RSTCTRL 0x82
#define TC35892_EXTRSTN 0x83
#define TC35892_RSTINTCLR 0x84
#define TC35892_GPIOIS0 0xC9
#define TC35892_GPIOIS1 0xCA
#define TC35892_GPIOIS2 0xCB
#define TC35892_GPIOIBE0 0xCC
#define TC35892_GPIOIBE1 0xCD
#define TC35892_GPIOIBE2 0xCE
#define TC35892_GPIOIEV0 0xCF
#define TC35892_GPIOIEV1 0xD0
#define TC35892_GPIOIEV2 0xD1
#define TC35892_GPIOIE0 0xD2
#define TC35892_GPIOIE1 0xD3
#define TC35892_GPIOIE2 0xD4
#define TC35892_GPIORIS0 0xD6
#define TC35892_GPIORIS1 0xD7
#define TC35892_GPIORIS2 0xD8
#define TC35892_GPIOMIS0 0xD9
#define TC35892_GPIOMIS1 0xDA
#define TC35892_GPIOMIS2 0xDB
#define TC35892_GPIOIC0 0xDC
#define TC35892_GPIOIC1 0xDD
#define TC35892_GPIOIC2 0xDE
#define TC35892_GPIODATA0 0xC0
#define TC35892_GPIOMASK0 0xc1
#define TC35892_GPIODATA1 0xC2
#define TC35892_GPIOMASK1 0xc3
#define TC35892_GPIODATA2 0xC4
#define TC35892_GPIOMASK2 0xC5
#define TC35892_GPIODIR0 0xC6
#define TC35892_GPIODIR1 0xC7
#define TC35892_GPIODIR2 0xC8
#define TC35892_GPIOSYNC0 0xE6
#define TC35892_GPIOSYNC1 0xE7
#define TC35892_GPIOSYNC2 0xE8
#define TC35892_GPIOWAKE0 0xE9
#define TC35892_GPIOWAKE1 0xEA
#define TC35892_GPIOWAKE2 0xEB
#define TC35892_GPIOODM0 0xE0
#define TC35892_GPIOODE0 0xE1
#define TC35892_GPIOODM1 0xE2
#define TC35892_GPIOODE1 0xE3
#define TC35892_GPIOODM2 0xE4
#define TC35892_GPIOODE2 0xE5
#define TC35892_INT_GPIIRQ 0
#define TC35892_INT_TI0IRQ 1
#define TC35892_INT_TI1IRQ 2
#define TC35892_INT_TI2IRQ 3
#define TC35892_INT_ROTIRQ 5
#define TC35892_INT_KBDIRQ 6
#define TC35892_INT_PORIRQ 7
#define TC35892_NR_INTERNAL_IRQS 8
#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x))
struct tc35892 {
struct mutex lock;
struct device *dev;
struct i2c_client *i2c;
int irq_base;
int num_gpio;
struct tc35892_platform_data *pdata;
};
extern int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data);
extern int tc35892_reg_read(struct tc35892 *tc35892, u8 reg);
extern int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length,
u8 *values);
extern int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length,
const u8 *values);
extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val);
/**
* struct tc35892_gpio_platform_data - TC35892 GPIO platform data
* @gpio_base: first gpio number assigned to TC35892. A maximum of
* %TC35892_NR_GPIOS GPIOs will be allocated.
*/
struct tc35892_gpio_platform_data {
int gpio_base;
};
/**
* struct tc35892_platform_data - TC35892 platform data
* @irq_base: base IRQ number. %TC35892_NR_IRQS irqs will be used.
* @gpio: GPIO-specific platform data
*/
struct tc35892_platform_data {
int irq_base;
struct tc35892_gpio_platform_data *gpio;
};
#define TC35892_NR_GPIOS 24
#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS)
#endif
/* linux/mfd/tps6507x.h
*
* Functions to access TPS65070 power management chip.
*
* Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com)
*
*
* For licencing details see kernel-base/COPYING
*/
#ifndef __LINUX_MFD_TPS6507X_H
#define __LINUX_MFD_TPS6507X_H
/*
* ----------------------------------------------------------------------------
* Registers, all 8 bits
* ----------------------------------------------------------------------------
*/
/* Register definitions */
#define TPS6507X_REG_PPATH1 0X01
#define TPS6507X_CHG_USB BIT(7)
#define TPS6507X_CHG_AC BIT(6)
#define TPS6507X_CHG_USB_PW_ENABLE BIT(5)
#define TPS6507X_CHG_AC_PW_ENABLE BIT(4)
#define TPS6507X_CHG_AC_CURRENT BIT(2)
#define TPS6507X_CHG_USB_CURRENT BIT(0)
#define TPS6507X_REG_INT 0X02
#define TPS6507X_REG_MASK_AC_USB BIT(7)
#define TPS6507X_REG_MASK_TSC BIT(6)
#define TPS6507X_REG_MASK_PB_IN BIT(5)
#define TPS6507X_REG_TSC_INT BIT(3)
#define TPS6507X_REG_PB_IN_INT BIT(2)
#define TPS6507X_REG_AC_USB_APPLIED BIT(1)
#define TPS6507X_REG_AC_USB_REMOVED BIT(0)
#define TPS6507X_REG_CHGCONFIG0 0X03
#define TPS6507X_REG_CHGCONFIG1 0X04
#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4)
#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3)
#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2)
#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1)
#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0)
#define TPS6507X_REG_CHGCONFIG2 0X05
#define TPS6507X_REG_CHGCONFIG3 0X06
#define TPS6507X_REG_ADCONFIG 0X07
#define TPS6507X_ADCONFIG_AD_ENABLE BIT(7)
#define TPS6507X_ADCONFIG_START_CONVERSION BIT(6)
#define TPS6507X_ADCONFIG_CONVERSION_DONE BIT(5)
#define TPS6507X_ADCONFIG_VREF_ENABLE BIT(4)
#define TPS6507X_ADCONFIG_INPUT_AD_IN1 0
#define TPS6507X_ADCONFIG_INPUT_AD_IN2 1
#define TPS6507X_ADCONFIG_INPUT_AD_IN3 2
#define TPS6507X_ADCONFIG_INPUT_AD_IN4 3
#define TPS6507X_ADCONFIG_INPUT_TS_PIN 4
#define TPS6507X_ADCONFIG_INPUT_BAT_CURRENT 5
#define TPS6507X_ADCONFIG_INPUT_AC_VOLTAGE 6
#define TPS6507X_ADCONFIG_INPUT_SYS_VOLTAGE 7
#define TPS6507X_ADCONFIG_INPUT_CHARGER_VOLTAGE 8
#define TPS6507X_ADCONFIG_INPUT_BAT_VOLTAGE 9
#define TPS6507X_ADCONFIG_INPUT_THRESHOLD_VOLTAGE 10
#define TPS6507X_ADCONFIG_INPUT_ISET1_VOLTAGE 11
#define TPS6507X_ADCONFIG_INPUT_ISET2_VOLTAGE 12
#define TPS6507X_ADCONFIG_INPUT_REAL_TSC 14
#define TPS6507X_ADCONFIG_INPUT_TSC 15
#define TPS6507X_REG_TSCMODE 0X08
#define TPS6507X_TSCMODE_X_POSITION 0
#define TPS6507X_TSCMODE_Y_POSITION 1
#define TPS6507X_TSCMODE_PRESSURE 2
#define TPS6507X_TSCMODE_X_PLATE 3
#define TPS6507X_TSCMODE_Y_PLATE 4
#define TPS6507X_TSCMODE_STANDBY 5
#define TPS6507X_TSCMODE_ADC_INPUT 6
#define TPS6507X_TSCMODE_DISABLE 7
#define TPS6507X_REG_ADRESULT_1 0X09
#define TPS6507X_REG_ADRESULT_2 0X0A
#define TPS6507X_REG_ADRESULT_2_MASK (BIT(1) | BIT(0))
#define TPS6507X_REG_PGOOD 0X0B
#define TPS6507X_REG_PGOODMASK 0X0C
#define TPS6507X_REG_CON_CTRL1 0X0D
#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4)
#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3)
#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2)
#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1)
#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0)
#define TPS6507X_REG_CON_CTRL2 0X0E
#define TPS6507X_REG_CON_CTRL3 0X0F
#define TPS6507X_REG_DEFDCDC1 0X10
#define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN BIT(7)
#define TPS6507X_DEFDCDC1_DCDC1_MASK 0X3F
#define TPS6507X_REG_DEFDCDC2_LOW 0X11
#define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK 0X3F
#define TPS6507X_REG_DEFDCDC2_HIGH 0X12
#define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK 0X3F
#define TPS6507X_REG_DEFDCDC3_LOW 0X13
#define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK 0X3F
#define TPS6507X_REG_DEFDCDC3_HIGH 0X14
#define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK 0X3F
#define TPS6507X_REG_DEFSLEW 0X15
#define TPS6507X_REG_LDO_CTRL1 0X16
#define TPS6507X_REG_LDO_CTRL1_LDO1_MASK 0X0F
#define TPS6507X_REG_DEFLDO2 0X17
#define TPS6507X_REG_DEFLDO2_LDO2_MASK 0X3F
#define TPS6507X_REG_WLED_CTRL1 0X18
#define TPS6507X_REG_WLED_CTRL2 0X19
/* VDCDC MASK */
#define TPS6507X_DEFDCDCX_DCDC_MASK 0X3F
#define TPS6507X_MAX_REGISTER 0X19
/**
* struct tps6507x_board - packages regulator and touchscreen init data
* @tps6507x_regulator_data: regulator initialization values
*
* Board data may be used to initialize regulator and touchscreen.
*/
struct tps6507x_board {
struct regulator_init_data *tps6507x_pmic_init_data;
struct touchscreen_init_data *tps6507x_ts_init_data;
};
/**
* struct tps6507x_dev - tps6507x sub-driver chip access routines
* @read_dev() - I2C register read function
* @write_dev() - I2C register write function
*
* Device data may be used to access the TPS6507x chip
*/
struct tps6507x_dev {
struct device *dev;
struct i2c_client *i2c_client;
int (*read_dev)(struct tps6507x_dev *tps6507x, char reg, int size,
void *dest);
int (*write_dev)(struct tps6507x_dev *tps6507x, char reg, int size,
void *src);
/* Client devices */
struct tps6507x_pmic *pmic;
struct tps6507x_ts *ts;
};
#endif /* __LINUX_MFD_TPS6507X_H */
...@@ -258,6 +258,7 @@ struct wm831x { ...@@ -258,6 +258,7 @@ struct wm831x {
/* Chip revision based flags */ /* Chip revision based flags */
unsigned has_gpio_ena:1; /* Has GPIO enable bit */ unsigned has_gpio_ena:1; /* Has GPIO enable bit */
unsigned has_cs_sts:1; /* Has current sink status bit */ unsigned has_cs_sts:1; /* Has current sink status bit */
unsigned charger_irq_wake:1; /* Are charger IRQs a wake source? */
int num_gpio; int num_gpio;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment