* [PATCH v5 6/9] ARM: davinci: Remoteproc driver support for OMAP-L138 DSP
From: Sekhar Nori @ 2013-01-15 12:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK=WgbbShpqxS7zrDs97HkjpyWq0xzW3b9KHLBBs_V3YzdJKiA@mail.gmail.com>
On 1/15/2013 3:33 PM, Ohad Ben-Cohen wrote:
> On Tue, Jan 15, 2013 at 11:15 AM, Sekhar Nori <nsekhar@ti.com> wrote:
>> Right, and platform data is not the way to achieve this.
>
> How do you suggest to handle platforms with multiple different remote
> processors (driven by the same driver) ?
>
> Requiring the user to indicate the fw name for each processor is
> somewhat error prone/cumbersome.
May be rproc_alloc() could auto-assign the firmware name to something
like 'rproc%d-fw' if firmware name passed to it is NULL?
Thanks,
Sekhar
^ permalink raw reply
* [PATCH 3/4] Enable ecc-mode selection in the driver
From: Jason Cooper @ 2013-01-15 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2d08c4c072fd4922a6056362adb96a455307d583.1358242644.git.s.peter@mpl.ch>
Stefan,
This is a good-looking patch series, nice and small! A few comments:
On Tue, Jan 15, 2013 at 01:13:12PM +0100, Stefan Peter wrote:
> In order to be able to use the ecc-mode, add the bch module to the default
> settings for the kirwood boards and enable the activation in orin-nand.c
s/orin-nand/orion-nand/
>
> Signed-off-by: Stefan Peter <s.peter@mpl.ch>
> ---
> diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
> index 93f3794..4a9d3f7 100644
> --- a/arch/arm/configs/kirkwood_defconfig
> +++ b/arch/arm/configs/kirkwood_defconfig
> @@ -84,6 +84,7 @@ CONFIG_MTD_CFI_STAA=y
> CONFIG_MTD_PHYSMAP=y
> CONFIG_MTD_M25P80=y
> CONFIG_MTD_NAND=y
> +CONFIG_MTD_NAND_ECC_BCH=y
> CONFIG_MTD_NAND_ORION=y
> CONFIG_BLK_DEV_LOOP=y
> # CONFIG_SCSI_PROC_FS is not set
Please make the defconfig change a separate patch.
As a general note (this series shouldn't be a problem), please sort the
series so that you add the driver feature first, then enable it in
defconfig, then use it in DT. This way, a future bisection won't run
into any nasty surprises, other than what they're looking for. ;-)
thx,
Jason.
^ permalink raw reply
* [PATCH 10/14] PCI: tegra: Move PCIe driver to drivers/pci/host
From: Arnd Bergmann @ 2013-01-15 12:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20130115120855.GA5637@avionic-0098.adnet.avionic-design.de>
On Tuesday 15 January 2013, Thierry Reding wrote:
> I'm not sure I follow you're reasoning here. Is it possible to use MSIs
> without PCI? If not then I think there's little sense in keeping the
> implementations separate.
Conceptually, you can use MSI for any device, but the Linux interfaces
for MSI are tied to PCI. If you use an MSI controller for a non-PCI
device, it would probably just appear as a regular interrupt controller.
> Furthermore, if MSI controller and PCI host bridge are separate entities
> how do you look up the MSI controller given a PCI device?
The host bridge can contain a pointer ot the MSI controller. You can
have multiple host bridges sharing a single MSI controller or you
can have separate ones for each host.
Arnd
^ permalink raw reply
* [PATCH v5 6/9] ARM: davinci: Remoteproc driver support for OMAP-L138 DSP
From: Ohad Ben-Cohen @ 2013-01-15 12:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50F54B91.4030406@ti.com>
On Tue, Jan 15, 2013 at 2:29 PM, Sekhar Nori <nsekhar@ti.com> wrote:
> May be rproc_alloc() could auto-assign the firmware name to something
> like 'rproc%d-fw' if firmware name passed to it is NULL?
I prefer we use name-based filenames instead to make it easier for
users (and us developers).
We can probably do something like "rproc-%s-fw" with pdata->name
assuming we/you do maintain a meaningful name in the latter.
Thanks,
Ohad.
^ permalink raw reply
* [PATCH 3/4] Enable ecc-mode selection in the driver
From: Andrew Lunn @ 2013-01-15 12:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2d08c4c072fd4922a6056362adb96a455307d583.1358242644.git.s.peter@mpl.ch>
On Tue, Jan 15, 2013 at 01:13:12PM +0100, Stefan Peter wrote:
> In order to be able to use the ecc-mode, add the bch module to the default
> settings for the kirwood boards and enable the activation in orin-nand.c
>
> Signed-off-by: Stefan Peter <s.peter@mpl.ch>
> ---
> diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
> index 93f3794..4a9d3f7 100644
> --- a/arch/arm/configs/kirkwood_defconfig
> +++ b/arch/arm/configs/kirkwood_defconfig
> @@ -84,6 +84,7 @@ CONFIG_MTD_CFI_STAA=y
> CONFIG_MTD_PHYSMAP=y
> CONFIG_MTD_M25P80=y
> CONFIG_MTD_NAND=y
> +CONFIG_MTD_NAND_ECC_BCH=y
> CONFIG_MTD_NAND_ORION=y
> CONFIG_BLK_DEV_LOOP=y
> # CONFIG_SCSI_PROC_FS is not set
> diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
> index cd72b92..1a35257 100644
> --- a/drivers/mtd/nand/orion_nand.c
> +++ b/drivers/mtd/nand/orion_nand.c
> @@ -14,6 +14,7 @@
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/of.h>
> +#include <linux/of_mtd.h>
> #include <linux/mtd/mtd.h>
> #include <linux/mtd/nand.h>
> #include <linux/mtd/partitions.h>
> @@ -130,6 +131,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> if (!of_property_read_u32(pdev->dev.of_node,
> "chip-delay", &val))
> board->chip_delay = (u8)val;
> + board->ecc_mode = of_get_nand_ecc_mode(pdev->dev.of_node);
> } else
> board = pdev->dev.platform_data;
>
> @@ -140,7 +142,8 @@ static int __init orion_nand_probe(struct platform_device *pdev)
> nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
> nc->cmd_ctrl = orion_nand_cmd_ctrl;
> nc->read_buf = orion_nand_read_buf;
> - nc->ecc.mode = NAND_ECC_SOFT;
> + nc->ecc.mode = board->ecc_mode == NAND_ECC_SOFT_BCH ?
> + NAND_ECC_SOFT_BCH : NAND_ECC_SOFT;
Hi Stefan
What about a user that wants one of the other valid values?
NAND_ECC_OOB_FIRST, NAND_ECC_HW_SYNDROME, etc.
Would:
if (IS_ERR(board->ecc_mode)) {
nc->ecc.mode = NAND_ECC_SOFT;
dev_info(&pdev->dev, "Defaulting to NAND_ECC_SOFT");
} else
nc->ecc.mode = board->ecc_mode
be better?
Andrew
^ permalink raw reply
* [kvmarm] [PATCH v5 06/14] KVM: ARM: Inject IRQs and FIQs from userspace
From: Gleb Natapov @ 2013-01-15 12:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFEAcA9wEtXu6B-4bUuezntvybhu8MCYfciKhdLK_Cs--qP8_w@mail.gmail.com>
On Tue, Jan 15, 2013 at 12:15:01PM +0000, Peter Maydell wrote:
> On 15 January 2013 09:56, Gleb Natapov <gleb@redhat.com> wrote:
> > On Tue, Jan 08, 2013 at 01:39:17PM -0500, Christoffer Dall wrote:
> >> From: Christoffer Dall <cdall@cs.columbia.edu>
> >>
> >> All interrupt injection is now based on the VM ioctl KVM_IRQ_LINE. This
> >> works semantically well for the GIC as we in fact raise/lower a line on
> >> a machine component (the gic). The IOCTL uses the follwing struct.
> >>
> >> struct kvm_irq_level {
> >> union {
> >> __u32 irq; /* GSI */
> >> __s32 status; /* not used for KVM_IRQ_LEVEL */
> >> };
> >> __u32 level; /* 0 or 1 */
> >> };
> >>
> >> ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
> > CPU level interrupt should use KVM_INTERRUPT instead.
>
> No, that would be wrong. KVM_INTERRUPT is for interrupts which must be
> delivered synchronously to the CPU. KVM_IRQ_LINE is for interrupts which
> can be fed to the kernel asynchronously. It happens that on x86 "must be
> delivered synchronously" and "not going to in kernel irqchip" are the same, but
> this isn't true for other archs. For ARM all our interrupts can be fed
> to the kernel
> asynchronously, and so we use KVM_IRQ_LINE in all cases.
>
I do no quite understand what you mean by synchronously and
asynchronously. The difference between KVM_INTERRUPT and KVM_IRQ_LINE line
is that former is used when destination cpu is known to userspace later
is used when kernel code is involved in figuring out the destination. The
injections themselves are currently synchronous for both of them on x86
and ARM. i.e vcpu is kicked out from guest mode when interrupt need to
be injected into a guest and vcpu state is changed to inject interrupt
during next guest entry. In the near feature x86 will be able to inject
interrupt without kicking vcpu out from the guest mode does ARM plan to
do the same? For GIC interrupts or for IRQ/FIQ or for both?
> There was a big discussion thread about this on kvm and qemu-devel last
> July (and we cleaned up some of the QEMU code to not smoosh together
> all these different concepts under "do I have an irqchip or not?").
Do you have a pointer?
>
> >> (GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
> >> specific cpus. The irq field is interpreted like this:
> >>
> > Haven't read about GIC yet. Is PPI an interrupt that device can send
> > directly to a specific CPU? Can we model that with irq routing like we do
> > for MSI?
>
> There is no routing involved -- you are raising a specific signal
> line (which happens to result in prodding a particular CPU), that's all.
>
We call it "irq routing", but it is not really a router. It just a
configuration to let KVM know how specific lines are wired. We abuse it
for MSI injection. So instead of encoding destination into kvm_irq_level
you configure "irq routing" entry with this information and get back a
cookie. You provide the cookie in kvm_irq_level->irq to KVM_IRQ_LEVEL
ioctl. This way you are not limited to 8 bit of cpuid for instance. This
is not efficient if "irq routing" is very dynamic though.
--
Gleb.
^ permalink raw reply
* [RFC PATCH 2/7] ARM: OMAP: devices: create device for usb part of control module
From: Sergei Shtylyov @ 2013-01-15 12:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358239378-10030-3-git-send-email-kishon@ti.com>
Hello.
On 15-01-2013 12:42, Kishon Vijay Abraham I wrote:
> A seperate driver has been added to handle the usb part of control
> module. A device for the above driver is created here, using the register
> address information to be used by the driver for powering on the PHY and
> for writing to the mailbox.
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
> arch/arm/mach-omap2/devices.c | 50 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 50 insertions(+)
> diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
> index 5e304d0..a761faf4 100644
> --- a/arch/arm/mach-omap2/devices.c
> +++ b/arch/arm/mach-omap2/devices.c
[...]
> @@ -254,6 +255,54 @@ static inline void omap_init_camera(void)
> #endif
> }
>
> +#if (defined(CONFIG_OMAP_CONTROL_USB) || \
> + defined(CONFIG_OMAP_CONTROL_USB_MODULE))
() around || not needed, and you're indenting the second line too much.
> +static inline void __init omap_init_control_usb(void)
> +{
> + int ret = 0;
Initializer not needed.
> +
> + if (cpu_is_omap44xx()) {
> + ret = platform_device_register(&omap4_control_usb);
> + if (ret)
> + pr_err("Error registering omap_control_usb device: %d\n"
> + , ret);
Please leave the comma on the previous line.
WBR, Sergei
^ permalink raw reply
* [PATCH 00/26] AB8500 MFD overhaul
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
Hi Sam,
So, "what the hell is this?" I hear you cry. Well, my team and
I are in the mists of an delta upstreaming torrent. As I'm sure
you've heard, ST-Ericsson's kernel delta is getting pretty big
now. There have been some excellent, interesting changes and
one way or another we need to sync them with Mainline. There is
also a big push to update the internal kernel with Mainline
changes too.
There are ~125 patches in drivers/mfd (lucky you) which are
currently held as delta. I'm hoping to whittle them down a
little, but whichever way you look at it, it's a lot of code.
I'd really appreciate it if you'd allow a little leniency with
regards to this and subsequent patch-sets. Some of the earlier
patches introduce some small issues which are ironed out in
latter patches. Some issues will still exist and the end of the
push, but I have every intention of fixing those once everything
is in. Please feel free to make comments on any
issues that you see, but instead of fixing them up right away,
I'd rather make a list of them and address them at the end, if
they're still present.
Thanks in advance.
Kind regards,
Lee
drivers/mfd/ab8500-core.c | 12 +-
drivers/mfd/ab8500-debugfs.c | 1247 +++++++++++++++++++++++++++--
drivers/mfd/ab8500-gpadc.c | 90 ++-
drivers/mfd/ab8500-sysctrl.c | 93 +++
drivers/mfd/abx500-core.c | 16 +
drivers/misc/ab8500-pwm.c | 282 +++++++
include/linux/mfd/ab8500/pwmleds.h | 20 +
include/linux/mfd/abx500.h | 2 +
include/linux/mfd/abx500/ab8500-sysctrl.h | 5 +
include/linux/mfd/abx500/ab8500.h | 14 +
10 files changed, 1697 insertions(+), 84 deletions(-)
^ permalink raw reply
* [PATCH 01/26] mfd: ab8500-sysctrl: Provide a platform specific pm_power_off() call-back
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
The kernel allows us to specify a function call-back which will be
invoked when a system power-off request has been received. Here we
provide one which is to be used when shutting down AB8500 based
platforms.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/ab8500-sysctrl.c | 22 ++++++++++++++++++++++
include/linux/mfd/abx500/ab8500.h | 2 ++
2 files changed, 24 insertions(+)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index c28d4eb..799fb5e 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -7,12 +7,29 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/signal.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
static struct device *sysctrl_dev;
+void ab8500_power_off(void)
+{
+ sigset_t old;
+ sigset_t all;
+
+ sigfillset(&all);
+
+ if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_SWOFF |
+ AB8500_STW4500CTRL1_SWRESET4500N);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ }
+}
+
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -51,7 +68,12 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
{
+ struct ab8500_platform_data *plat;
+
sysctrl_dev = &pdev->dev;
+ plat = dev_get_platdata(pdev->dev.parent);
+ if (plat->pm_power_off)
+ pm_power_off = ab8500_power_off;
return 0;
}
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 1491044..96840c4 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -274,6 +274,7 @@ struct ab8500_codec_platform_data;
/**
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
+ * @pm_power_off: Should machine pm power off hook be registered or not
* @init: board-specific initialization after detection of ab8500
* @num_regulator_reg_init: number of regulator init registers
* @regulator_reg_init: regulator init registers
@@ -282,6 +283,7 @@ struct ab8500_codec_platform_data;
*/
struct ab8500_platform_data {
int irq_base;
+ bool pm_power_off;
void (*init) (struct ab8500 *);
int num_regulator_reg_init;
struct ab8500_regulator_reg_init *regulator_reg_init;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 02/26] mfd: ab8500-sysctrl: If a charger is present, reboot instead
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Jonas Aaberg <jonas.aberg@stericsson.com>
If a changer is attached on power off, reboot the system
into charging mode instead of powering it off.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Karl KOMIEROWSKI <karl.komierowski@stericsson.com>
---
drivers/mfd/ab8500-sysctrl.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 799fb5e..01b0669 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -8,7 +8,9 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/reboot.h>
#include <linux/signal.h>
+#include <linux/power_supply.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
@@ -19,6 +21,31 @@ void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
+ static char *pss[] = {"ab8500_ac", "ab8500_usb"};
+ int i;
+
+ /*
+ * If we have a charger connected and we're powering off,
+ * reboot into charge-only mode.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(pss); i++) {
+ union power_supply_propval val;
+ struct power_supply *psy;
+ int ret;
+
+ psy = power_supply_get_by_name(pss[i]);
+ if (!psy)
+ continue;
+ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+
+ if (!ret && val.intval) {
+ printk(KERN_INFO
+ "Charger \"%s\" is connected. Rebooting.\n",
+ pss[i]);
+ machine_restart(NULL);
+ }
+ }
sigfillset(&all);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 03/26] mfd: ab8500-sysctrl: Only reboot into charging mode if battery type is known
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Jonas Aaberg <jonas.aberg@stericsson.com>
When a charger is connected, we usually want AB8500 based systems to
reboot into charging-only mode. However, if the battery type cannot
be identified this would be futile, so we'll just shut the system
down instead.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Karl KOMIEROWSKI <karl.komierowski@stericsson.com>
---
drivers/mfd/ab8500-sysctrl.c | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 01b0669..26216e7 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -23,6 +23,10 @@ void ab8500_power_off(void)
sigset_t all;
static char *pss[] = {"ab8500_ac", "ab8500_usb"};
int i;
+ bool charger_present = false;
+ union power_supply_propval val;
+ struct power_supply *psy;
+ int ret;
/*
* If we have a charger connected and we're powering off,
@@ -30,23 +34,36 @@ void ab8500_power_off(void)
*/
for (i = 0; i < ARRAY_SIZE(pss); i++) {
- union power_supply_propval val;
- struct power_supply *psy;
- int ret;
-
psy = power_supply_get_by_name(pss[i]);
if (!psy)
continue;
+
ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
if (!ret && val.intval) {
+ charger_present = true;
+ break;
+ }
+ }
+
+ if (!charger_present)
+ goto shutdown;
+
+ /* Check if battery is known */
+ psy = power_supply_get_by_name("ab8500_btemp");
+ if (psy) {
+ ret = psy->get_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY,
+ &val);
+ if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
printk(KERN_INFO
- "Charger \"%s\" is connected. Rebooting.\n",
+ "Charger \"%s\" is connected with known battery."
+ " Rebooting.\n",
pss[i]);
machine_restart(NULL);
}
}
+shutdown:
sigfillset(&all);
if (!sigprocmask(SIG_BLOCK, &all, &old)) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 04/26] mfd: ab8500-sysctrl.c: Provide charging as reset reason
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Jonas Aaberg <jonas.aberg@stericsson.com>
It's possible to supply a string to provide a reason for
triggering a restart. In this case our reason is to enter
charging-only mode, as a charger was found to be present.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Karl KOMIEROWSKI <karl.komierowski@stericsson.com>
---
drivers/mfd/ab8500-sysctrl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 26216e7..cf58f69 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -59,7 +59,7 @@ void ab8500_power_off(void)
"Charger \"%s\" is connected with known battery."
" Rebooting.\n",
pss[i]);
- machine_restart(NULL);
+ machine_restart("charging");
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 05/26] mfd: ab8500-gpadc: Change to mdelay for greater resolution
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Jonas Aaberg <jonas.aberg@stericsson.com>
The resolution of msleep is related to HZ, so with HZ set to
100 any msleep of less than 10ms will become ~10ms.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Bibek BASU <bibek.basu@stericsson.com>
Tested-by: Bibek BASU <bibek.basu@stericsson.com>
---
drivers/mfd/ab8500-gpadc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 29d72a2..3883b93 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -344,7 +344,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
* Delay might be needed for ABB8500 cut 3.0, if not, remove
* when hardware will be available
*/
- msleep(1);
+ mdelay(1);
break;
}
/* Intentional fallthrough */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 06/26] mfd: ab8500-sysctrl: Provide configuration for SysClkReqRfClkBuf registers
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Kennet Wallden <kennet.wallden@stericsson.com>
Add the possibility to pass configuration settings for
SysCl1kReqRfClkBuf to SysClk8ReqRfClkBuf via platform data.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Kennet Wallden <kennet.wallden@stericsson.com>
Reviewed-by: Karl-Johan PERNTZ <karl-johan.perntz@stericsson.com>
Reviewed-by: Bengt JONSSON <bengt.g.jonsson@stericsson.com>
---
drivers/mfd/ab8500-sysctrl.c | 25 +++++++++++++++++++++++++
include/linux/mfd/abx500/ab8500-sysctrl.h | 5 +++++
include/linux/mfd/abx500/ab8500.h | 2 ++
3 files changed, 32 insertions(+)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index cf58f69..19a024e 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -113,11 +113,36 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
{
struct ab8500_platform_data *plat;
+ struct ab8500_sysctrl_platform_data *pdata;
sysctrl_dev = &pdev->dev;
plat = dev_get_platdata(pdev->dev.parent);
if (plat->pm_power_off)
pm_power_off = ab8500_power_off;
+
+ pdata = plat->sysctrl;
+
+ if (pdata) {
+ int ret;
+ int i;
+ int j;
+ for (i = AB8500_SYSCLKREQ1RFCLKBUF;
+ i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
+ j = i - AB8500_SYSCLKREQ1RFCLKBUF;
+ ret = ab8500_sysctrl_write(i, 0xff,
+ pdata->initial_req_buf_config[j]);
+ dev_dbg(&pdev->dev,
+ "Setting SysClkReq%dRfClkBuf 0x%X\n",
+ j + 1,
+ pdata->initial_req_buf_config[j]);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "unable to set sysClkReq%dRfClkBuf: "
+ "%d\n", j + 1, ret);
+ }
+ }
+ }
+
return 0;
}
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
index 10eb509..ebf12e7 100644
--- a/include/linux/mfd/abx500/ab8500-sysctrl.h
+++ b/include/linux/mfd/abx500/ab8500-sysctrl.h
@@ -37,6 +37,11 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
return ab8500_sysctrl_write(reg, bits, 0);
}
+/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
+struct ab8500_sysctrl_platform_data {
+ u8 initial_req_buf_config[8];
+};
+
/* Registers */
#define AB8500_TURNONSTATUS 0x100
#define AB8500_RESETSTATUS 0x101
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 96840c4..3f4e6d1 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -270,6 +270,7 @@ struct regulator_reg_init;
struct regulator_init_data;
struct ab8500_gpio_platform_data;
struct ab8500_codec_platform_data;
+struct ab8500_sysctrl_platform_data;
/**
* struct ab8500_platform_data - AB8500 platform data
@@ -291,6 +292,7 @@ struct ab8500_platform_data {
struct regulator_init_data *regulator;
struct ab8500_gpio_platform_data *gpio;
struct ab8500_codec_platform_data *codec;
+ struct ab8500_sysctrl_platform_data *sysctrl;
};
extern int __devinit ab8500_init(struct ab8500 *ab8500,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 07/26] mfd: ab8500-sysctrl: export read/write symbols
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Jonas Aaberg <jonas.aberg@stericsson.com>
Export ab8500_sysctrl_read() and ab8500_sysctrl_write() symobols.
They will be used by LTP test cases.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Bengt JONSSON <bengt.g.jonsson@stericsson.com>
---
drivers/mfd/ab8500-sysctrl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 19a024e..5a61e94 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -94,6 +94,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
return abx500_get_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), value);
}
+EXPORT_SYMBOL(ab8500_sysctrl_read);
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
{
@@ -109,6 +110,7 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
(u8)(reg & 0xFF), mask, value);
}
+EXPORT_SYMBOL(ab8500_sysctrl_write);
static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
{
--
1.7.9.5
^ permalink raw reply related
* [PATCH 08/26] mfd: abx500-core: Provide an API to dump all ABx500 registers
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Some drivers can detect subsystem failures e.g. shared memory driver
can detect modem sub system failures. It would be helpful in analyzing
these failures if AB register dump is available at that point. This
patch adds the API for the drivers to dump AB registers in the kernel
log.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
drivers/mfd/abx500-core.c | 16 ++++++++++++++++
include/linux/mfd/abx500.h | 2 ++
2 files changed, 18 insertions(+)
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index 7ce65f4..9818afb 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -153,6 +153,22 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
}
EXPORT_SYMBOL(abx500_startup_irq_enabled);
+void abx500_dump_all_banks(void)
+{
+ struct abx500_ops *ops;
+ struct device dummy_child = {0};
+ struct abx500_device_entry *dev_entry;
+
+ list_for_each_entry(dev_entry, &abx500_list, list) {
+ dummy_child.parent = dev_entry->dev;
+ ops = &dev_entry->ops;
+
+ if ((ops != NULL) && (ops->dump_all_banks != NULL))
+ ops->dump_all_banks(&dummy_child);
+ }
+}
+EXPORT_SYMBOL(abx500_dump_all_banks);
+
MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
MODULE_DESCRIPTION("ABX500 core driver");
MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 5d5298d..2667af4 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -326,6 +326,7 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
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);
+void abx500_dump_all_banks(void);
struct abx500_ops {
int (*get_chip_id) (struct device *);
@@ -336,6 +337,7 @@ struct abx500_ops {
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);
+ void (*dump_all_banks) (struct device *);
};
int abx500_register_ops(struct device *core_dev, struct abx500_ops *ops);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 09/26] mfd: ab8500-debugfs: Provide a means for a user subscribe to IRQs
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
Allow users to subscribe to and view IRQ events live from debugfs.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/ab8500-debugfs.c | 197 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 197 insertions(+)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index c4cb806..71df8e4 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -11,6 +11,9 @@
#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>
@@ -18,6 +21,9 @@
static u32 debug_bank;
static u32 debug_address;
+static int irq_first;
+static int irq_last;
+
/**
* struct ab8500_reg_range
* @first: the first address of the range
@@ -354,6 +360,21 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
};
+static irqreturn_t ab8500_debug_handler(int irq, void *data)
+{
+ char buf[16];
+ struct kobject *kobj = (struct kobject *)data;
+
+ /*
+ * This makes it possible to use poll for events (POLLPRI | POLLERR)
+ * from userspace on sysfs file named irq-<nr>
+ */
+ sprintf(buf, "irq-%d", irq);
+ sysfs_notify(kobj, NULL, buf);
+
+ return IRQ_HANDLED;
+}
+
static int ab8500_registers_print(struct seq_file *s, void *p)
{
struct device *dev = s->private;
@@ -519,6 +540,130 @@ static ssize_t ab8500_val_write(struct file *file,
return count;
}
+static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
+{
+ seq_printf(s, "%d\n", irq_first);
+
+ return 0;
+}
+
+static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_subscribe_unsubscribe_print,
+ inode->i_private);
+}
+
+/*
+ * This function is used for all interrupts and will always print
+ * the same string. It is however this file sysfs_notify called on.
+ * Userspace should read this file and then poll. When an event occur
+ * the blocking poll will be released.
+ */
+static ssize_t show_irq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "irq\n");
+}
+
+static struct device_attribute *dev_attr[AB8500_NR_IRQS];
+static char *event_name[AB8500_NR_IRQS];
+
+static ssize_t ab8500_subscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ 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_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ /*
+ * This will create a sysfs file named irq-<nr> which userspace can
+ * use to select or poll and get the AB8500 events
+ */
+ dev_attr[user_val] = kmalloc(sizeof(struct device_attribute),
+ GFP_KERNEL);
+ event_name[user_val] = kmalloc(buf_size, GFP_KERNEL);
+ sprintf(event_name[user_val], "irq-%lu", user_val);
+ dev_attr[user_val]->show = show_irq;
+ dev_attr[user_val]->store = NULL;
+ dev_attr[user_val]->attr.name = event_name[user_val];
+ dev_attr[user_val]->attr.mode = S_IRUGO;
+ err = sysfs_create_file(&dev->kobj, &dev_attr[user_val]->attr);
+ if (err < 0) {
+ printk(KERN_ERR "sysfs_create_file failed %d\n", err);
+ return err;
+ }
+
+ err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
+ 0, "ab8500-debug", &dev->kobj);
+ if (err < 0) {
+ printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
+ err, user_val);
+ return err;
+ }
+
+ return buf_size;
+}
+
+static ssize_t ab8500_unsubscribe_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ 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_val);
+ if (err)
+ return -EINVAL;
+ if (user_val < irq_first) {
+ dev_err(dev, "debugfs error input < %d\n", irq_first);
+ return -EINVAL;
+ }
+ if (user_val > irq_last) {
+ dev_err(dev, "debugfs error input > %d\n", irq_last);
+ return -EINVAL;
+ }
+
+ free_irq(user_val, &dev->kobj);
+ kfree(event_name[user_val]);
+ kfree(dev_attr[user_val]);
+
+ if (dev_attr[user_val])
+ sysfs_remove_file(&dev->kobj, &dev_attr[user_val]->attr);
+
+ return buf_size;
+}
+
static const struct file_operations ab8500_bank_fops = {
.open = ab8500_bank_open,
.write = ab8500_bank_write,
@@ -546,17 +691,51 @@ static const struct file_operations ab8500_val_fops = {
.owner = THIS_MODULE,
};
+static const struct file_operations ab8500_subscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_subscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations ab8500_unsubscribe_fops = {
+ .open = ab8500_subscribe_unsubscribe_open,
+ .write = ab8500_unsubscribe_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static struct dentry *ab8500_dir;
static struct dentry *ab8500_reg_file;
static struct dentry *ab8500_bank_file;
static struct dentry *ab8500_address_file;
static struct dentry *ab8500_val_file;
+static struct dentry *ab8500_subscribe_file;
+static struct dentry *ab8500_unsubscribe_file;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
debug_bank = AB8500_MISC;
debug_address = AB8500_REV_REG & 0x00FF;
+ irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
+ if (irq_first < 0) {
+ dev_err(&plf->dev, "First irq not found, err %d\n",
+ irq_first);
+ return irq_first;
+ }
+
+ irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
+ if (irq_last < 0) {
+ dev_err(&plf->dev, "Last irq not found, err %d\n",
+ irq_last);
+ return irq_last;
+ }
+
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
if (!ab8500_dir)
goto exit_no_debugfs;
@@ -582,8 +761,26 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
if (!ab8500_val_file)
goto exit_destroy_address;
+ ab8500_subscribe_file =
+ debugfs_create_file("irq-subscribe",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_subscribe_fops);
+ if (!ab8500_subscribe_file)
+ goto exit_destroy_val;
+
+ ab8500_unsubscribe_file =
+ debugfs_create_file("irq-unsubscribe",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_unsubscribe_fops);
+ if (!ab8500_unsubscribe_file)
+ goto exit_destroy_subscribe;
+
return 0;
+exit_destroy_subscribe:
+ debugfs_remove(ab8500_subscribe_file);
+exit_destroy_val:
+ debugfs_remove(ab8500_val_file);
exit_destroy_address:
debugfs_remove(ab8500_address_file);
exit_destroy_bank:
--
1.7.9.5
^ permalink raw reply related
* [PATCH 10/26] mfd: ab8500-debugfs: Wake-up device on debugfs IRQ
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
Ensure the device wakes up if the debugfs IRQ fires if we're
in suspend mode.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/ab8500-debugfs.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 71df8e4..b3ddc23 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -616,7 +616,8 @@ static ssize_t ab8500_subscribe_write(struct file *file,
}
err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
- 0, "ab8500-debug", &dev->kobj);
+ IRQF_SHARED | IRQF_NO_SUSPEND,
+ "ab8500-debug", &dev->kobj);
if (err < 0) {
printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
err, user_val);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 11/26] mfd: ab8500-debugfs: Keep count of IRQs in debugfs
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Mattias Wallin <mattias.wallin@stericsson.com>
This patch adds a counter to the sysfs file dynamically created
by debugfs. It also fixes an array index error.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Reviewed-by: Mattias NILSSON <mattias.i.nilsson@stericsson.com>
---
drivers/mfd/ab8500-debugfs.c | 77 +++++++++++++++++++++++++++++-------------
1 file changed, 53 insertions(+), 24 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index b3ddc23..03eacf1 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -23,6 +23,10 @@ static u32 debug_address;
static int irq_first;
static int irq_last;
+static u32 irq_count[AB8500_NR_IRQS];
+
+static struct device_attribute *dev_attr[AB8500_NR_IRQS];
+static char *event_name[AB8500_NR_IRQS];
/**
* struct ab8500_reg_range
@@ -364,12 +368,15 @@ static irqreturn_t ab8500_debug_handler(int irq, void *data)
{
char buf[16];
struct kobject *kobj = (struct kobject *)data;
+ unsigned int irq_abb = irq - irq_first;
+ if (irq_abb < AB8500_NR_IRQS)
+ irq_count[irq_abb]++;
/*
* This makes it possible to use poll for events (POLLPRI | POLLERR)
- * from userspace on sysfs file named irq-<nr>
+ * from userspace on sysfs file named <irq-nr>
*/
- sprintf(buf, "irq-%d", irq);
+ sprintf(buf, "%d", irq);
sysfs_notify(kobj, NULL, buf);
return IRQ_HANDLED;
@@ -555,19 +562,26 @@ static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
}
/*
- * This function is used for all interrupts and will always print
- * the same string. It is however this file sysfs_notify called on.
- * Userspace should read this file and then poll. When an event occur
+ * Userspace should use poll() on this file. When an event occur
* the blocking poll will be released.
*/
static ssize_t show_irq(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "irq\n");
-}
+ unsigned long name;
+ unsigned int irq_index;
+ int err;
-static struct device_attribute *dev_attr[AB8500_NR_IRQS];
-static char *event_name[AB8500_NR_IRQS];
+ err = strict_strtoul(attr->attr.name, 0, &name);
+ if (err)
+ return err;
+
+ irq_index = name - irq_first;
+ if (irq_index >= AB8500_NR_IRQS)
+ return -EINVAL;
+ else
+ return sprintf(buf, "%u\n", irq_count[irq_index]);
+}
static ssize_t ab8500_subscribe_write(struct file *file,
const char __user *user_buf,
@@ -578,6 +592,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
int buf_size;
unsigned long user_val;
int err;
+ unsigned int irq_index;
/* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf)-1));
@@ -597,19 +612,23 @@ static ssize_t ab8500_subscribe_write(struct file *file,
return -EINVAL;
}
+ irq_index = user_val - irq_first;
+ if (irq_index >= AB8500_NR_IRQS)
+ return -EINVAL;
+
/*
- * This will create a sysfs file named irq-<nr> which userspace can
+ * This will create a sysfs file named <irq-nr> which userspace can
* use to select or poll and get the AB8500 events
*/
- dev_attr[user_val] = kmalloc(sizeof(struct device_attribute),
- GFP_KERNEL);
- event_name[user_val] = kmalloc(buf_size, GFP_KERNEL);
- sprintf(event_name[user_val], "irq-%lu", user_val);
- dev_attr[user_val]->show = show_irq;
- dev_attr[user_val]->store = NULL;
- dev_attr[user_val]->attr.name = event_name[user_val];
- dev_attr[user_val]->attr.mode = S_IRUGO;
- err = sysfs_create_file(&dev->kobj, &dev_attr[user_val]->attr);
+ dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
+ GFP_KERNEL);
+ event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
+ sprintf(event_name[irq_index], "%lu", user_val);
+ dev_attr[irq_index]->show = show_irq;
+ dev_attr[irq_index]->store = NULL;
+ dev_attr[irq_index]->attr.name = event_name[irq_index];
+ dev_attr[irq_index]->attr.mode = S_IRUGO;
+ err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
if (err < 0) {
printk(KERN_ERR "sysfs_create_file failed %d\n", err);
return err;
@@ -621,6 +640,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
if (err < 0) {
printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
err, user_val);
+ sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
return err;
}
@@ -636,6 +656,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
int buf_size;
unsigned long user_val;
int err;
+ unsigned int irq_index;
/* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf)-1));
@@ -655,12 +676,20 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
return -EINVAL;
}
- free_irq(user_val, &dev->kobj);
- kfree(event_name[user_val]);
- kfree(dev_attr[user_val]);
+ irq_index = user_val - irq_first;
+ if (irq_index >= AB8500_NR_IRQS)
+ return -EINVAL;
+
+ /* Set irq count to 0 when unsubscribe */
+ irq_count[irq_index] = 0;
+
+ if (dev_attr[irq_index])
+ sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
- if (dev_attr[user_val])
- sysfs_remove_file(&dev->kobj, &dev_attr[user_val]->attr);
+
+ free_irq(user_val, &dev->kobj);
+ kfree(event_name[irq_index]);
+ kfree(dev_attr[irq_index]);
return buf_size;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 12/26] mfd: ab8500-debugfs: Use NULL to initialise remaining NULL pointer
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
Partly for coding style reasons, but mostly because sparse warns on it.
This patch is a completion of a previous patch my Mark Brown.
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/ab8500-debugfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 03eacf1..4f36907 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -60,7 +60,7 @@ struct ab8500_prcmu_ranges {
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,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 13/26] mfd: ab8500-debugfs: Formated access AB8500 registers from debugfs entry
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: carriere etienne <etienne.carriere@stericsson.com>
Add debugfs entry ab8500/hwreg to read/write bit-field in AB8500 registers.
Check the debugfs entries usage from heading comments in ab8500-debugfs.c
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: carriere etienne <etienne.carriere@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
drivers/mfd/ab8500-debugfs.c | 388 ++++++++++++++++++++++++++++++++++++------
1 file changed, 336 insertions(+), 52 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 4f36907..78a8e0c 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>
@@ -18,6 +84,11 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/string.h>
+#include <linux/ctype.h>
+#endif
+
static u32 debug_bank;
static u32 debug_address;
@@ -52,6 +123,25 @@ 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
@@ -547,6 +637,203 @@ static ssize_t ab8500_val_write(struct file *file,
return count;
}
+/*
+ * - HWREG DB8500 formated routines
+ */
+static int ab8500_hwreg_print(struct seq_file *s, void *d)
+{
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, ®value);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+
+ if (hwreg_cfg.shift >= 0)
+ regvalue >>= hwreg_cfg.shift;
+ else
+ regvalue <<= -hwreg_cfg.shift;
+ regvalue &= hwreg_cfg.mask;
+
+ if (REG_FMT_DEC(&hwreg_cfg))
+ seq_printf(s, "%d\n", regvalue);
+ else
+ seq_printf(s, "0x%02X\n", regvalue);
+ return 0;
+}
+
+static int ab8500_hwreg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_hwreg_print, inode->i_private);
+}
+
+/*
+ * return length of an ASCII numerical value, 0 is string is not a
+ * numerical value.
+ * string shall start at value 1st char.
+ * string can be tailed with \0 or space or newline chars only.
+ * value can be decimal or hexadecimal (prefixed 0x or 0X).
+ */
+static int strval_len(char *b)
+{
+ char *s = b;
+ if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
+ s += 2;
+ for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+ if (!isxdigit(*s))
+ return 0;
+ }
+ } else {
+ if (*s == '-')
+ s++;
+ for (; *s && (*s != ' ') && (*s != '\n'); s++) {
+ if (!isdigit(*s))
+ return 0;
+ }
+ }
+ return (int) (s-b);
+}
+
+/*
+ * parse hwreg input data.
+ * update global hwreg_cfg only if input data syntax is ok.
+ */
+static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
+ struct device *dev)
+{
+ uint write, val = 0;
+ struct hwreg_cfg loc = {
+ .bank = 0, /* default: invalid phys addr */
+ .addr = 0, /* default: invalid phys addr */
+ .fmt = 0, /* default: 32bit access, hex output */
+ .mask = 0xFFFFFFFF, /* default: no mask */
+ .shift = 0, /* default: no bit shift */
+ };
+
+ /* read or write ? */
+ if (!strncmp(b, "read ", 5)) {
+ write = 0;
+ b += 5;
+ } else if (!strncmp(b, "write ", 6)) {
+ write = 1;
+ b += 6;
+ } else
+ return -EINVAL;
+
+ /* OPTIONS -l|-w|-b -s -m -o */
+ while ((*b == ' ') || (*b == '-')) {
+ if (*(b-1) != ' ') {
+ b++;
+ continue;
+ }
+ if ((!strncmp(b, "-d ", 3)) ||
+ (!strncmp(b, "-dec ", 5))) {
+ b += (*(b+2) == ' ') ? 3 : 5;
+ loc.fmt |= (1<<0);
+ } else if ((!strncmp(b, "-h ", 3)) ||
+ (!strncmp(b, "-hex ", 5))) {
+ b += (*(b+2) == ' ') ? 3 : 5;
+ loc.fmt &= ~(1<<0);
+ } else if ((!strncmp(b, "-m ", 3)) ||
+ (!strncmp(b, "-mask ", 6))) {
+ b += (*(b+2) == ' ') ? 3 : 6;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.mask = simple_strtoul(b, &b, 0);
+ } else if ((!strncmp(b, "-s ", 3)) ||
+ (!strncmp(b, "-shift ", 7))) {
+ b += (*(b+2) == ' ') ? 3 : 7;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.shift = simple_strtol(b, &b, 0);
+ } else {
+ return -EINVAL;
+ }
+ }
+ /* get arg BANK and ADDRESS */
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.bank = simple_strtoul(b, &b, 0);
+ while (*b == ' ')
+ b++;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ loc.addr = simple_strtoul(b, &b, 0);
+
+ if (write) {
+ while (*b == ' ')
+ b++;
+ if (strval_len(b) == 0)
+ return -EINVAL;
+ val = simple_strtoul(b, &b, 0);
+ }
+
+ /* args are ok, update target cfg (mainly for read) */
+ *cfg = loc;
+
+#if ABB_HWREG_DEBUG
+ pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d
+ value=0x%X\n", (write) ? "write" : "read",
+ REG_FMT_DEC(cfg) ? "decimal" : "hexa",
+ cfg->addr, cfg->mask, cfg->shift, val);
+#endif
+
+ if (write) {
+ u8 regvalue;
+ int ret = abx500_get_register_interruptible(dev,
+ (u8)cfg->bank, (u8)cfg->addr, ®value);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+
+ if (cfg->shift >= 0) {
+ regvalue &= ~(cfg->mask << (cfg->shift));
+ val = (val & cfg->mask) << (cfg->shift);
+ } else {
+ regvalue &= ~(cfg->mask >> (-cfg->shift));
+ val = (val & cfg->mask) >> (-cfg->shift);
+ }
+ val = val | regvalue;
+
+ ret = abx500_set_register_interruptible(dev,
+ (u8)cfg->bank, (u8)cfg->addr, (u8)val);
+ if (ret < 0) {
+ pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
+ return -EINVAL;
+ }
+
+ }
+ return 0;
+}
+
+static ssize_t ab8500_hwreg_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[128];
+ int buf_size, ret;
+
+ /* 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;
+
+ /* get args and process */
+ ret = hwreg_common_write(buf, &hwreg_cfg, dev);
+ return (ret) ? ret : buf_size;
+}
+
+/*
+ * - irq subscribe/unsubscribe stuff
+ */
static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
{
seq_printf(s, "%d\n", irq_first);
@@ -694,6 +981,10 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
return buf_size;
}
+/*
+ * - several deubgfs nodes fops
+ */
+
static const struct file_operations ab8500_bank_fops = {
.open = ab8500_bank_open,
.write = ab8500_bank_write,
@@ -739,16 +1030,20 @@ static const struct file_operations ab8500_unsubscribe_fops = {
.owner = THIS_MODULE,
};
+static const struct file_operations ab8500_hwreg_fops = {
+ .open = ab8500_hwreg_open,
+ .write = ab8500_hwreg_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static struct dentry *ab8500_dir;
-static struct dentry *ab8500_reg_file;
-static struct dentry *ab8500_bank_file;
-static struct dentry *ab8500_address_file;
-static struct dentry *ab8500_val_file;
-static struct dentry *ab8500_subscribe_file;
-static struct dentry *ab8500_unsubscribe_file;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
+ struct dentry *file;
debug_bank = AB8500_MISC;
debug_address = AB8500_REV_REG & 0x00FF;
@@ -768,70 +1063,59 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
if (!ab8500_dir)
- goto exit_no_debugfs;
+ goto err;
- ab8500_reg_file = debugfs_create_file("all-bank-registers",
+ file = debugfs_create_file("all-bank-registers",
S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
- if (!ab8500_reg_file)
- goto exit_destroy_dir;
+ if (!file)
+ goto err;
- ab8500_bank_file = debugfs_create_file("register-bank",
+ file = debugfs_create_file("register-bank",
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
- if (!ab8500_bank_file)
- goto exit_destroy_reg;
+ if (!file)
+ goto err;
- ab8500_address_file = debugfs_create_file("register-address",
+ file = debugfs_create_file("register-address",
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
&ab8500_address_fops);
- if (!ab8500_address_file)
- goto exit_destroy_bank;
+ if (!file)
+ goto err;
- ab8500_val_file = debugfs_create_file("register-value",
+ file = debugfs_create_file("register-value",
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
- if (!ab8500_val_file)
- goto exit_destroy_address;
-
- ab8500_subscribe_file =
- debugfs_create_file("irq-subscribe",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
- &ab8500_subscribe_fops);
- if (!ab8500_subscribe_file)
- goto exit_destroy_val;
-
- ab8500_unsubscribe_file =
- debugfs_create_file("irq-unsubscribe",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
- &ab8500_unsubscribe_fops);
- if (!ab8500_unsubscribe_file)
- goto exit_destroy_subscribe;
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("irq-subscribe",
+ (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
+ &ab8500_subscribe_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("irq-unsubscribe",
+ (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
+ &ab8500_unsubscribe_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("hwreg",
+ (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
+ &ab8500_hwreg_fops);
+ if (!file)
+ goto err;
return 0;
-exit_destroy_subscribe:
- debugfs_remove(ab8500_subscribe_file);
-exit_destroy_val:
- debugfs_remove(ab8500_val_file);
-exit_destroy_address:
- debugfs_remove(ab8500_address_file);
-exit_destroy_bank:
- debugfs_remove(ab8500_bank_file);
-exit_destroy_reg:
- debugfs_remove(ab8500_reg_file);
-exit_destroy_dir:
- debugfs_remove(ab8500_dir);
-exit_no_debugfs:
+err:
+ if (ab8500_dir)
+ debugfs_remove_recursive(ab8500_dir);
dev_err(&plf->dev, "failed to create debugfs entries.\n");
return -ENOMEM;
}
static int __devexit ab8500_debug_remove(struct platform_device *plf)
{
- debugfs_remove(ab8500_val_file);
- debugfs_remove(ab8500_address_file);
- debugfs_remove(ab8500_bank_file);
- debugfs_remove(ab8500_reg_file);
- debugfs_remove(ab8500_dir);
-
+ debugfs_remove_recursive(ab8500_dir);
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 14/26] mfd: ab8500-debugfs: Fix introduced compiler time warnings
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Philippe Langlais <philippe.langlais@stericsson.com>
Some simple fixes regarding pre-processor usage.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Philippe Langlais <philippe.langlais@linaro.org>
---
drivers/mfd/ab8500-debugfs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 78a8e0c..7698d30 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -776,9 +776,9 @@ static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
/* args are ok, update target cfg (mainly for read) */
*cfg = loc;
-#if ABB_HWREG_DEBUG
- pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d
- value=0x%X\n", (write) ? "write" : "read",
+#ifdef ABB_HWREG_DEBUG
+ pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
+ "value=0x%X\n", (write) ? "write" : "read",
REG_FMT_DEC(cfg) ? "decimal" : "hexa",
cfg->addr, cfg->mask, cfg->shift, val);
#endif
--
1.7.9.5
^ permalink raw reply related
* [PATCH 15/26] mfd: ab8500-debugfs: Export all AB8500 ADCs as debugfs nodes
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: John Beckett <john.beckett@stericsson.com>
Allow a user to take a glimpse into the inner workings of the
AB8500 Analogue-to-Digital Converters, via debugfs.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: John Beckett <john.beckett@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
drivers/mfd/ab8500-debugfs.c | 486 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 465 insertions(+), 21 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 7698d30..aedbcb0 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -82,7 +82,7 @@
#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>
@@ -143,6 +143,7 @@ static struct hwreg_cfg hwreg_cfg = {
};
#define AB8500_NAME_STRING "ab8500"
+#define AB8500_ADC_NAME_STRING "gpadc"
#define AB8500_NUM_BANKS 22
#define AB8500_REV_REG 0x80
@@ -672,6 +673,382 @@ static int ab8500_hwreg_open(struct inode *inode, struct file *file)
return single_open(file, ab8500_hwreg_print, inode->i_private);
}
+static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
+{
+ int bat_ctrl_raw;
+ int bat_ctrl_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
+ bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ BAT_CTRL, bat_ctrl_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ bat_ctrl_convert, bat_ctrl_raw);
+}
+
+static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_bat_ctrl_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bat_ctrl_fops = {
+ .open = ab8500_gpadc_bat_ctrl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
+{
+ int btemp_ball_raw;
+ int btemp_ball_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
+ btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
+ btemp_ball_raw);
+
+ return seq_printf(s,
+ "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
+}
+
+static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_btemp_ball_fops = {
+ .open = ab8500_gpadc_btemp_ball_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
+{
+ int main_charger_v_raw;
+ int main_charger_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
+ main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ MAIN_CHARGER_V, main_charger_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_charger_v_convert, main_charger_v_raw);
+}
+
+static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_charger_v_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
+ .open = ab8500_gpadc_main_charger_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
+{
+ int acc_detect1_raw;
+ int acc_detect1_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
+ acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
+ acc_detect1_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ acc_detect1_convert, acc_detect1_raw);
+}
+
+static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_acc_detect1_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
+ .open = ab8500_gpadc_acc_detect1_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
+{
+ int acc_detect2_raw;
+ int acc_detect2_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
+ acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ ACC_DETECT2, acc_detect2_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ acc_detect2_convert, acc_detect2_raw);
+}
+
+static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_acc_detect2_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
+ .open = ab8500_gpadc_acc_detect2_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
+{
+ int aux1_raw;
+ int aux1_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
+ aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
+ aux1_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ aux1_convert, aux1_raw);
+}
+
+static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_aux1_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux1_fops = {
+ .open = ab8500_gpadc_aux1_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
+{
+ int aux2_raw;
+ int aux2_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
+ aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
+ aux2_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ aux2_convert, aux2_raw);
+}
+
+static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_aux2_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_aux2_fops = {
+ .open = ab8500_gpadc_aux2_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
+{
+ int main_bat_v_raw;
+ int main_bat_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
+ main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
+ main_bat_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_bat_v_convert, main_bat_v_raw);
+}
+
+static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_bat_v_fops = {
+ .open = ab8500_gpadc_main_bat_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
+{
+ int vbus_v_raw;
+ int vbus_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
+ vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
+ vbus_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ vbus_v_convert, vbus_v_raw);
+}
+
+static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_vbus_v_fops = {
+ .open = ab8500_gpadc_vbus_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
+{
+ int main_charger_c_raw;
+ int main_charger_c_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
+ main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ MAIN_CHARGER_C, main_charger_c_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ main_charger_c_convert, main_charger_c_raw);
+}
+
+static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_main_charger_c_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
+ .open = ab8500_gpadc_main_charger_c_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
+{
+ int usb_charger_c_raw;
+ int usb_charger_c_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
+ usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ USB_CHARGER_C, usb_charger_c_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ usb_charger_c_convert, usb_charger_c_raw);
+}
+
+static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8500_gpadc_usb_charger_c_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
+ .open = ab8500_gpadc_usb_charger_c_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
+{
+ int bk_bat_v_raw;
+ int bk_bat_v_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
+ bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ BK_BAT_V, bk_bat_v_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ bk_bat_v_convert, bk_bat_v_raw);
+}
+
+static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_bk_bat_v_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_bk_bat_v_fops = {
+ .open = ab8500_gpadc_bk_bat_v_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
+{
+ int die_temp_raw;
+ int die_temp_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get();
+ die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
+ die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
+ die_temp_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ die_temp_convert, die_temp_raw);
+}
+
+static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_die_temp_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_die_temp_fops = {
+ .open = ab8500_gpadc_die_temp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
/*
* return length of an ASCII numerical value, 0 is string is not a
* numerical value.
@@ -1040,6 +1417,7 @@ static const struct file_operations ab8500_hwreg_fops = {
};
static struct dentry *ab8500_dir;
+static struct dentry *ab8500_gpadc_dir;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
@@ -1050,14 +1428,14 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
if (irq_first < 0) {
dev_err(&plf->dev, "First irq not found, err %d\n",
- irq_first);
+ irq_first);
return irq_first;
}
irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
if (irq_last < 0) {
dev_err(&plf->dev, "Last irq not found, err %d\n",
- irq_last);
+ irq_last);
return irq_last;
}
@@ -1065,42 +1443,108 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
if (!ab8500_dir)
goto err;
- file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
+ ab8500_dir);
+ if (!ab8500_gpadc_dir)
+ goto err;
+
+ file = debugfs_create_file("all-bank-registers", S_IRUGO,
+ ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_address_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
+ ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
- &ab8500_address_fops);
+ file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
+ file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
if (!file)
goto err;
- file = debugfs_create_file("irq-subscribe",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
- &ab8500_subscribe_fops);
+ file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
if (!file)
goto err;
- file = debugfs_create_file("irq-unsubscribe",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
- &ab8500_unsubscribe_fops);
+ file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
if (!file)
goto err;
- file = debugfs_create_file("hwreg",
- (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
- &ab8500_hwreg_fops);
+ file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
if (!file)
goto err;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 16/26] mfd: ab8500-debugfs: Set the USB charging current to 300mA for ABV3
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Philippe Langlais <philippe.langlais@stericsson.com>
In case of AB-V3, the eye diagram related issues are resolved.
So, set the device charging current to 300mA when connected to
standard host. Also, add the USB PHY tuning values to improve
the USB eye diagram
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: <thirupathi.chippakurthy@stericsson.com>
---
drivers/mfd/ab8500-debugfs.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index aedbcb0..a231faf 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -144,7 +144,7 @@ static struct hwreg_cfg hwreg_cfg = {
#define AB8500_NAME_STRING "ab8500"
#define AB8500_ADC_NAME_STRING "gpadc"
-#define AB8500_NUM_BANKS 22
+#define AB8500_NUM_BANKS 24
#define AB8500_REV_REG 0x80
@@ -316,7 +316,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,
@@ -350,6 +350,10 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
.first = 0xC0,
.last = 0xC2,
},
+ {
+ .first = 0xf5,
+ .last = 0xf6,
+ },
},
},
[AB8500_GAS_GAUGE] = {
@@ -369,6 +373,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[]) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 17/26] mfd: ab8500-debugfs: add debugfs node to read all registers
From: Lee Jones @ 2013-01-15 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1358254566-12419-1-git-send-email-lee.jones@linaro.org>
From: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Update the ab8500_registers_print() to reuse it from multiple places.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
drivers/mfd/ab8500-debugfs.c | 95 +++++++++++++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 14 deletions(-)
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index a231faf..a1ce55e 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -495,15 +495,12 @@ static irqreturn_t ab8500_debug_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int ab8500_registers_print(struct seq_file *s, void *p)
+/* Prints to seq_file or log_buf */
+static int ab8500_registers_print(struct device *dev, u32 bank,
+ struct seq_file *s)
{
- struct device *dev = s->private;
unsigned int i;
- u32 bank = debug_bank;
-
- seq_printf(s, AB8500_NAME_STRING " register values:\n");
- seq_printf(s, " bank %u:\n", bank);
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
u32 reg;
@@ -520,22 +517,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_bank_registers, inode->i_private);
}
static const struct file_operations ab8500_registers_fops = {
@@ -546,6 +563,51 @@ static const struct file_operations ab8500_registers_fops = {
.owner = THIS_MODULE,
};
+static int ab8500_print_all_banks(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ unsigned int i;
+ int err;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ for (i = 1; i < AB8500_NUM_BANKS; i++) {
+ err = seq_printf(s, " bank %u:\n", i);
+ if (err < 0)
+ dev_err(dev, "seq_printf overflow, bank=%d\n", i);
+
+ ab8500_registers_print(dev, i, s);
+ }
+ return 0;
+}
+
+static int ab8500_all_banks_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *s;
+ int err;
+
+ err = single_open(file, ab8500_print_all_banks, inode->i_private);
+ if (!err) {
+ /* Default buf size in seq_read is not enough */
+ s = (struct seq_file *)file->private_data;
+ s->size = (PAGE_SIZE * 2);
+ s->buf = kmalloc(s->size, GFP_KERNEL);
+ if (!s->buf) {
+ single_release(inode, file);
+ err = -ENOMEM;
+ }
+ }
+ return err;
+}
+
+static const struct file_operations ab8500_all_banks_fops = {
+ .open = ab8500_all_banks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static int ab8500_bank_print(struct seq_file *s, void *p)
{
return seq_printf(s, "%d\n", debug_bank);
@@ -1475,6 +1537,11 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
if (!file)
goto err;
+ file = debugfs_create_file("all-banks", S_IRUGO,
+ ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
+ if (!file)
+ goto err;
+
file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
ab8500_dir, &plf->dev, &ab8500_bank_fops);
if (!file)
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox