diff options
Diffstat (limited to 'drivers/mfd')
33 files changed, 2941 insertions, 997 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index 391e23e6a64..582bda54352 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -531,7 +531,7 @@ static int pm800_probe(struct i2c_client *client, ret = device_800_init(chip, pdata); if (ret) { dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id); - goto err_800_init; + goto err_subchip_alloc; } ret = pm800_pages_init(chip); @@ -546,10 +546,8 @@ static int pm800_probe(struct i2c_client *client, err_page_init: mfd_remove_devices(chip->dev); device_irq_exit_800(chip); -err_800_init: - devm_kfree(&client->dev, subchip); err_subchip_alloc: - pm80x_deinit(client); + pm80x_deinit(); out_init: return ret; } @@ -562,9 +560,7 @@ static int pm800_remove(struct i2c_client *client) device_irq_exit_800(chip); pm800_pages_exit(chip); - devm_kfree(&client->dev, chip->subchip); - - pm80x_deinit(client); + pm80x_deinit(); return 0; } diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index e671230be2b..65d7ac099b2 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -257,7 +257,7 @@ static int pm805_probe(struct i2c_client *client, pdata->plat_config(chip, pdata); err_805_init: - pm80x_deinit(client); + pm80x_deinit(); out_init: return ret; } @@ -269,7 +269,7 @@ static int pm805_remove(struct i2c_client *client) mfd_remove_devices(chip->dev); device_irq_exit_805(chip); - pm80x_deinit(client); + pm80x_deinit(); return 0; } diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c index 1adb355d86d..f736a46eb8c 100644 --- a/drivers/mfd/88pm80x.c +++ b/drivers/mfd/88pm80x.c @@ -48,14 +48,12 @@ int pm80x_init(struct i2c_client *client, ret = PTR_ERR(map); dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); - goto err_regmap_init; + return ret; } chip->id = id->driver_data; - if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) { - ret = -EINVAL; - goto err_chip_id; - } + if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) + return -EINVAL; chip->client = client; chip->regmap = map; @@ -82,19 +80,11 @@ int pm80x_init(struct i2c_client *client, } return 0; - -err_chip_id: - regmap_exit(map); -err_regmap_init: - devm_kfree(&client->dev, chip); - return ret; } EXPORT_SYMBOL_GPL(pm80x_init); -int pm80x_deinit(struct i2c_client *client) +int pm80x_deinit(void) { - struct pm80x_chip *chip = i2c_get_clientdata(client); - /* * workaround: clear the dependency between pm800 and pm805. * would remove it after HW chip fixes the issue. @@ -103,10 +93,6 @@ int pm80x_deinit(struct i2c_client *client) g_pm80x_chip->companion = NULL; else g_pm80x_chip = NULL; - - regmap_exit(chip->regmap); - devm_kfree(&client->dev, chip); - return 0; } EXPORT_SYMBOL_GPL(pm80x_deinit); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ff553babf45..671f5b171c7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -65,7 +65,7 @@ config MFD_SM501_GPIO config MFD_RTSX_PCI tristate "Support for Realtek PCI-E card reader" - depends on PCI + depends on PCI && GENERIC_HARDIRQS select MFD_CORE help This supports for Realtek PCI-Express card reader including rts5209, @@ -95,7 +95,7 @@ config MFD_DM355EVM_MSP config MFD_TI_SSP tristate "TI Sequencer Serial Port support" - depends on ARCH_DAVINCI_TNETV107X + depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS select MFD_CORE ---help--- Say Y here if you want support for the Sequencer Serial Port @@ -109,6 +109,7 @@ config MFD_TI_AM335X_TSCADC select MFD_CORE select REGMAP select REGMAP_MMIO + depends on GENERIC_HARDIRQS help If you say yes here you get support for Texas Instruments series of Touch Screen /ADC chips. @@ -126,6 +127,7 @@ config HTC_EGPIO config HTC_PASIC3 tristate "HTC PASIC3 LED/DS1WM chip support" select MFD_CORE + depends on GENERIC_HARDIRQS help This core driver provides register access for the LED/DS1WM chips labeled "AIC2" and "AIC3", found on HTC Blueangel and @@ -157,6 +159,7 @@ config MFD_LM3533 depends on I2C select MFD_CORE select REGMAP_I2C + depends on GENERIC_HARDIRQS help Say yes here to enable support for National Semiconductor / TI LM3533 Lighting Power chips. @@ -171,6 +174,7 @@ config TPS6105X select REGULATOR select MFD_CORE select REGULATOR_FIXED_VOLTAGE + depends on GENERIC_HARDIRQS help This option enables a driver for the TP61050/TPS61052 high-power "white LED driver". This boost converter is @@ -193,7 +197,7 @@ config TPS65010 config TPS6507X tristate "TPS6507x Power Management / Touch Screen chips" select MFD_CORE - depends on I2C + depends on I2C && GENERIC_HARDIRQS help If you say yes here you get support for the TPS6507x series of Power Management / Touch Screen chips. These include voltage @@ -204,7 +208,7 @@ config TPS6507X config MFD_TPS65217 tristate "TPS65217 Power Management / White LED chips" - depends on I2C + depends on I2C && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C help @@ -234,7 +238,7 @@ config MFD_TPS6586X config MFD_TPS65910 bool "TPS65910 Power Management chip" - depends on I2C=y && GPIOLIB + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -251,7 +255,7 @@ config MFD_TPS65912_I2C bool "TPS65912 Power Management chip with I2C" select MFD_CORE select MFD_TPS65912 - depends on I2C=y && GPIOLIB + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS help If you say yes here you get support for the TPS65912 series of PM chips with I2C interface. @@ -260,7 +264,7 @@ config MFD_TPS65912_SPI bool "TPS65912 Power Management chip with SPI" select MFD_CORE select MFD_TPS65912 - depends on SPI_MASTER && GPIOLIB + depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS help If you say yes here you get support for the TPS65912 series of PM chips with SPI interface. @@ -330,13 +334,13 @@ config TWL4030_POWER config MFD_TWL4030_AUDIO bool - depends on TWL4030_CORE + depends on TWL4030_CORE && GENERIC_HARDIRQS select MFD_CORE default n config TWL6040_CORE bool "Support for TWL6040 audio codec" - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -405,7 +409,7 @@ config MFD_TMIO config MFD_T7L66XB bool "Support Toshiba T7L66XB" - depends on ARM && HAVE_CLK + depends on ARM && HAVE_CLK && GENERIC_HARDIRQS select MFD_CORE select MFD_TMIO help @@ -413,7 +417,7 @@ config MFD_T7L66XB config MFD_SMSC bool "Support for the SMSC ECE1099 series chips" - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C help @@ -460,7 +464,7 @@ config MFD_DA9052_SPI select REGMAP_SPI select REGMAP_IRQ select PMIC_DA9052 - depends on SPI_MASTER=y + depends on SPI_MASTER=y && GENERIC_HARDIRQS help Support for the Dialog Semiconductor DA9052 PMIC when controlled using SPI. This driver provides common support @@ -472,7 +476,7 @@ config MFD_DA9052_I2C select REGMAP_I2C select REGMAP_IRQ select PMIC_DA9052 - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS help Support for the Dialog Semiconductor DA9052 PMIC when controlled using I2C. This driver provides common support @@ -485,7 +489,7 @@ config MFD_DA9055 select REGMAP_IRQ select PMIC_DA9055 select MFD_CORE - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS help Say yes here for support of Dialog Semiconductor DA9055. This is a Power Management IC. This driver provides common support for @@ -508,7 +512,7 @@ config PMIC_ADP5520 config MFD_LP8788 bool "Texas Instruments LP8788 Power Management Unit Driver" - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS select MFD_CORE select REGMAP_I2C select IRQ_DOMAIN @@ -611,7 +615,7 @@ config MFD_ARIZONA_I2C select MFD_ARIZONA select MFD_CORE select REGMAP_I2C - depends on I2C + depends on I2C && GENERIC_HARDIRQS help Support for the Wolfson Microelectronics Arizona platform audio SoC core functionality controlled via I2C. @@ -621,7 +625,7 @@ config MFD_ARIZONA_SPI select MFD_ARIZONA select MFD_CORE select REGMAP_SPI - depends on SPI_MASTER + depends on SPI_MASTER && GENERIC_HARDIRQS help Support for the Wolfson Microelectronics Arizona platform audio SoC core functionality controlled via I2C. @@ -641,7 +645,7 @@ config MFD_WM5110 config MFD_WM8400 bool "Support Wolfson Microelectronics WM8400" select MFD_CORE - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS select REGMAP_I2C help Support for the Wolfson Microelecronics WM8400 PMIC and audio @@ -785,7 +789,7 @@ config MFD_MC13783 config MFD_MC13XXX tristate - depends on SPI_MASTER || I2C + depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS select MFD_CORE select MFD_MC13783 help @@ -796,7 +800,7 @@ config MFD_MC13XXX config MFD_MC13XXX_SPI tristate "Freescale MC13783 and MC13892 SPI interface" - depends on SPI_MASTER + depends on SPI_MASTER && GENERIC_HARDIRQS select REGMAP_SPI select MFD_MC13XXX help @@ -804,7 +808,7 @@ config MFD_MC13XXX_SPI config MFD_MC13XXX_I2C tristate "Freescale MC13892 I2C interface" - depends on I2C + depends on I2C && GENERIC_HARDIRQS select REGMAP_I2C select MFD_MC13XXX help @@ -822,7 +826,7 @@ config ABX500_CORE config AB3100_CORE bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C=y && ABX500_CORE + depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS select MFD_CORE default y if ARCH_U300 help @@ -909,7 +913,7 @@ config MFD_TIMBERDALE config LPC_SCH tristate "Intel SCH LPC" - depends on PCI + depends on PCI && GENERIC_HARDIRQS select MFD_CORE help LPC bridge function of the Intel SCH provides support for @@ -917,7 +921,7 @@ config LPC_SCH config LPC_ICH tristate "Intel ICH LPC" - depends on PCI + depends on PCI && GENERIC_HARDIRQS select MFD_CORE help The LPC bridge function of the Intel ICH provides support for @@ -928,7 +932,7 @@ config LPC_ICH config MFD_RDC321X tristate "Support for RDC-R321x southbridge" select MFD_CORE - depends on PCI + depends on PCI && GENERIC_HARDIRQS 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 @@ -937,7 +941,7 @@ config MFD_RDC321X config MFD_JANZ_CMODIO tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE - depends on PCI + depends on PCI && GENERIC_HARDIRQS 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 @@ -955,7 +959,7 @@ config MFD_JZ4740_ADC config MFD_VX855 tristate "Support for VIA VX855/VX875 integrated south bridge" - depends on PCI + depends on PCI && GENERIC_HARDIRQS select MFD_CORE help Say yes here to enable support for various functions of the @@ -964,7 +968,7 @@ config MFD_VX855 config MFD_WL1273_CORE tristate "Support for TI WL1273 FM radio." - depends on I2C + depends on I2C && GENERIC_HARDIRQS select MFD_CORE default n help @@ -1028,7 +1032,7 @@ config MFD_TPS65090 config MFD_AAT2870_CORE bool "Support for the AnalogicTech AAT2870" select MFD_CORE - depends on I2C=y && GPIOLIB + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS help If you say yes here you get support for the AAT2870. This driver provides common support for accessing the device, @@ -1060,7 +1064,7 @@ config MFD_RC5T583 config MFD_STA2X11 bool "STA2X11 multi function device support" - depends on STA2X11 + depends on STA2X11 && GENERIC_HARDIRQS select MFD_CORE select REGMAP_MMIO @@ -1077,7 +1081,7 @@ config MFD_PALMAS select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS help If you say yes here you get support for the Palmas series of PMIC chips from Texas Instruments. @@ -1085,7 +1089,7 @@ config MFD_PALMAS config MFD_VIPERBOARD tristate "Support for Nano River Technologies Viperboard" select MFD_CORE - depends on USB + depends on USB && GENERIC_HARDIRQS default n help Say yes here if you want support for Nano River Technologies @@ -1099,7 +1103,7 @@ config MFD_VIPERBOARD config MFD_RETU tristate "Support for Retu multi-function device" select MFD_CORE - depends on I2C + depends on I2C && GENERIC_HARDIRQS select REGMAP_IRQ help Retu is a multi-function device found on Nokia Internet Tablets @@ -1110,7 +1114,7 @@ config MFD_AS3711 select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y + depends on I2C=y && GENERIC_HARDIRQS help Support for the AS3711 PMIC from AMS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 8b977f8045a..b90409c2366 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o -rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o +rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8b5d685ab98..7c84ced2e01 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -320,6 +320,7 @@ static struct abx500_ops ab8500_ops = { .mask_and_set_register = ab8500_mask_and_set_register, .event_registers_startup_state_get = NULL, .startup_irq_enabled = NULL, + .dump_all_banks = ab8500_dump_all_banks, }; static void ab8500_irq_lock(struct irq_data *data) @@ -368,16 +369,48 @@ static void ab8500_irq_mask(struct irq_data *data) int mask = 1 << (offset % 8); ab8500->mask[index] |= mask; + + /* The AB8500 GPIOs have two interrupts each (rising & falling). */ + if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) + ab8500->mask[index + 2] |= mask; + if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) + ab8500->mask[index + 1] |= mask; + if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) + /* Here the falling IRQ is one bit lower */ + ab8500->mask[index] |= (mask << 1); } static void ab8500_irq_unmask(struct irq_data *data) { struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); + unsigned int type = irqd_get_trigger_type(data); int offset = data->hwirq; int index = offset / 8; int mask = 1 << (offset % 8); - ab8500->mask[index] &= ~mask; + if (type & IRQ_TYPE_EDGE_RISING) + ab8500->mask[index] &= ~mask; + + /* The AB8500 GPIOs have two interrupts each (rising & falling). */ + if (type & IRQ_TYPE_EDGE_FALLING) { + if (offset >= AB8500_INT_GPIO6R && offset <= AB8500_INT_GPIO41R) + ab8500->mask[index + 2] &= ~mask; + else if (offset >= AB9540_INT_GPIO50R && offset <= AB9540_INT_GPIO54R) + ab8500->mask[index + 1] &= ~mask; + else if (offset == AB8540_INT_GPIO43R || offset == AB8540_INT_GPIO44R) + /* Here the falling IRQ is one bit lower */ + ab8500->mask[index] &= ~(mask << 1); + else + ab8500->mask[index] &= ~mask; + } else { + /* Satisfies the case where type is not set. */ + ab8500->mask[index] &= ~mask; + } +} + +static int ab8500_irq_set_type(struct irq_data *data, unsigned int type) +{ + return 0; } static struct irq_chip ab8500_irq_chip = { @@ -387,6 +420,7 @@ static struct irq_chip ab8500_irq_chip = { .irq_mask = ab8500_irq_mask, .irq_disable = ab8500_irq_mask, .irq_unmask = ab8500_irq_unmask, + .irq_set_type = ab8500_irq_set_type, }; static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, @@ -411,6 +445,19 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, line = (i << 3) + int_bit; latch_val &= ~(1 << int_bit); + /* + * This handles the falling edge hwirqs from the GPIO + * lines. Route them back to the line registered for the + * rising IRQ, as this is merely a flag for the same IRQ + * in linux terms. + */ + if (line >= AB8500_INT_GPIO6F && line <= AB8500_INT_GPIO41F) + line -= 16; + if (line >= AB9540_INT_GPIO50F && line <= AB9540_INT_GPIO54F) + line -= 8; + if (line == AB8540_INT_GPIO43F || line == AB8540_INT_GPIO44F) + line += 1; + handle_nested_irq(ab8500->irq_base + line); } while (latch_val); @@ -521,6 +568,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int virq = ab8500_irq_get_virq(ab8500, line); handle_nested_irq(virq); + ab8500_debug_register_interrupt(line); value &= ~(1 << bit); } while (value); @@ -929,7 +977,7 @@ static struct resource ab8505_iddet_resources[] = { static struct resource ab8500_temp_resources[] = { { - .name = "AB8500_TEMP_WARM", + .name = "ABX500_TEMP_WARM", .start = AB8500_INT_TEMP_WARM, .end = AB8500_INT_TEMP_WARM, .flags = IORESOURCE_IRQ, @@ -1005,8 +1053,8 @@ static struct mfd_cell abx500_common_devs[] = { .of_compatible = "stericsson,ab8500-denc", }, { - .name = "ab8500-temp", - .of_compatible = "stericsson,ab8500-temp", + .name = "abx500-temp", + .of_compatible = "stericsson,abx500-temp", .num_resources = ARRAY_SIZE(ab8500_temp_resources), .resources = ab8500_temp_resources, }, @@ -1049,7 +1097,7 @@ static struct mfd_cell ab8500_bm_devs[] = { static struct mfd_cell ab8500_devs[] = { { - .name = "ab8500-gpio", + .name = "pinctrl-ab8500", .of_compatible = "stericsson,ab8500-gpio", }, { @@ -1066,7 +1114,8 @@ static struct mfd_cell ab8500_devs[] = { static struct mfd_cell ab9540_devs[] = { { - .name = "ab8500-gpio", + .name = "pinctrl-ab9540", + .of_compatible = "stericsson,ab9540-gpio", }, { .name = "ab9540-usb", diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 5a8e707bc03..45fe3c50eb0 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -4,6 +4,72 @@ * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. * License Terms: GNU General Public License v2 */ +/* + * AB8500 register access + * ====================== + * + * read: + * # echo BANK > <debugfs>/ab8500/register-bank + * # echo ADDR > <debugfs>/ab8500/register-address + * # cat <debugfs>/ab8500/register-value + * + * write: + * # echo BANK > <debugfs>/ab8500/register-bank + * # echo ADDR > <debugfs>/ab8500/register-address + * # echo VALUE > <debugfs>/ab8500/register-value + * + * read all registers from a bank: + * # echo BANK > <debugfs>/ab8500/register-bank + * # cat <debugfs>/ab8500/all-bank-register + * + * BANK target AB8500 register bank + * ADDR target AB8500 register address + * VALUE decimal or 0x-prefixed hexadecimal + * + * + * User Space notification on AB8500 IRQ + * ===================================== + * + * Allows user space entity to be notified when target AB8500 IRQ occurs. + * When subscribed, a sysfs entry is created in ab8500.i2c platform device. + * One can pool this file to get target IRQ occurence information. + * + * subscribe to an AB8500 IRQ: + * # echo IRQ > <debugfs>/ab8500/irq-subscribe + * + * unsubscribe from an AB8500 IRQ: + * # echo IRQ > <debugfs>/ab8500/irq-unsubscribe + * + * + * AB8500 register formated read/write access + * ========================================== + * + * Read: read data, data>>SHIFT, data&=MASK, output data + * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE + * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data + * [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98] + * + * Usage: + * # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg + * + * CMD read read access + * write write access + * + * BANK target reg bank + * ADDRESS target reg address + * VALUE (write) value to be updated + * + * OPTIONS + * -d|-dec (read) output in decimal + * -h|-hexa (read) output in 0x-hexa (default) + * -l|-w|-b 32bit (default), 16bit or 8bit reg access + * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF) + * -s|-shift SHIFT bit shift value (read:left, write:right) + * -o|-offset OFFSET address offset to add to ADDRESS value + * + * Warning: bit shift operation is applied to bit-mask. + * Warning: bit shift direction depends on read or right command. + */ #include <linux/seq_file.h> #include <linux/uaccess.h> @@ -11,13 +77,30 @@ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/kobject.h> +#include <linux/slab.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> +#include <linux/mfd/abx500/ab8500-gpadc.h> + +#ifdef CONFIG_DEBUG_FS +#include <linux/string.h> +#include <linux/ctype.h> +#endif static u32 debug_bank; static u32 debug_address; +static int irq_first; +static int irq_last; +static u32 *irq_count; +static int num_irqs; + +static struct device_attribute **dev_attr; +static char **event_name; + /** * struct ab8500_reg_range * @first: the first address of the range @@ -42,15 +125,35 @@ struct ab8500_prcmu_ranges { const struct ab8500_reg_range *range; }; +/* hwreg- "mask" and "shift" entries ressources */ +struct hwreg_cfg { + u32 bank; /* target bank */ + u32 addr; /* target address */ + uint fmt; /* format */ + uint mask; /* read/write mask, applied before any bit shift */ + int shift; /* bit shift (read:right shift, write:left shift */ +}; +/* fmt bit #0: 0=hexa, 1=dec */ +#define REG_FMT_DEC(c) ((c)->fmt & 0x1) +#define REG_FMT_HEX(c) (!REG_FMT_DEC(c)) + +static struct hwreg_cfg hwreg_cfg = { + .addr = 0, /* default: invalid phys addr */ + .fmt = 0, /* default: 32bit access, hex output */ + .mask = 0xFFFFFFFF, /* default: no mask */ + .shift = 0, /* default: no bit shift */ +}; + #define AB8500_NAME_STRING "ab8500" -#define AB8500_NUM_BANKS 22 +#define AB8500_ADC_NAME_STRING "gpadc" +#define AB8500_NUM_BANKS 24 #define AB8500_REV_REG 0x80 static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = { [0x0] = { .num_ranges = 0, - .range = 0, + .range = NULL, }, [AB8500_SYS_CTRL1_BLOCK] = { .num_ranges = 3, @@ -215,7 +318,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = { }, }, [AB8500_CHARGER] = { - .num_ranges = 8, + .num_ranges = 9, .range = (struct ab8500_reg_range[]) { { .first = 0x00, @@ -249,6 +352,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = { .first = 0xC0, .last = 0xC2, }, + { + .first = 0xf5, + .last = 0xf6, + }, }, }, [AB8500_GAS_GAUGE] = { @@ -268,6 +375,24 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = { }, }, }, + [AB8500_DEVELOPMENT] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x00, + .last = 0x00, + }, + }, + }, + [AB8500_DEBUG] = { + .num_ranges = 1, + .range = (struct ab8500_reg_range[]) { + { + .first = 0x05, + .last = 0x07, + }, + }, + }, [AB8500_AUDIO] = { .num_ranges = 1, .range = (struct ab8500_reg_range[]) { @@ -354,15 +479,30 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = { }, }; -static int ab8500_registers_print(struct seq_file *s, void *p) +static irqreturn_t ab8500_debug_handler(int irq, void *data) { - struct device *dev = s->private; - unsigned int i; - u32 bank = debug_bank; + char buf[16]; + struct kobject *kobj = (struct kobject *)data; + unsigned int irq_abb = irq - irq_first; - seq_printf(s, AB8500_NAME_STRING " register values:\n"); + if (irq_abb < num_irqs) + irq_count[irq_abb]++; + /* + * This makes it possible to use poll for events (POLLPRI | POLLERR) + * from userspace on sysfs file named <irq-nr> + */ + sprintf(buf, "%d", irq); + sysfs_notify(kobj, NULL, buf); + + return IRQ_HANDLED; +} + +/* Prints to seq_file or log_buf */ +static int ab8500_registers_print(struct device *dev, u32 bank, + struct seq_file *s) +{ + unsigned int i; - seq_printf(s, " bank %u:\n", bank); for (i = 0; i < debug_ranges[bank].num_ranges; i++) { u32 reg; @@ -379,22 +519,42 @@ static int ab8500_registers_print(struct seq_file *s, void *p) return err; } - err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, - reg, value); - if (err < 0) { - dev_err(dev, "seq_printf overflow\n"); - /* Error is not returned here since - * the output is wanted in any case */ - return 0; + if (s) { + err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", + bank, reg, value); + if (err < 0) { + dev_err(dev, + "seq_printf overflow bank=%d reg=%d\n", + bank, reg); + /* Error is not returned here since + * the output is wanted in any case */ + return 0; + } + } else { + printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank, + reg, value); } } } return 0; } +static int ab8500_print_bank_registers(struct seq_file *s, void *p) +{ + struct device *dev = s->private; + u32 bank = debug_bank; + + seq_printf(s, AB8500_NAME_STRING " register values:\n"); + + seq_printf(s, " bank %u:\n", bank); + + ab8500_registers_print(dev, bank, s); + return 0; +} + static int ab8500_registers_open(struct inode *inode, struct file *file) { - return single_open(file, ab8500_registers_print, inode->i_private); + return single_open(file, ab8500_print_ba |