* Building with gcc 4.6.4
From: Russell King - ARM Linux @ 2014-01-28 15:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <21223.49366.479579.145000@gargle.gargle.HOWL>
On Tue, Jan 28, 2014 at 03:38:14PM +0100, Mikael Pettersson wrote:
> Russell King - ARM Linux writes:
> > So, yesterday I built gcc 4.6.4 (mainline) for the autobuilder, and the
> > result is that every build failed with the same error:
> >
> > scripts/mod/empty.c:1:0: error: FPA is unsupported in the AAPCS
> >
> > This seems to be because linux-elf targets default to fpe3 in mainline
> > gcc, but specifying -mabi=aapcs-linux switches us into EABI mode where
> > the compiler errors out with the default FPU.
> >
> > Hence, I believe we need this to ensure that a compatible VFP is
> > selected. One can argue that building EABI ARMv4 with VFP is silly,
> > but it seems that's what the gcc folk have decided (rightly or
> > wrongly.)
> >
> > Maybe this is a bug in mainline GCC - which begs the question why
> > (presumably, since no one has picked this up) Linaro's toolchain
> > has fixes but mainline GCC doesn't.
> >
> > Comments?
>
> Perhaps because most ARM EABI toolchains default to soft-float,
> and the hardfloat ones usually select v6 or v7 + vfp-d16 or neon
> as their defaults, so the archaic FPA is never the default.
soft-float has nothing to do with it, because the kernel always passes
-msoft-float.
> Or are you using an OABI toolchain to compile an EABI kernel?
... which should make no difference what so ever since the kernel should
be passing the appropriate options. That's why we pass -mabi=aapcs-linux
to the kernel.
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* [PATCH] arm/xen: Initialize event channels earlier
From: Julien Grall @ 2014-01-28 14:54 UTC (permalink / raw)
To: linux-arm-kernel
Event channels driver needs to be initialized very early. Until now, Xen
initialization was done after all CPUs was bring up.
We can safely move the initialization to an early initcall.
Also use a cpu notifier to:
- Register the VCPU when the CPU is prepared
- Enable event channel IRQ when the CPU is running
Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
arch/arm/xen/enlighten.c | 84 ++++++++++++++++++++++++++++++----------------
1 file changed, 55 insertions(+), 29 deletions(-)
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 293eeea..39b668e 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -23,6 +23,7 @@
#include <linux/of_address.h>
#include <linux/cpuidle.h>
#include <linux/cpufreq.h>
+#include <linux/cpu.h>
#include <linux/mm.h>
@@ -154,12 +155,11 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
}
EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range);
-static void __init xen_percpu_init(void *unused)
+static void xen_percpu_init(int cpu)
{
struct vcpu_register_vcpu_info info;
struct vcpu_info *vcpup;
int err;
- int cpu = get_cpu();
pr_info("Xen: initializing cpu%d\n", cpu);
vcpup = per_cpu_ptr(xen_vcpu_info, cpu);
@@ -170,9 +170,11 @@ static void __init xen_percpu_init(void *unused)
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
BUG_ON(err);
per_cpu(xen_vcpu, cpu) = vcpup;
+}
+static void xen_interrupt_init(void)
+{
enable_percpu_irq(xen_events_irq, 0);
- put_cpu();
}
static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
@@ -193,6 +195,36 @@ static void xen_power_off(void)
BUG();
}
+static irqreturn_t xen_arm_callback(int irq, void *arg)
+{
+ xen_hvm_evtchn_do_upcall();
+ return IRQ_HANDLED;
+}
+
+static int xen_cpu_notification(struct notifier_block *self,
+ unsigned long action,
+ void *hcpu)
+{
+ int cpu = (long)hcpu;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ xen_percpu_init(cpu);
+ break;
+ case CPU_STARTING:
+ xen_interrupt_init();
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block xen_cpu_notifier = {
+ .notifier_call = xen_cpu_notification,
+};
+
/*
* see Documentation/devicetree/bindings/arm/xen.txt for the
* documentation of the Xen Device Tree format.
@@ -209,6 +241,7 @@ static int __init xen_guest_init(void)
const char *xen_prefix = "xen,xen-";
struct resource res;
phys_addr_t grant_frames;
+ int cpu;
node = of_find_compatible_node(NULL, NULL, "xen,xen");
if (!node) {
@@ -281,9 +314,27 @@ static int __init xen_guest_init(void)
disable_cpuidle();
disable_cpufreq();
+ xen_init_IRQ();
+
+ if (xen_events_irq < 0)
+ return -ENODEV;
+
+ if (request_percpu_irq(xen_events_irq, xen_arm_callback,
+ "events", &xen_vcpu)) {
+ pr_err("Error request IRQ %d\n", xen_events_irq);
+ return -EINVAL;
+ }
+
+ cpu = get_cpu();
+ xen_percpu_init(cpu);
+ xen_interrupt_init();
+ put_cpu();
+
+ register_cpu_notifier(&xen_cpu_notifier);
+
return 0;
}
-core_initcall(xen_guest_init);
+early_initcall(xen_guest_init);
static int __init xen_pm_init(void)
{
@@ -297,31 +348,6 @@ static int __init xen_pm_init(void)
}
late_initcall(xen_pm_init);
-static irqreturn_t xen_arm_callback(int irq, void *arg)
-{
- xen_hvm_evtchn_do_upcall();
- return IRQ_HANDLED;
-}
-
-static int __init xen_init_events(void)
-{
- if (!xen_domain() || xen_events_irq < 0)
- return -ENODEV;
-
- xen_init_IRQ();
-
- if (request_percpu_irq(xen_events_irq, xen_arm_callback,
- "events", &xen_vcpu)) {
- pr_err("Error requesting IRQ %d\n", xen_events_irq);
- return -EINVAL;
- }
-
- on_each_cpu(xen_percpu_init, NULL, 0);
-
- return 0;
-}
-postcore_initcall(xen_init_events);
-
/* In the hypervisor.S file. */
EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
--
1.7.10.4
^ permalink raw reply related
* [RFC 1/1] Device Tree Schema Source format description
From: Grant Likely @ 2014-01-28 14:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <3511775.RFRDLM8Ohp@amdc1227>
Some random thoughts ahead of meeting today...
On Fri, 18 Oct 2013 16:57:36 +0200, Tomasz Figa <t.figa@samsung.com> wrote:
> /*
> * schema.dtss - Sample Device Tree schema file.
> *
> * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> * Author: Tomasz Figa <t.figa@samsung.com>
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License as
> * published by the Free Software Foundation version 2.
> *
> * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> * kind, whether express or implied; without even the implied warranty
> * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> * GNU General Public License for more details.
> */
>
> /dtss-v1/;
In general I'm concerned about the creation of a new language, even if
it is based on the DTS syntax. It forces us to define grammer that by
necessity will be simple at first just to get things working, but then
need to be extended to handle complex stuff. I've been researching ASN.1
and similar schema languages to see if we can adopt the structure if not
the syntax when writing schema files.
In the mean time I'm now feeling that we should go ahead with the
C-implementation of schema checking just to make some progress and then
migrate the logic out into separately parsed schema files when we have
something better. The low hanging fruit of course is the core bindings.
Interrupts, gpios, regs, clocks, common busses like spi, i2c & pci.
I think the most important thing to get settled now is determining how
we trigger schema checks. For example, given a random node in the tree,
how does the checker know to apply the interrupts and regs tests?
> * Special keywords:
> *
> * /template/
> * Defines schema template that can be used to represent generic bindings
> * which may be then included in device bindings by /use/ keyword.
> * A template can take a set of required or optional parameters.
> * Optional parameters need to have default value specified, which is
> * used when the parameter is omited from parameters of /use/ clause.
> *
> * Template declaration uses following syntax:
> * /template/ template-name {
> * /arg/ argument-name-1; // Required argument
> * /arg/ argument-name-2 = <1>; // Optional argument
> * // Here follows binding specification described further
> * // in this document.
> * };
I'm wary of the template approach. I think schemas should be schemas,
and it should alwasy be possible for a schema to derive from any other
schema. For instance, a device binding will pull in the interrupt
consumer and reg core schemas. Also, a special purpose UART device
may use a simple extension of the ns16550 binding.
I guess my point is that templates shouldn't be a special case. All
bindings should be derivable, but what we do need is a mechanism to
constrain bindings. For example, the interrupts binding would describe
one or more interrupts in a list, but a given device may need to
constrain a minimum of 2 interrupts. For an initial C implementation that
could merely be a argument when invoking the binding test.
> *
> * A template argument is dereferenced by its name prefixed with
> * a dollar ($) sign. An arbitrary property specified in parsed
> * tree can be dereferenced by its absolute or relative path or
> * by a lookup up the tree (interrupt-parent like).
> *
> * /arg/
> * Marks following property declaration as a template argument.
> * Can be used only inside a template declaration, to declare template
> * arguments, as described above in /template/ keyword description.
> *
> * /use/
> * Instantiates binding template. Causes the specified template to be
> * included as a part of the binding specified by current node.
> *
> * Syntax used to instatiate templates:
> * /use/ template-name {
> * // List of template arguments and their values, e.g.
> * argument-name-1 = <int-value>;
> * argument-name-2 = "string-value";
> * // etc.
> * };
On the syntax, this feels very verbose. If we were to draw inspiration
from the ASN.1 syntax, we might do somehting like this:
FdtDevice ::= SET {
interrupts FdtInterrupt (SIZE(1))
reg FdtReg
}
FdtDevice is a type that makes use of the FdtReg and FdtInterrupt types.
> *
> * /incomplete/
> * Tells the validator that the schema is not complete, i.e.
> * only specified properties and subnodes should be validated,
> * without complaining about ones not specified in the schema.
> *
> * Example of use:
> * {
> * compatible = "simple-bus";
> * #address-cells = <1>;
> * #size-cells = <1>;
> *
> * *.* { // Zero or more subnodes
> * /incomplete/; // of unspecified contents
> * };
> * };
> *
> * /inheritable/
> * Marks property as inheritable by subnodes of node in which
> * it is defined. An example of such property is interrupt-parent,
> * which, if not specified in the same node as interrupts property,
> * is assumed to be the same as the closest interrupt-parent property
> * found when walking up the tree.
> *
> * This is purely a helper construct to allow referencing to
> * a property from inside of a DTSS, even if it is not specified
> * in referred node explicitly.
> *
> * Example of use:
> * {
> * /inheritable/ interrupt-parent = phandle;
> *
> * .* {
> * // interrupt-parent is defined for this node
> * // implicitly, even if not specified explicitly
> * };
> * };
Some bindings are just core, like interrupts. It would probablay be
better to just leave those in C even when we're happy with a schema
language.
> * Binding description
> *
> * A binding starts with a top level node that must be described using at
> * least one of the key node attributes specified below. The top level node
> * can contains a set of properties and subnodes that describe the binding.
> * They can be specified using the DTS Schema syntax, which is basically
> * the standard DTS syntax modified to convey information about the schema,
> * not contents.
It seems to me that what you're getting at is that a binding needs to
describe how it is matched (key attributes) and then the set of
constraints. That is a good start, but it feels to me like the matching
isn't very well defined yet. We need some pretty firm rules about how
the checker know when it can apply rules, and those rules will change
depending on where in the tree you are. For example, the cpus schema
only is applicable under the /cpus node, and device nodes with
compatible properties should only match on nodes that are under bus
nodes. (there's another issue of checking for nodes placed where they
shouldn't be, but I'll leave that aside for now).
Also the key properties or matching criteria will not be present for
some bindings because they are only ever directly instantiated. ie. the
interrupts binding doesn't stand on its own, it is only ever called out
to by another binding. (I know, you've addressed some of this above, but
I'm working through a though process).
As we talked about on the call today, if we can hammer out how the
schemas will get selected at test time, then we can start to implement a
hybrid approach where core stuff is implemented in C code and schema
files can instantiate the core bindings as needed.
g.
> *
> * Node description
> *
> * A node starts with a node-name, then { and ends with matching } and
> * a semicolon. It can be described by a set of key attributes, which are:
> * - compatible property,
> * - device_type property,
> * - node name (DEPRECATED for top level nodes of bindings).
> *
> * Once a node matches all specified key attributes of a defined binding
> * it is validated according to description of this binding.
> *
> * Property specification
> *
> * Each property inside a node is specified just as in a normal DTS file,
> * except that the value specified determines value type and range of
> * allowed values, not a particular value itself. In addition, property
> * name can be prefixed with an optionality quantifier, marking the property
> * as optional (specified 0 or 1 times).
> *
> * Property type can be specified using type specification syntax. It is
> * a regular expression like syntax, but including special type keywords,
> * that represent all the defined DTS value types, which is:
> * 1) string: a string of characters enclosed by quotation marks,
> * 2) cell: a single, unsigned 32-bit value,
> * 3) phandle: a valid phandle to any device node,
> * 4) binary: a sequence of bytes (NOTE: quantifiers work as byte count here).
> * Property types can be mixed inside the property, so the value can consist
> * of followed multiple blocks of data of different types.
> *
> * In addition, string and cell types can be limited to specified set
> * of allowed values, discrete or contiguous (cell only), by using
> * parentheses after type name. Regular expressions are allowed when
> * specifying allowed string values.
> *
> * Inside property specifiers, other properties and template arguments
> * can be dereferenced by preceding their names with dollar "$" sign.
> * Element count of a property that is an array can be received by
> * preceding its name with at "@" sign. The property name following
> * $ or @ sign is interpreted as a path in device tree, either absolute
> * if started by a slash "/" or relative otherwise.
> *
> * Example properties built from strings:
> *
> * string-property-1 = string; // one string
> * string-property-2 = string+; // array of strings
> * string-property-3 = string{@clock-names}; // same count as in
> * // clock-names property
> * string-property-4 = string("one", "two", "three"); // three
> * // allowed values
> * string-property-5 = string("[a-zA-Z]+[0-9]"); // allowed values
> * // defined using a regexp
> *
> * Example properties built from cells:
> *
> * cell-property-1 = cell; // one cell
> * cell-property-2 = (cell{$#cell-property-2-cells})+; // cell count
> * // specified by #cell-property-name-cells property
> * cell-property-3 = cell(0, 1, 2, 3, 4); // integers from 0 to 4
> * cell-property-4 = cell(0..4); // same as above, but using a range
> *
> * Example proprerties built from phandles:
> *
> * phandle-property-1 = phandle; // one phandle
> *
> * Example properties built from binary data:
> *
> * binary-property-1 = binary+; // one or more bytes of binary data
> * binary-property-2 = binary{6}; // 6 bytes of binary data
> *
> * Example mixed properties:
> *
> * mixed-property-1 = ((phandle),cell{$\2/#mixed-property-1-cells})+;
> * // typical specifier - phandle of controller node and a set of cells
> * // defined by #*-cells property of controller node. Note the use
> * // of backreferences here.
> * // TODO: How to represent references to properties in a node
> * // pointed by a phandle?
> *
> * Quantifiers
> *
> * Determines valid iteration count for element after the quantifier
> * symbol, which can be a property or a child node. <quantifier> can be
> * any valid quantifier according to POSIX extended regular expression
> * syntax.
> *
> * Examples of use:
> *
> * // For properties
> * property-name-1; // Required property
> * ?property-name-2; // Optional property
> *
> * // For subnodes
> * node-name-1 {}; // Required node (exactly 1 time)
> * ?node-name-2 {}; // Optional node (0 or 1 times)
> * +node-name-3 {}; // Required node (1 or more times)
> * *node-name-4 {}; // Optional nodes (0 or more times)
> * {1,3}node-name-5 {}; // From 1 to 3 subnodes must be present
> *
> * // For data types
> * property-name-1 = cell; // One cell
> * property-name-2 = string+; // One or more strings
> * property-name-3 = phandle{3,8}; // From three to eight phandles
> *
> * Real-life examples
> *
> * Following is a set of examples of DTS Schema syntax use, based on existing
> * device tree bindings. All examples are commented to explain used mechanisms.
> * Note that all the examples are valid and should compile fine using a DTS
> * Schema enabled version of the DTC compiler.
> */
>
> /*
> * Utility schema templates.
> */
> /template/ reg-property {
> /*
> * This template takes one argument reg-count, which is optional
> * and if omitted, takes the default value of 1.
> */
> /arg/ reg-count = <1>;
>
> /*
> * The example below defines a mandatory "reg" property, consisting
> * of exactly reg-count groups, each consisting of (#address-cells +
> * #size-cells) cells each.
> */
> reg = (cell{$../#address-cells},cell{$../#size-cells}){$reg-count};
> };
>
> /template/ status-property {
> /*
> * Template without arguments.
> *
> * Defines a single, optional status property that can take one of
> * enumerated values.
> */
> ?status = string("okay", "disabled");
> };
>
> /template/ device {
> /* Optional argument, defaulting to 1. */
>
> /* TODO: How to specify variable entry count? */
> /arg/ reg-count = <1>;
>
> /* Use a template. */
> /use/ reg-property {
> /*
> * Specify value of template argument.
> * Note the reference to argument of this template.
> */
> reg-count = $reg-count;
> };
> /* Use another template. This time without arguments specified. */
> /use/ status-property;
> };
>
> /template/ bus {
> #address-cells = cell;
> #size-cells = cell;
>
> /default/ #address-cells = <2>;
> /default/ #size-cells = <1>;
> };
>
> /*
> * Generic SPI bindings.
> */
> /template/ spi {
> /* Mandatory argument, without default value. */
> /arg/ cs-cells = cell;
>
> /* #address-cells property equal to cs-cells argument. */
> #address-cells = <$cs-cells>;
> /* Fixed value of #size-cells property. */
> #size-cells = <0>;
> /* A single-cell property num-cs. */
> num-cs = cell;
>
> /* From 0 to $num-cs subnodes with any name. */
> {0,$num-cs}.* {
> /* This node must have a reg property, with one entry. */
> /use/ reg-property {
> reg-count = <1>;
> };
> /* This binding does not fully define node contents. */
> /incomplete/;
> };
> };
>
> /*
> * Generic interrupt bindings.
> */
> /template/ interrupts {
> /*
> * Optional argument, specifying number of entries in interrupts
> * property. Defaults to 1.
> * TODO: How to specify optional interrupts or interrupt lists
> * that vary with compatible string?
> */
> /arg/ interrupt-count = <1>;
>
> /* Optional phandle to interrupt controller. */
> /inheritable/ ?interrupt-parent = phandle;
> /*
> * List of interrupts.
> * TODO: variable interrupt count?
> */
> interrupts = (cell{$($interrupt-parent)/#interrupt-cells}){$interrupt-count};
> };
>
> /*
> * Generic clock bindings.
> */
> /template/ clocks {
> /*
> * Required argument specifying number of clocks.
> * TODO: Optional clocks?
> */
> /arg/ clock-count = cell;
>
> /*
> * List of exactly $count clock specifiers.
> * TODO: How to dereference phandles of specifiers properly.
> */
> clocks = ((phandle),cell{$\2/#clock-cells}){$count};
> };
>
> /*
> * Generic pinctrl bindings.
> */
> /template/ pinctrl {
> /*
> * List of pinctrl names.
> * TODO: Optional pinctrl states?
> */
> /arg/ names = string+;
>
> /* Pinctrl names, as specified in $names. */
> pinctrl-names = $names;
> /*
> * Pinctrl groups for every entry of pinctrl-names property.
> * TODO: Find a correct way to define a series of properties.
> */
> pinctrl-[0- at names] = phandle+;
> };
>
> /template/ pinctrl-default {
> /* Fixed value of required pinctrl-names property. */
> pinctrl-names = "default";
> /*
> * List of pinctrl groups for default pinctrl state.
> * NOTE that an empty list of groups can be specified too.
> */
> pinctrl-0 = phandle*;
> };
>
> /*
> * Generic video interface (V4L2/media) bindings.
> */
> /template/ video-port {
> port {
> /* Bus with 1-cell addresses and no sizes. */
> #address-cells = <1>;
> #size-cells = <0>;
>
> /* One or more endpoint nodes. */
> +endpoint {
> /* Single entry reg property. */
> /use/ reg-property;
> /*
> * Required phandle to remote endpoint.
> * TODO: Do we need to check things like bidirectional
> * connectivity? I.e. whether the node pointed by
> * $remote-endpoint points to this node?
> */
> remote-endpoint = phandle;
> /* Optional property indicating slave mode operation. */
> ?slave-mode;
> /* Optional bus width */
> ?bus-width = cell;
> /* ... */
> };
> };
> };
>
> /template/ video-ports {
> /* Bus with 1-cell addresses and no sizes. */
> #address-cells = <1>;
> #size-cells = <0>;
>
> /* Include video port template. */
> /use/ video-port {
> /* Override quantifier of port subnodes. */
> +port {
> /* Single entry reg property. */
> /use/ reg-property;
> };
> };
> };
>
> /*
> * Skeleton schema for all DTSes according to ePAPR 1.1.
> *
> * NOTE explicit node location specified.
> */
> &{/} {
> /* Human readable board model. */
> model = string;
> /* Set of board compatible values. */
> compatible = string+;
> /* Optional version of ePAPR spec this device tree complies to. */
> ?epapr-version = string;
> /* Top level bus */
> /use/ bus;
>
> /* Required chosen node. */
> chosen {
> /* Optional bootargs string. */
> ?bootargs = string;
> /* Optional stdout-path string. */
> ?stdout-path = string;
> /* Optional stdin-path string. */
> ?stdin-path = string;
> };
>
> /* Required aliases node. */
> aliases {
> /*
> * Optional list of aliases with arbitrary names, pointing
> * to device nodes either by path...
> */
> ?[a-z0-9_]+ = string; /* TODO: Should we check path validity? */
> /* ...or phandle. */
> ?[a-z0-9_]+ = phandle;
> };
>
> /* Required memory node. */
> memory {
> /* Required single entry reg property. */
> /use/ reg-property {
> reg-count = /* TODO: how to specify a range here */;
> };
>
> /* Required device_type set to "memory". */
> device_type = "memory";
> /* Optional property containing multiple reg-like entries. */
> ?initial-mapped-area = (cell{../#address-cells},cell{../#size-cells})+;
> };
>
> /* Required cpus node. */
> cpus {
> /* A bus with 1-cell address and 0-cell size specifiers. */
> #address-cells = <1>;
> #size-cells = <0>;
>
> /* A set of CPU nodes. At least one is required. */
> +cpu {
> /* 1-entry reg property, for CPU MPIDR. */
> /use/ reg-property;
> /* This node can have status property. */
> /use/ status-property;
> /* The device_type property must be set to "cpu". */
> device_type = "cpu";
> /*
> * Optional clock-frequency property, specified
> * using 1 or 2 cells, depending on the platform.
> */
> ?clock-frequency = cell{1,2};
>
> /*
> * Additional platform-specific properties might be
> * present here, which are out of scope of this
> * binding.
> */
> /incomplete/;
> };
> };
>
> /* Any optional device nodes. */
> *.* {
> /* Out of scope of this binding. */
> /incomplete/;
> };
> };
>
> /*
> * Davinci SPI controller device bindings
> */
> {
> /* Binding is defined for any of following compatible values. */
> compatible = string("ti,dm64410-spi", "ti,da830-spi");
>
> /* Use generic device bindings. */
> /use/ device;
> /* Use generic SPI bindings. */
> /use/ spi {
> /* Chip select is identified using one cell. */
> cs-cells = <1>;
> };
> /* Use generic interrupt bindings. */
> /use/ interrupts {
> /* This device has one interrupt signal. */
> interrupt-count = <1>;
> };
> /* Use generic clock bindings. */
> /use/ clocks {
> /*
> * This device consumes one clock, without the need to
> * specify its name.
> */
> count = <1>;
> };
>
> /*
> * Device-specific property that defines which IP interrupt signal
> * is tied to SoC's interrupt controller.
> *
> * TODO: Is this correct?
> */
> ti,davinci-spi-intr-line = cell(<0>, <1>);
> };
>
> /*
> * Samsung S5P/EXYNOS SoC Camera Subsystem (FIMC)
> */
> {
> /* Binding is defined for following compatible value. */
> compatible = "samsung,fimc";
>
> /* Use generic clock bindings. */
> /use/ clocks {
> clock-count = <4>;
> };
> /* Clocks with following names must be specified. */
> clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1";
> /* Use generic pinctrl bindings. */
> /use/ pinctrl {
> /*
> * At least "default" state must be specified. Remaining
> * three states are optional.
> * TODO: Revise handling of optional states.
> */
> names = "default", ("idle", "active-a", "active-b")?;
> };
> /* This node can have a status property. */
> /use/ status-property;
> /* This node represents a bus with 1-cell addresses and sizes. */
> #address-cells = <1>;
> #size-cells = <1>;
>
> /* Optional node representing parallel camera ports. */
> ?parallel-ports {
> /*
> * This node represents a bus with 1-cell addresses and
> * no sizes.
> */
> #address-cells = <1>;
> #size-cells = <0>;
>
> /* Use generic video port bindings. */
> /use/ video-port;
> };
>
> /* At least one fimc node is required */
> +fimc {
> /* Compatible should be set to one of following values. */
> compatible = string("samsung,s5pv210-fimc",
> "samsung,exynos4210-fimc",
> "samsung,exynos4212-fimc");
> /* This is a device. */
> /use/ device;
> /* This device has a single interrupt signal. */
> /use/ interrupts;
> /* Clocks are used. */
> /use/ clocks {
> clock-count = <2>;
> };
> /* With following clock names. */
> clock-names = "fimc", "sclk_fimc";
>
> /*
> * Here follows an example set of properties described
> * as in existing binding documentation files.
> *
> * NOTE: Each property is followed by its description.
> */
>
> /* Required properties: */
> samsung,pix-limits = cell{4};
> /*
> * an array of maximum supported image sizes in pixels, for
> * details refer to Table 2-1 in the S5PV210 SoC User Manual; The meaning of
> * each cell is as follows:
> * 0 - scaler input horizontal size,
> * 1 - input horizontal size for the scaler bypassed,
> * 2 - REAL_WIDTH without input rotation,
> * 3 - REAL_HEIGHT with input rotation.
> */
> samsung,sysreg = phandle;
> /* A phandle to the SYSREG node. */
>
> /* Optional properties: */
> ?clock-frequency = cell;
> /* maximum FIMC local clock (LCLK) frequency */
> ?samsung,min-pix-sizes = cell{2};
> /*
> * An array specifying minimum image size in pixels at
> * the FIMC input and output DMA, in the first and second cell
> * respectively. Default value when this property is not
> * present is <16 16>
> */
> ?samsung,min-pix-alignment = cell{2};
> /*
> * minimum supported image height alignment (first cell)
> * and the horizontal image offset (second cell). The values
> * are in pixels and default to <2 1> when this property is
> * not present
> */
> ?samsung,mainscaler-ext;
> /*
> * A boolean property indicating whether the FIMC IP
> * supports extended image size and has CIEXTEN register.
> */
> ?samsung,rotators = cell;
> /*
> * A bitmask specifying whether this IP has the input and
> * the output rotator. Bits 4 and 0 correspond to input and
> * output rotator respectively. If a rotator is present its
> * corresponding bit should be set. Default value when this
> * property is not specified is 0x11.
> */
> ?samsung,cam-if;
> /*
> * A bolean property indicating whether the IP block includes
> * the camera input interface.
> */
> ?samsung,isp-wb;
> /*
> * This property must be present if the IP block has the ISP
> * writeback input.
> */
> ?samsung,lcd-wb;
> /*
> * This property must be present if the IP block has the LCD
> * writeback input.
> */
> };
>
> /*
> * One or more optional csis node.
> * Contents unspecified by this binding.
> */
> *csis {
> /incomplete/;
> };
>
> /*
> * One or more optional fimc-lite node.
> * Contents unspecified by this binding.
> */
> *fimc-lite {
> /incomplete/;
> };
> };
>
> /*
> * PCI device binding template (used by PCI bus binding)
> */
> /template/ pci-device {
> /* Compatible string matching any of listed regular expressions. */
> compatible = string("pciclass,([0-9a-f]{4})([0-9a-f]{2})?",
> "pci([1-9a-f][0-9a-f]{0,3}|0),([1-9a-f][0-9a-f]{0,3}|0)\.([1-9a-f][0-9a-f]{0,3})\.([1-9a-f][0-9a-f]{0,3}|0)\.([1-9a-f][0-9a-f]?|0)",
> "pci([1-9a-f][0-9a-f]{0,3}|0),([1-9a-f][0-9a-f]{0,3}|0)\.([1-9a-f][0-9a-f]{0,3})\.([1-9a-f][0-9a-f]{0,3}|0)",
> "pci([1-9a-f][0-9a-f]{0,3}),([1-9a-f][0-9a-f]{0,3}|0)",
> "pci([1-9a-f][0-9a-f]{0,3}|0),([1-9a-f][0-9a-f]{0,3}|0)\.([1-9a-f][0-9a-f]?|0)",
> "pci([1-9a-f][0-9a-f]{0,3}|0),([1-9a-f][0-9a-f]{0,3}|0)",
> "pciclass,([0-9a-f]{4})([0-9a-f]{2})?");
> /* Device name string. */
> name = string;
> /*
> * A set of 5-cell reg entries defined accordign to PCI binding
> * specification.
> */
> reg = (cell{5})+;
> /* Optional interrupt specifier. */
> /use/ ?interrupts = {
> interrupt-count = <1>;
> };
>
> /* Optional alternate reg property. */
> ?alternate-reg = (cell{5})+;
> /* Optional single cell property. */
> ?fcode-rom-offset = cell;
> /* Optional list of up to 6 Assigned addresses. */
> ?assigned-addresses = (cell{5}){0,6};
> /* Optional list of power consumption values - from 1 to 10 cells. */
> ?power-consumption = cell{1,10};
>
> /*
> * Simple single cell properties defined in PCI binding
> * specification.
> */
> vendor-id = cell;
> device-id = cell;
> revision-id = cell;
> class-code = cell;
> min-grant = cell;
> max-latency = cell;
> devsel-speed = cell;
> ?cache-line-size = cell;
> ?fast-back-to-back;
> ?subsystem-id = cell;
> ?subsystem-vendor-id = cell;
>
> /* Boolean properties. */
> ?66mhz-capable;
> ?udf-supported;
>
> /* Extra per-device attributes are allowed. */
> /incomplete/;
> };
>
> /*
> * PCI bus binding template
> */
> /template/ pci-bus {
> /* PCI bus node must have device_type set to "pci". */
> device_type = "pci";
> /* Standard bus attributes. */
> #address-cells = <3>;
> #size-cells = <2>;
> ranges;
>
> /* A set of optional properties. */
> ?bus-range = cell{2};
> ?clock-frequency = cell;
> ?slot-names = cell, string+;
> ?bus-master-capable = cell;
>
> /* PCI devices */
> * {
> /use/ pci-device;
> };
> };
>
> /*
> * NVIDIA Tegra PCIe controller
> */
> {
> /* Binding is identified by following compatible list. */
> compatible = string("nvidia,tegra20-pcie", "nvidia,tegra30-pcie");
> /* It is a PCI bus. */
> /use/ pci-bus;
> /* Needs 3 reg entries. */
> /use/ reg-property {
> reg-count = <3>;
> };
> /* Names of reg entries must be specified as follows. */
> reg-names = "pads", "afi", "cs";
> /* Neds 2 interrupts. */
> /use/ interrupts {
> interrupt-count = <2>;
> };
> /* With names as specified below. */
> interrupt-names = "intr", "msi";
> /* Needs 5 clocks. */
> /use/ clocks {
> clock-count = <5>;
> };
> /* With following input names. */
> clock-names = "pex", "afi", "pcie_xclk", "pll_e", "cml";
> /* Needs pex-clk regulator. */
> /use/ regulator {
> supply-name = "pex-clk";
> };
> /* Needs vdd regulator. */
> /use/ regulator {
> supply-name = "vdd";
> };
> /* Needs avdd regulator. */
> /use/ regulator {
> supply-name = "avdd";
> };
>
> /* Root port nodes. */
> *pci {
> /use/ pci-bus;
> nvidia,num-lanes = cell;
> };
> };
>
^ permalink raw reply
* Building with gcc 4.6.4
From: Mikael Pettersson @ 2014-01-28 14:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128120150.GG15937@n2100.arm.linux.org.uk>
Russell King - ARM Linux writes:
> So, yesterday I built gcc 4.6.4 (mainline) for the autobuilder, and the
> result is that every build failed with the same error:
>
> scripts/mod/empty.c:1:0: error: FPA is unsupported in the AAPCS
>
> This seems to be because linux-elf targets default to fpe3 in mainline
> gcc, but specifying -mabi=aapcs-linux switches us into EABI mode where
> the compiler errors out with the default FPU.
>
> Hence, I believe we need this to ensure that a compatible VFP is
> selected. One can argue that building EABI ARMv4 with VFP is silly,
> but it seems that's what the gcc folk have decided (rightly or
> wrongly.)
>
> Maybe this is a bug in mainline GCC - which begs the question why
> (presumably, since no one has picked this up) Linaro's toolchain
> has fixes but mainline GCC doesn't.
>
> Comments?
Perhaps because most ARM EABI toolchains default to soft-float,
and the hardfloat ones usually select v6 or v7 + vfp-d16 or neon
as their defaults, so the archaic FPA is never the default.
Or are you using an OABI toolchain to compile an EABI kernel?
/Mikael
^ permalink raw reply
* [PATCH 01/11] resolve PXA<->8250 serial device address conflict
From: Sergei Ianovich @ 2014-01-28 14:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128141437.GB8713@xo-6d-61-c0.localdomain>
On Tue, 2014-01-28 at 15:14 +0100, Pavel Machek wrote:
> Yes, please. I was hitting the same issue with Sharp Zaurus and bluetooth
> CF card... Bluetooth card had 8250 inside...
A better implementation is posted as v3 of the patch.
http://linux-kernel.2935.n7.nabble.com/PATCH-00-11-ARM-support-for-ICP-DAS-LP-8x4x-tp761919p773485.html
It would be great if you could test that patch add post back the
results.
^ permalink raw reply
* [linux-pm] ARM hibernation / suspend-to-disk
From: Pavel Machek @ 2014-01-28 14:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <51A6399D.4090606@ti.com>
Hi!
> > what's the status of suspend-to-disk on ARM? The most recent discussion I
> > found is:
> > http://lists.linuxfoundation.org/pipermail/linux-pm/2012-November/034997.html
> >
> > with no replies at all. Is anyone still working on that? Anyone got it running?
> >
> > I tried the patch above (on top of LTS 3.4) and got stuck forever, the last
> > thing on the console was:
> >
> > root at omap5:/sys/power# echo disk > state
> > [ 2015.641540] PM: Syncing filesystems ... done.
> > [ 2015.666870] PM: Preallocating image memory... done (allocated 16957 pages)
> > [ 2016.062011] PM: Allocated 67828 kbytes in 0.38 seconds (178.49 MB/s)
> >
> > Any hint how to debug that?
>
> Because of the nature of omap5 PM, you'd need omap5 specific support in
> order for this to work. Specifically, there are a number of assumptions
> about certain power domains never losing state. You can take a look at
> the work I did to get this working on am335x here:
>
> https://github.com/russdill/linux/commits/arm-hibernation-am33xx
>
> For ARM hibernation support to get merged, there needs to be at least
> one platform that supports it. the am335x code I have is not ready as it
> still relies on PM patchsets that have not yet themselves been merged.
Given that we have chicken-and-egg problem here, I believe it makes sense
to merge generic ARM hibernation support now.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH 01/11] resolve PXA<->8250 serial device address conflict
From: Pavel Machek @ 2014-01-28 14:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1385879185-22455-2-git-send-email-ynvich@gmail.com>
Hi!
> PXA serial ports have "standard" UART names (ttyS[0-3]), major
> device number (4) and first minor device number (64) by default.
>
> If the system has extra 8250 serial port hardware in addition
> to onboard PXA serial ports, default settings produce a device
> allocation conflict.
>
> The patch provides a configuration option which can move onboard
> ports out of the way of 8250_core by assigning a different (204)
> major number and corresponding device names (ttySA[0-3]).
Yes, please. I was hitting the same issue with Sharp Zaurus and bluetooth
CF card... Bluetooth card had 8250 inside...
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [Q] block / zynq: DMA bouncing
From: Michal Simek @ 2014-01-28 13:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128134827.GK15937@n2100.arm.linux.org.uk>
On 01/28/2014 02:48 PM, Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 02:28:28PM +0100, Guennadi Liakhovetski wrote:
>> +static void __init zynq_memory_init(void)
>> +{
>> + /*
>> + * Reserve the 0-0x4000 addresses (before page tables and kernel)
>> + * which can't be used for DMA
>> + */
>> + if (!__pa(PAGE_OFFSET))
>> + memblock_reserve(0, 0x4000);
>
> Or maybe this:
>
> memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir));
>
> since that's actually what you mean here.
yep with that if too.
I will prepare that patch and will send it out.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 263 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140128/a500c3b6/attachment.sig>
^ permalink raw reply
* [Q] block / zynq: DMA bouncing
From: Russell King - ARM Linux @ 2014-01-28 13:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <Pine.LNX.4.64.1401281420580.2714@axis700.grange>
On Tue, Jan 28, 2014 at 02:28:28PM +0100, Guennadi Liakhovetski wrote:
> +static void __init zynq_memory_init(void)
> +{
> + /*
> + * Reserve the 0-0x4000 addresses (before page tables and kernel)
> + * which can't be used for DMA
> + */
> + if (!__pa(PAGE_OFFSET))
> + memblock_reserve(0, 0x4000);
Or maybe this:
memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir));
since that's actually what you mean here.
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* [Q] block / zynq: DMA bouncing
From: Guennadi Liakhovetski @ 2014-01-28 13:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <Pine.LNX.4.64.1401281420580.2714@axis700.grange>
On Tue, 28 Jan 2014, Guennadi Liakhovetski wrote:
> Hi Michal,
>
> (trimmed CC a bit)
>
> On Mon, 27 Jan 2014, Michal Simek wrote:
>
> > On 01/27/2014 06:52 PM, Russell King - ARM Linux wrote:
> > > On Mon, Jan 27, 2014 at 06:45:50PM +0100, Michal Simek wrote:
> > >> Why 0x4000? IRC Linux for ARM is using space for any purpose.
> > >> Russell knows this much better than I.
> > >
> > > Probably because as the kernel is loaded at 0x8000, it will place the
> > > swapper page table at 0x4000, thus covering from 0x4000 upwards.
> >
> > Ah yeah swapper.
> >
> > >
> > > Thus, the majority of your un-DMA-able memory will be kernel text or
> > > swapper page tables.
> >
> > Yes, exactly.
> > 0x0 - 0x4000 - reserving not to be used by DMA
> > 0x4000 - 0x8000 swapper page table
> > 0x8000 - 0x80000 kernel text + up
>
> Maybe you could submit something like the attached patch upstream. I'm not
> sure shom you'd like to put as its original author. I put John Linn there
> as he originally authored commit 5b9f3f2ac8a3e4edae9de7b855f25f757884d84c
Sorry, I actually meant commit 83e198c01c381a1d90ba07e241a517d1dabf7c84
Guennadi
> from Xilinx tree with the same description, as the attached patch.
> Unfortunately, that commit didn't have an Sob.
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* [Q] block / zynq: DMA bouncing
From: Guennadi Liakhovetski @ 2014-01-28 13:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <52E69E1E.3020202@monstr.eu>
Hi Michal,
(trimmed CC a bit)
On Mon, 27 Jan 2014, Michal Simek wrote:
> On 01/27/2014 06:52 PM, Russell King - ARM Linux wrote:
> > On Mon, Jan 27, 2014 at 06:45:50PM +0100, Michal Simek wrote:
> >> Why 0x4000? IRC Linux for ARM is using space for any purpose.
> >> Russell knows this much better than I.
> >
> > Probably because as the kernel is loaded at 0x8000, it will place the
> > swapper page table at 0x4000, thus covering from 0x4000 upwards.
>
> Ah yeah swapper.
>
> >
> > Thus, the majority of your un-DMA-able memory will be kernel text or
> > swapper page tables.
>
> Yes, exactly.
> 0x0 - 0x4000 - reserving not to be used by DMA
> 0x4000 - 0x8000 swapper page table
> 0x8000 - 0x80000 kernel text + up
Maybe you could submit something like the attached patch upstream. I'm not
sure shom you'd like to put as its original author. I put John Linn there
as he originally authored commit 5b9f3f2ac8a3e4edae9de7b855f25f757884d84c
from Xilinx tree with the same description, as the attached patch.
Unfortunately, that commit didn't have an Sob.
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Xilinx-ARM-BSP-prevent-DMA-into-lower-memory.patch
Type: text/x-diff
Size: 1867 bytes
Desc:
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140128/50003bc6/attachment.bin>
^ permalink raw reply
* [Patch v3 2/2] dmaengine: qcom_bam_dma: Add device tree binding
From: Russell King - ARM Linux @ 2014-01-28 13:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4916428.f0GtxdkWKj@wuerfel>
On Tue, Jan 28, 2014 at 01:05:10PM +0100, Arnd Bergmann wrote:
> Ok, thanks for clearing up my mistake. However, the argument remains:
> the direction doesn't need to be in the DT DMA descriptor since it
> gets set by software anyway.
Yes - for full-duplex, it's implied, since you have one DMA request
(and therefore virtual channel) for memory-to-device and another for
device-to-memory.
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply
* [PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions
From: Thomas Abraham @ 2014-01-28 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140128114932.GE20583@S2101-09.ap.freescale.net>
On Tue, Jan 28, 2014 at 5:19 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Tue, Jan 28, 2014 at 11:00:29AM +0530, Thomas Abraham wrote:
>> Hi Mike,
>>
>> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette <mturquette@linaro.org> wrote:
>> > Quoting Thomas Abraham (2014-01-18 04:10:51)
>> >> From: Thomas Abraham <thomas.ab@samsung.com>
>> >>
>> >> On some platforms such as the Samsung Exynos, changing the frequency
>> >> of the CPU clock requires changing the frequency of the PLL that is
>> >> supplying the CPU clock. To change the frequency of the PLL, the CPU
>> >> clock is temporarily reparented to another parent clock.
>> >>
>> >> The clock frequency of this temporary parent clock could be much higher
>> >> than the clock frequency of the PLL at the time of reparenting. Due
>> >> to the temporary increase in the CPU clock speed, the CPU (and any other
>> >> components in the CPU clock domain such as dividers, mux, etc.) have to
>> >> to be operated at a higher voltage level, called the safe voltage level.
>> >> This patch adds optional support to temporarily switch to a safe voltage
>> >> level during CPU frequency transitions.
>> >>
>> >> Cc: Shawn Guo <shawn.guo@linaro.org>
>> >> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
>> >
>> > I'm not a fan of this change. This corner case should be abstracted away
>> > somehow. I had talked to Chander Kayshap previously about handling
>> > voltage changes in clock notifier callbacks, which then renders any
>> > voltage change as a trivial part of the clock rate transition. That
>> > means that this "safe voltage" thing could be handled automagically
>> > without any additional code in the CPUfreq driver.
>> >
>> > There are two nice ways to do this with the clock framework. First is
>> > explicit re-parenting with voltage scaling done in the clock rate-change
>> > notifiers:
>> >
>> > clk_set_parent(cpu_clk, temp_parent);
>> > /* implicit voltage scaling to "safe voltage" happens above */
>> > clk_set_rate(pll, some_rate);
>> > clk_set_parent(cpu_clk, pll);
>> > /* implicit voltage scaling to nominal OPP voltage happens above */
>> >
>> > The above sequence would require a separate exnyos CPUfreq driver, due
>> > to the added clk_set_parent logic.
>> >
>> > The second way to do this is to abstract the clk re-muxing logic out
>> > into the clk driver, which would allow cpufreq-cpu0 to be used for the
>> > exynos chips.
>>
>> This is the approach this patch series takes (patch 2/7). The clock
>> re-muxing logic is handled by a clock driver code. The difference from
>> what you suggested is that the safe voltage (that may be optionally)
>> required before doing the re-muxing is handled here in cpufreq-cpu0
>> driver.
>>
>> The safe voltage setup can be done in the notifier as you suggested.
>> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
>> this feature if required. Also, if done here, the regulator handling
>> is localized in this driver which otherwise would need to be handled
>> in two places, cpufreq-cpu0 driver and the clock notifier.
>>
>> So I tend to prefer the approach in this patch but I am willing to
>> consider any suggestions. Shawn, it would be helpful if you could let
>> us know your thoughts on this. I am almost done with testing the v3 of
>> this series and want to post it so if there are any objections to the
>> changes in this patch, please let me know.
>
> To me, it's the best that we reuse cpufreq-cpu0 for exynos without any
> changes on cpufreq-cpu0 driver ;)
Okay, so that leaves us with the only option of handling "safe
voltage" using clock notifier callbacks as suggested by Mike. So there
are two options - a samsung specific cpufreq driver handling the clock
notifiers (and reusing cpufreq-cpu0 driver) or the samsung clock
driver handles the clock notifiers (and reusing cpufreq-cpu0 driver).
With the second option, the clock driver will have to handle the
regulator lookup from the cpu node, deferring regulator lookup until
the cpu and regulator devices are registered and using regulator api
inside clock driver. This seems like too much code to just manage the
"safe voltage".
So how about the first option of samsung specific cpufreq driver. If
there are any other alternatives, please let me know.
Thanks,
Thomas.
>
> Shawn
>
^ permalink raw reply
* [PATCH 2/2] ARM: dts: imx6sl-evk: Add audio support
From: Shawn Guo @ 2014-01-28 12:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5BWfrjxJr=f=0hHwQNuJcQDeLSJi=u6Fci44EctKMSCHQ@mail.gmail.com>
On Tue, Jan 28, 2014 at 10:14:55AM -0200, Fabio Estevam wrote:
> On Tue, Jan 28, 2014 at 10:12 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
>
> >> diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
> >> index 95bb37b..04cf457 100644
> >> --- a/arch/arm/boot/dts/imx6sl.dtsi
> >> +++ b/arch/arm/boot/dts/imx6sl.dtsi
> >> @@ -236,6 +236,7 @@
> >> <&sdma 38 1 0>;
> >> dma-names = "rx", "tx";
> >> fsl,fifo-depth = <15>;
> >> + fsl,ssi-dma-events = <38 37>;
> >
> > Do you still need this custom property?
>
> I can get rid of it.
>
> Should I remove from the other SoCs as well?
We have the requirement that a newer kernel must work with all the older
DTBs. But I haven't heard too much about the opposite - a newer DTB
needs to work with all the older kernel. If that's case, we can remove
it from other SoCs as well, since the latest kernel already moves to
generic DMA bindings.
Shawn
^ permalink raw reply
* [PATCH 18/18] mfd: max14577: Add device tree bindings document
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add document describing device tree bindings for MAX14577 MFD driver
(for both MAX14577 and MAX77836 chipsets).
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Tomasz Figa <t.figa@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: devicetree at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
---
Documentation/devicetree/bindings/mfd/max14577.txt | 104 ++++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/max14577.txt
diff --git a/Documentation/devicetree/bindings/mfd/max14577.txt b/Documentation/devicetree/bindings/mfd/max14577.txt
new file mode 100644
index 000000000000..cb758f84be00
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max14577.txt
@@ -0,0 +1,104 @@
+Maxim MAX14577/77836 Multi-Function Device
+
+MAX14577 is a Multi-Function Device with Micro-USB Interface Circuit, Li+
+Battery Charger and SFOUT LDO output for powering USB devices. It is
+interfaced to host controller using I2C.
+
+MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge.
+
+
+Required properties:
+- compatible : Must be "maxim,max14577" or "maxim,max77836".
+- reg : I2C slave address for the max14577 chip (0x25 for max14577/max77836)
+- interrupts : IRQ line for the chip.
+- interrupt-parent : The parent interrupt controller.
+
+
+Optional nodes:
+- max14577-muic/max77836-muic :
+ Node used only by extcon consumers.
+ Required properties:
+ - compatible : "maxim,max14577-muic" or "maxim,max77836-muic"
+
+- regulators :
+ Required properties:
+ - compatible : "maxim,max14577-regulator"
+ or "maxim,max77836-regulator"
+
+ May contain a sub-node per regulator from the list below. Each
+ sub-node should contain the constraints and initialization information
+ for that regulator. See regulator.txt for a description of standard
+ properties for these sub-nodes.
+
+ List of valid regulator names:
+ - for max14577: CHARGER, SAFEOUT.
+ - for max77836: CHARGER, SAFEOUT, LDO1, LDO2.
+
+ The SAFEOUT is a fixed voltage regulator so there is no need to specify
+ voltages for it.
+
+
+Example:
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+max14577 at 25 {
+ compatible = "maxim,max14577";
+ reg = <0x25>;
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 IRQ_TYPE_NONE>;
+
+ muic: max14577-muic {
+ compatible = "maxim,max14577-muic";
+ };
+
+ regulators {
+ compatible = "maxim,max14577-regulator";
+
+ SAFEOUT {
+ regulator-name = "SAFEOUT";
+ };
+ CHARGER {
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <90000>;
+ regulator-max-microamp = <950000>;
+ regulator-boot-on;
+ };
+ };
+};
+
+
+max77836 at 25 {
+ compatible = "maxim,max77836";
+ reg = <0x25>;
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 IRQ_TYPE_NONE>;
+
+ muic: max77836-muic {
+ compatible = "maxim,max77836-muic";
+ };
+
+ regulators {
+ compatible = "maxim,max77836-regulator";
+
+ SAFEOUT {
+ regulator-name = "SAFEOUT";
+ };
+ CHARGER {
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <90000>;
+ regulator-max-microamp = <950000>;
+ regulator-boot-on;
+ };
+ LDO1 {
+ regulator-name = "LDO1";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ };
+ LDO2 {
+ regulator-name = "LDO2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3950000>;
+ };
+ };
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 17/18] power: max17040: Add ID for max77836 Fuel Gauge block
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
MAX77836 has the same Fuel Gauge as MAX17040. The max17040 driver can be
safely re-used. The patch adds MAX77836 ID to array with i2c_device_id.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---
drivers/power/max17040_battery.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index c7ff6d67f158..591984a93f9f 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -277,6 +277,7 @@ static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
static const struct i2c_device_id max17040_id[] = {
{ "max17040", 0 },
+ { "max77836-battery", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max17040_id);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 16/18] charger: max14577: Add support for MAX77836 charger
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add support for MAX77836 charger to the max14577 driver. The MAX77836
charger is almost the same as 14577 model except:
- No dead-battery detection;
- Support for special charger (like in max77693);
- Support for DX over-voltage protection (like in max77693);
- Lower values of charging current (two times lower current for
slow/fast charge, much lower EOC current);
- Slightly different values in ChgTyp field of STATUS2 register. On
MAX14577 0x6 is reserved and 0x7 dead battery. On the MAX77836 the
0x6 means special charger and 0x7 is reserved. Regardless of these
differences the driver maps them to one enum maxim_muic_charger_type.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Anton Vorontsov <anton@enomsg.org>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
---
drivers/extcon/extcon-max14577.c | 2 +-
drivers/power/max14577_charger.c | 81 +++++++++++++++++++++++++++-------
include/linux/mfd/max14577-private.h | 57 +++++++++++++++++-------
3 files changed, 106 insertions(+), 34 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 440b19ac5fba..9390471f1a56 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -498,7 +498,7 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info)
extcon_set_cable_state(info->edev, "Fast-charger", attached);
break;
case MAXIM_CHARGER_TYPE_NONE:
- case MAXIM_CHARGER_TYPE_DEAD_BATTERY:
+ case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
break;
default:
dev_err(info->dev,
diff --git a/drivers/power/max14577_charger.c b/drivers/power/max14577_charger.c
index 58cddc3b15d6..405f4d736337 100644
--- a/drivers/power/max14577_charger.c
+++ b/drivers/power/max14577_charger.c
@@ -1,7 +1,7 @@
/*
- * Battery charger driver for the Maxim 14577
+ * max14577_charger.c - Battery charger driver for the Maxim 14577/77836
*
- * Copyright (C) 2013 Samsung Electronics
+ * Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -25,10 +25,35 @@ struct max14577_charger {
struct maxim_core *maxim_core;
struct power_supply charger;
- unsigned int charging_state;
- unsigned int battery_state;
+ unsigned int charging_state;
+ unsigned int battery_state;
};
+/*
+ * Helper function for mapping values of STATUS2/CHGTYP register on max14577
+ * and max77836 chipsets to enum maxim_muic_charger_type.
+ */
+static enum maxim_muic_charger_type maxim_get_charger_type(
+ enum maxim_device_type dev_type, u8 val) {
+ switch (val) {
+ case MAXIM_CHARGER_TYPE_NONE:
+ case MAXIM_CHARGER_TYPE_USB:
+ case MAXIM_CHARGER_TYPE_DOWNSTREAM_PORT:
+ case MAXIM_CHARGER_TYPE_DEDICATED_CHG:
+ case MAXIM_CHARGER_TYPE_SPECIAL_500MA:
+ case MAXIM_CHARGER_TYPE_SPECIAL_1A:
+ return val;
+ case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
+ case MAX14577_CHARGER_TYPE_RESERVED:
+ if (dev_type == MAXIM_DEVICE_TYPE_MAX77836)
+ val |= 0x8;
+ return val;
+ default:
+ WARN_ONCE(1, "max14577: Unsupported chgtyp register value 0x%02x", val);
+ return val;
+ }
+}
+
static int max14577_get_charger_state(struct max14577_charger *chg)
{
struct regmap *rmap = chg->maxim_core->regmap_muic;
@@ -89,20 +114,24 @@ static int max14577_get_online(struct max14577_charger *chg)
{
struct regmap *rmap = chg->maxim_core->regmap_muic;
u8 reg_data;
+ enum maxim_muic_charger_type chg_type;
max14577_read_reg(rmap, MAXIM_MUIC_REG_STATUS2, ®_data);
reg_data = reg_data & MAXIM_STATUS2_CHGTYP_MASK;
reg_data >>= MAXIM_STATUS2_CHGTYP_SHIFT;
- switch (reg_data) {
+ chg_type = maxim_get_charger_type(chg->maxim_core->dev_type, reg_data);
+ switch (chg_type) {
case MAXIM_CHARGER_TYPE_USB:
case MAXIM_CHARGER_TYPE_DEDICATED_CHG:
case MAXIM_CHARGER_TYPE_SPECIAL_500MA:
case MAXIM_CHARGER_TYPE_SPECIAL_1A:
- case MAXIM_CHARGER_TYPE_DEAD_BATTERY:
+ case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
+ case MAX77836_CHARGER_TYPE_SPECIAL_BIAS:
return 1;
case MAXIM_CHARGER_TYPE_NONE:
case MAXIM_CHARGER_TYPE_DOWNSTREAM_PORT:
- case MAXIM_CHARGER_TYPE_RESERVED:
+ case MAX14577_CHARGER_TYPE_RESERVED:
+ case MAX77836_CHARGER_TYPE_RESERVED:
default:
return 0;
}
@@ -119,11 +148,13 @@ static int max14577_get_battery_health(struct max14577_charger *chg)
struct regmap *rmap = chg->maxim_core->regmap_muic;
int state = POWER_SUPPLY_HEALTH_GOOD;
u8 reg_data;
+ enum maxim_muic_charger_type chg_type;
max14577_read_reg(rmap, MAXIM_MUIC_REG_STATUS2, ®_data);
reg_data = reg_data & MAXIM_STATUS2_CHGTYP_MASK;
reg_data >>= MAXIM_STATUS2_CHGTYP_SHIFT;
- if (reg_data == MAXIM_CHARGER_TYPE_DEAD_BATTERY) {
+ chg_type = maxim_get_charger_type(chg->maxim_core->dev_type, reg_data);
+ if (chg_type == MAX14577_CHARGER_TYPE_DEAD_BATTERY) {
state = POWER_SUPPLY_HEALTH_DEAD;
goto state_set;
}
@@ -170,7 +201,7 @@ static void max14577_charger_reg_init(struct max14577_charger *chg)
MAXIM_CDETCTRL1_CHGTYPMAN_MASK,
reg_data);
- /* Battery Fast-Charge Timer, from SM-V700: 6hrs */
+ /* Battery Fast-Charge Timer, set to: 6hrs */
reg_data = 0x3 << MAXIM_CHGCTRL1_TCHW_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL1, reg_data);
@@ -182,19 +213,22 @@ static void max14577_charger_reg_init(struct max14577_charger *chg)
reg_data |= 0x1 << MAXIM_CHGCTRL2_MBCHOSTEN_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL2, reg_data);
- /* Battery-Charger Constant Voltage (CV) Mode, from SM-V700: 4.35V */
+ /* Battery-Charger Constant Voltage (CV) Mode, set to: 4.35V */
reg_data = 0xf << MAXIM_CHGCTRL3_MBCCVWRC_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL3, reg_data);
/*
- * Fast Battery-Charge Current Low, default 200-950mA
- * Fast Battery-Charge Current High, from SM-V700: 450mA
+ * Fast Battery-Charge Current Low,
+ * default 200-950mA (max14577) / 100-475mA (max77836)
+ *
+ * Fast Battery-Charge Current High,
+ * set to 450mA (max14577) / 225mA (max77836)
*/
reg_data = 0x1 << MAXIM_CHGCTRL4_MBCICHWRCL_SHIFT;
reg_data |= 0x5 << MAXIM_CHGCTRL4_MBCICHWRCH_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL4, reg_data);
- /* End-of-Charge Current, from SM-V700: 50mA */
+ /* End-of-Charge Current, set to 50mA (max14577) / 7.5mA (max77836) */
reg_data = 0x0 << MAXIM_CHGCTRL5_EOCS_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL5, reg_data);
@@ -202,7 +236,7 @@ static void max14577_charger_reg_init(struct max14577_charger *chg)
reg_data = 0x0 << MAXIM_CHGCTRL6_AUTOSTOP_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL6, reg_data);
- /* Overvoltage-Protection Threshold, from SM-V700: 6.5V */
+ /* Overvoltage-Protection Threshold, set to 6.5V */
reg_data = 0x2 << MAXIM_CHGCTRL7_OTPCGHCVS_SHIFT;
max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL7, reg_data);
}
@@ -218,7 +252,11 @@ static enum power_supply_property max14577_charger_props[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
};
-static const char *model_name = "MAX14577";
+static const char * const model_names[] = {
+ [MAXIM_DEVICE_TYPE_UNKNOWN] = "MAX14577-like",
+ [MAXIM_DEVICE_TYPE_MAX14577] = "MAX14577",
+ [MAXIM_DEVICE_TYPE_MAX77836] = "MAX77836",
+};
static const char *manufacturer = "Maxim Integrated";
static int max14577_charger_get_property(struct power_supply *psy,
@@ -247,7 +285,8 @@ static int max14577_charger_get_property(struct power_supply *psy,
val->intval = max14577_get_online(chg);
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = model_name;
+ BUILD_BUG_ON(ARRAY_SIZE(model_names) != MAXIM_DEVICE_TYPE_NUM);
+ val->strval = model_names[chg->maxim_core->dev_type];
break;
case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = manufacturer;
@@ -299,6 +338,13 @@ static int max14577_charger_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max14577_charger_id[] = {
+ { "max14577-charger", MAXIM_DEVICE_TYPE_MAX14577, },
+ { "max77836-charger", MAXIM_DEVICE_TYPE_MAX77836, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
+
static struct platform_driver max14577_charger_driver = {
.driver = {
.owner = THIS_MODULE,
@@ -306,9 +352,10 @@ static struct platform_driver max14577_charger_driver = {
},
.probe = max14577_charger_probe,
.remove = max14577_charger_remove,
+ .id_table = max14577_charger_id,
};
module_platform_driver(max14577_charger_driver);
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-MODULE_DESCRIPTION("MAXIM 14577 charger driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 charger driver");
MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index 621e24fc45df..6f45bcf804d3 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -62,15 +62,32 @@ enum maxim_muic_reg {
MAXIM_MUIC_REG_END,
};
+/*
+ * Combined charger types for max14577 and max77836.
+ *
+ * On max14577 three lower bits map to STATUS2/CHGTYP field.
+ * On max77836 two values of this field are bitwise OR-ed with 0x8 to indicate
+ * the difference.
+ */
enum maxim_muic_charger_type {
- MAXIM_CHARGER_TYPE_NONE = 0,
- MAXIM_CHARGER_TYPE_USB,
- MAXIM_CHARGER_TYPE_DOWNSTREAM_PORT,
- MAXIM_CHARGER_TYPE_DEDICATED_CHG,
- MAXIM_CHARGER_TYPE_SPECIAL_500MA,
- MAXIM_CHARGER_TYPE_SPECIAL_1A,
- MAXIM_CHARGER_TYPE_RESERVED,
- MAXIM_CHARGER_TYPE_DEAD_BATTERY = 7,
+ MAXIM_CHARGER_TYPE_NONE = 0x0,
+ MAXIM_CHARGER_TYPE_USB = 0x1,
+ MAXIM_CHARGER_TYPE_DOWNSTREAM_PORT = 0x2,
+ MAXIM_CHARGER_TYPE_DEDICATED_CHG = 0x3,
+ MAXIM_CHARGER_TYPE_SPECIAL_500MA = 0x4,
+ /* Special 1A or 2A charger */
+ MAXIM_CHARGER_TYPE_SPECIAL_1A = 0x5,
+ /* max14577: reserved, used on max77836 */
+ MAX14577_CHARGER_TYPE_RESERVED = 0x6,
+ /* max14577: dead-battery charing with maximum current 100mA */
+ MAX14577_CHARGER_TYPE_DEAD_BATTERY = 0x7,
+ /*
+ * max77836: special charger (bias on D+/D-),
+ * register value 0x6 | 0x8 (4th bit set)
+ */
+ MAX77836_CHARGER_TYPE_SPECIAL_BIAS = 0xe,
+ /* max77836: reserved, register value 0x7 | 0x8 (4th bit set) */
+ MAX77836_CHARGER_TYPE_RESERVED = 0xf,
};
/* MAX14577 interrupts */
@@ -111,13 +128,15 @@ enum maxim_muic_charger_type {
#define MAXIM_STATUS2_CHGTYP_SHIFT 0
#define MAXIM_STATUS2_CHGDETRUN_SHIFT 3
#define MAXIM_STATUS2_DCDTMR_SHIFT 4
-#define MAXIM_STATUS2_DBCHG_SHIFT 5
+#define MAX14577_STATUS2_DBCHG_SHIFT 5
+#define MAX77836_STATUS2_DXOVP_SHIFT 5
#define MAXIM_STATUS2_VBVOLT_SHIFT 6
#define MAX77836_STATUS2_VIDRM_SHIFT 7
#define MAXIM_STATUS2_CHGTYP_MASK (0x7 << MAXIM_STATUS2_CHGTYP_SHIFT)
#define MAXIM_STATUS2_CHGDETRUN_MASK (0x1 << MAXIM_STATUS2_CHGDETRUN_SHIFT)
#define MAXIM_STATUS2_DCDTMR_MASK (0x1 << MAXIM_STATUS2_DCDTMR_SHIFT)
-#define MAXIM_STATUS2_DBCHG_MASK (0x1 << MAXIM_STATUS2_DBCHG_SHIFT)
+#define MAX14577_STATUS2_DBCHG_MASK (0x1 << MAX14577_STATUS2_DBCHG_SHIFT)
+#define MAX77836_STATUS2_DXOVP_MASK (0x1 << MAX77836_STATUS2_DXOVP_SHIFT)
#define MAXIM_STATUS2_VBVOLT_MASK (0x1 << MAXIM_STATUS2_VBVOLT_SHIFT)
#define MAX77836_STATUS2_VIDRM_MASK (0x1 << MAX77836_STATUS2_VIDRM_SHIFT)
@@ -178,26 +197,32 @@ enum maxim_muic_charger_type {
#define MAXIM_CONTROL3_JIGSET_SHIFT 0
#define MAXIM_CONTROL3_BOOTSET_SHIFT 2
#define MAXIM_CONTROL3_ADCDBSET_SHIFT 4
+#define MAX14577_CONTROL3_WBTH_SHIFT 6
#define MAXIM_CONTROL3_JIGSET_MASK (0x3 << MAXIM_CONTROL3_JIGSET_SHIFT)
#define MAXIM_CONTROL3_BOOTSET_MASK (0x3 << MAXIM_CONTROL3_BOOTSET_SHIFT)
#define MAXIM_CONTROL3_ADCDBSET_MASK (0x3 << MAXIM_CONTROL3_ADCDBSET_SHIFT)
+#define MAX14577_CONTROL3_WBTH_MASK (0x3 << MAX14577_CONTROL3_WBTH_SHIFT)
/* MAX14577 CDETCTRL1 register */
#define MAXIM_CDETCTRL1_CHGDETEN_SHIFT 0
#define MAXIM_CDETCTRL1_CHGTYPMAN_SHIFT 1
#define MAXIM_CDETCTRL1_DCDEN_SHIFT 2
#define MAXIM_CDETCTRL1_DCD2SCT_SHIFT 3
-#define MAXIM_CDETCTRL1_DCHKTM_SHIFT 4
-#define MAXIM_CDETCTRL1_DBEXIT_SHIFT 5
-#define MAXIM_CDETCTRL1_DBIDLE_SHIFT 6
+#define MAX14577_CDETCTRL1_DCHKTM_SHIFT 4
+#define MAX77836_CDETCTRL1_CDLY_SHIFT 4
+#define MAX14577_CDETCTRL1_DBEXIT_SHIFT 5
+#define MAX77836_CDETCTRL1_DCDCPL_SHIFT 5
+#define MAX14577_CDETCTRL1_DBIDLE_SHIFT 6
#define MAXIM_CDETCTRL1_CDPDET_SHIFT 7
#define MAXIM_CDETCTRL1_CHGDETEN_MASK (0x1 << MAXIM_CDETCTRL1_CHGDETEN_SHIFT)
#define MAXIM_CDETCTRL1_CHGTYPMAN_MASK (0x1 << MAXIM_CDETCTRL1_CHGTYPMAN_SHIFT)
#define MAXIM_CDETCTRL1_DCDEN_MASK (0x1 << MAXIM_CDETCTRL1_DCDEN_SHIFT)
#define MAXIM_CDETCTRL1_DCD2SCT_MASK (0x1 << MAXIM_CDETCTRL1_DCD2SCT_SHIFT)
-#define MAXIM_CDETCTRL1_DCHKTM_MASK (0x1 << MAXIM_CDETCTRL1_DCHKTM_SHIFT)
-#define MAXIM_CDETCTRL1_DBEXIT_MASK (0x1 << MAXIM_CDETCTRL1_DBEXIT_SHIFT)
-#define MAXIM_CDETCTRL1_DBIDLE_MASK (0x1 << MAXIM_CDETCTRL1_DBIDLE_SHIFT)
+#define MAX14577_CDETCTRL1_DCHKTM_MASK (0x1 << MAX14577_CDETCTRL1_DCHKTM_SHIFT)
+#define MAX77836_CDETCTRL1_CDDLY_MASK (0x1 << MAX77836_CDETCTRL1_CDDLY_SHIFT)
+#define MAX14577_CDETCTRL1_DBEXIT_MASK (0x1 << MAX14577_CDETCTRL1_DBEXIT_SHIFT)
+#define MAX77836_CDETCTRL1_DCDCPL_MASK (0x1 << MAX77836_CDETCTRL1_DCDCPL_SHIFT)
+#define MAX14577_CDETCTRL1_DBIDLE_MASK (0x1 << MAX14577_CDETCTRL1_DBIDLE_SHIFT)
#define MAXIM_CDETCTRL1_CDPDET_MASK (0x1 << MAXIM_CDETCTRL1_CDPDET_SHIFT)
/* MAX14577 MAXIM_CHGCTRL1 register */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 15/18] regulator: max14577: Add support for max77836 regulators
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add support for MAX77836 chipset and its additional two LDO regulators.
These LDO regulators are controlled by the PMIC block with additional
regmap (different I2C slave address).
The MAX77836 charger and safeout regulators are almost identical to
MAX14577. The registry layout is the same, except values for charger's
current. The patch adds simple mapping between device type and supported
current by the charger regulator.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/regulator/max14577.c | 275 +++++++++++++++++++++++++++++-----
include/linux/mfd/max14577-private.h | 32 +++-
include/linux/mfd/max14577.h | 10 ++
3 files changed, 281 insertions(+), 36 deletions(-)
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index 8856c660a5da..7150606ac482 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -1,5 +1,5 @@
/*
- * max14577.c - Regulator driver for the Maxim 14577
+ * max14577.c - Regulator driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
@@ -22,6 +22,42 @@
#include <linux/mfd/max14577-private.h>
#include <linux/regulator/of_regulator.h>
+/*
+ * Valid limits of current for max14577 and max77836 chargers.
+ * They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4
+ * register for given chipset.
+ */
+struct maxim_charger_current {
+ /* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */
+ unsigned int min;
+ /*
+ * Minimal current when high setting is active,
+ * set in CHGCTRL4/MBCICHWRCH, uA
+ */
+ unsigned int high_start;
+ /* Value of one step in high setting, uA */
+ unsigned int high_step;
+ /* Maximum current of high setting, uA */
+ unsigned int max;
+};
+
+/* Table of valid charger currents for different Maxim chipsets */
+static const struct maxim_charger_current maxim_charger_currents[] = {
+ [MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
+ [MAXIM_DEVICE_TYPE_MAX14577] = {
+ .min = MAX14577_REGULATOR_CURRENT_LIMIT_MIN,
+ .high_start = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START,
+ .high_step = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
+ .max = MAX14577_REGULATOR_CURRENT_LIMIT_MAX,
+ },
+ [MAXIM_DEVICE_TYPE_MAX77836] = {
+ .min = MAX77836_REGULATOR_CURRENT_LIMIT_MIN,
+ .high_start = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START,
+ .high_step = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
+ .max = MAX77836_REGULATOR_CURRENT_LIMIT_MAX,
+ },
+};
+
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
{
int rid = rdev_get_id(rdev);
@@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
{
u8 reg_data;
struct regmap *rmap = rdev->regmap;
+ struct maxim_core *maxim_core = rdev_get_drvdata(rdev);
+ const struct maxim_charger_current *limits =
+ &maxim_charger_currents[maxim_core->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
@@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
max14577_read_reg(rmap, MAXIM_CHG_REG_CHGCTRL4, ®_data);
if ((reg_data & MAXIM_CHGCTRL4_MBCICHWRCL_MASK) == 0)
- return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
+ return limits->min;
reg_data = ((reg_data & MAXIM_CHGCTRL4_MBCICHWRCH_MASK) >>
MAXIM_CHGCTRL4_MBCICHWRCH_SHIFT);
- return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
- reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
+ return limits->high_start + reg_data * limits->high_step;
}
static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
@@ -67,33 +105,35 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
{
int i, current_bits = 0xf;
u8 reg_data;
+ struct maxim_core *maxim_core = rdev_get_drvdata(rdev);
+ const struct maxim_charger_current *limits =
+ &maxim_charger_currents[maxim_core->dev_type];
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
- if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
- max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
+ if (min_uA > limits->max || max_uA < limits->min)
return -EINVAL;
- if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
- /* Less than 200 mA, so set 90mA (turn only Low Bit off) */
+ if (max_uA < limits->high_start) {
+ /* Less than high_start,
+ * so set the minimal current (turn only Low Bit off) */
u8 reg_data = 0x0 << MAXIM_CHGCTRL4_MBCICHWRCL_SHIFT;
return max14577_update_reg(rdev->regmap,
MAXIM_CHG_REG_CHGCTRL4,
MAXIM_CHGCTRL4_MBCICHWRCL_MASK, reg_data);
}
- /* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
- * valid current starting from LIMIT_MAX. */
- for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
- i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
- i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
+ /* max_uA is in range: <high_start, inifinite>, so search for
+ * valid current starting from maximum current. */
+ for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
if (i <= max_uA)
break;
current_bits--;
}
BUG_ON(current_bits < 0); /* Cannot happen */
- /* Turn Low Bit on (use range 200mA-950 mA) */
+
+ /* Turn Low Bit on (use range high_start-max)... */
reg_data = 0x1 << MAXIM_CHGCTRL4_MBCICHWRCL_SHIFT;
/* and set proper High Bits */
reg_data |= current_bits << MAXIM_CHGCTRL4_MBCICHWRCH_SHIFT;
@@ -118,7 +158,7 @@ static struct regulator_ops max14577_charger_ops = {
.set_current_limit = max14577_reg_set_current_limit,
};
-static const struct regulator_desc supported_regulators[] = {
+static const struct regulator_desc max14577_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
.id = MAX14577_SAFEOUT,
@@ -141,16 +181,88 @@ static const struct regulator_desc supported_regulators[] = {
},
};
+static struct regulator_ops max77836_ldo_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ /* TODO: add .set_suspend_mode */
+};
+
+static const struct regulator_desc max77836_supported_regulators[] = {
+ [MAX14577_SAFEOUT] = {
+ .name = "SAFEOUT",
+ .id = MAX14577_SAFEOUT,
+ .ops = &max14577_safeout_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE,
+ .enable_reg = MAXIM_MUIC_REG_CONTROL2,
+ .enable_mask = MAXIM_CONTROL2_SFOUTORD_MASK,
+ },
+ [MAX14577_CHARGER] = {
+ .name = "CHARGER",
+ .id = MAX14577_CHARGER,
+ .ops = &max14577_charger_ops,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ .enable_reg = MAXIM_CHG_REG_CHGCTRL2,
+ .enable_mask = MAXIM_CHGCTRL2_MBCHOSTEN_MASK,
+ },
+ [MAX77836_LDO1] = {
+ .name = "LDO1",
+ .id = MAX77836_LDO1,
+ .ops = &max77836_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
+ .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
+ .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
+ .enable_reg = MAX77836_LDO_REG_CNFG1_LDO1,
+ .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
+ .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO1,
+ .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
+ },
+ [MAX77836_LDO2] = {
+ .name = "LDO2",
+ .id = MAX77836_LDO2,
+ .ops = &max77836_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
+ .min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
+ .uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
+ .enable_reg = MAX77836_LDO_REG_CNFG1_LDO2,
+ .enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
+ .vsel_reg = MAX77836_LDO_REG_CNFG1_LDO2,
+ .vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
+ },
+};
+
#ifdef CONFIG_OF
static struct of_regulator_match max14577_regulator_matches[] = {
{ .name = "SAFEOUT", },
{ .name = "CHARGER", },
};
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
+static struct of_regulator_match max77836_regulator_matches[] = {
+ { .name = "SAFEOUT", },
+ { .name = "CHARGER", },
+ { .name = "LDO1", },
+ { .name = "LDO2", },
+};
+
+static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
+ enum maxim_device_type dev_type)
{
int ret;
struct device_node *np;
+ struct of_regulator_match *regulator_matches;
+ unsigned int regulator_matches_size;
np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
if (!np) {
@@ -158,8 +270,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return -EINVAL;
}
- ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
- ARRAY_SIZE(max14577_regulator_matches));
+ switch (dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ regulator_matches = max77836_regulator_matches;
+ regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
+ break;
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ regulator_matches = max14577_regulator_matches;
+ regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
+ }
+
+ ret = of_regulator_match(&pdev->dev, np, regulator_matches,
+ regulator_matches_size);
if (ret < 0) {
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
return ret;
@@ -168,31 +291,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
return 0;
}
-static inline struct regulator_init_data *match_init_data(int index)
+static inline struct regulator_init_data *match_init_data(int index,
+ enum maxim_device_type dev_type)
{
- return max14577_regulator_matches[index].init_data;
+ switch (dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ return max77836_regulator_matches[index].init_data;
+
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ return max14577_regulator_matches[index].init_data;
+ }
}
-static inline struct device_node *match_of_node(int index)
+static inline struct device_node *match_of_node(int index,
+ enum maxim_device_type dev_type)
{
- return max14577_regulator_matches[index].of_node;
+ switch (dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ return max77836_regulator_matches[index].of_node;
+
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ return max14577_regulator_matches[index].of_node;
+ }
}
#else /* CONFIG_OF */
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
+static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
+ enum maxim_device_type dev_type)
{
return 0;
}
-static inline struct regulator_init_data *match_init_data(int index)
+static inline struct regulator_init_data *match_init_data(int index,
+ enum maxim_device_type dev_type)
{
return NULL;
}
-static inline struct device_node *match_of_node(int index)
+static inline struct device_node *match_of_node(int index,
+ enum maxim_device_type dev_type)
{
return NULL;
}
#endif /* CONFIG_OF */
+/**
+ * Registers for regulators of max77836 use different I2C slave addresses so
+ * different regmaps must be used for them.
+ *
+ * Returns proper regmap for accessing regulator passed by id.
+ */
+static struct regmap *max14577_get_regmap(struct maxim_core *maxim_core,
+ int reg_id)
+{
+ switch (maxim_core->dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ switch (reg_id) {
+ case MAX77836_SAFEOUT ... MAX77836_CHARGER:
+ return maxim_core->regmap_muic;
+ default:
+ /* MAX77836_LDO1 ... MAX77836_LDO2 */
+ return maxim_core->regmap_pmic;
+ }
+
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ return maxim_core->regmap_muic;
+ }
+}
static int max14577_regulator_probe(struct platform_device *pdev)
{
@@ -200,15 +366,29 @@ static int max14577_regulator_probe(struct platform_device *pdev)
struct max14577_platform_data *pdata = dev_get_platdata(maxim_core->dev);
int i, ret;
struct regulator_config config = {};
+ const struct regulator_desc *supported_regulators;
+ unsigned int supported_regulators_size;
+ enum maxim_device_type dev_type = maxim_core->dev_type;
- ret = max14577_regulator_dt_parse_pdata(pdev);
+ ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
if (ret)
return ret;
+ switch (dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ supported_regulators = max77836_supported_regulators;
+ supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators);
+ break;
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ supported_regulators = max14577_supported_regulators;
+ supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
+ }
+
config.dev = &pdev->dev;
- config.regmap = maxim_core->regmap_muic;
+ config.driver_data = maxim_core;
- for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
+ for (i = 0; i < supported_regulators_size; i++) {
struct regulator_dev *regulator;
/*
* Index of supported_regulators[] is also the id and must
@@ -218,38 +398,63 @@ static int max14577_regulator_probe(struct platform_device *pdev)
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].of_node;
} else {
- config.init_data = match_init_data(i);
- config.of_node = match_of_node(i);
+ config.init_data = match_init_data(i, dev_type);
+ config.of_node = match_of_node(i, dev_type);
}
+ config.regmap = max14577_get_regmap(maxim_core,
+ supported_regulators[i].id);
regulator = devm_regulator_register(&pdev->dev,
&supported_regulators[i], &config);
if (IS_ERR(regulator)) {
ret = PTR_ERR(regulator);
dev_err(&pdev->dev,
- "Regulator init failed for ID %d with error: %d\n",
- i, ret);
+ "Regulator init failed for %d/%s with error: %d\n",
+ i, supported_regulators[i].name, ret);
return ret;
}
+ dev_dbg(&pdev->dev, "Registered regulator %d/%s\n", i,
+ supported_regulators[i].name);
}
return ret;
}
+static const struct platform_device_id max14577_regulator_id[] = {
+ { "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, },
+ { "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
+
static struct platform_driver max14577_regulator_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "max14577-regulator",
},
- .probe = max14577_regulator_probe,
+ .probe = max14577_regulator_probe,
+ .id_table = max14577_regulator_id,
};
static int __init max14577_regulator_init(void)
{
+ /* Check for valid values for charger */
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
- BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_NUM);
+ BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START +
+ MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
+ MAX77836_REGULATOR_CURRENT_LIMIT_MAX);
+ /* Valid charger current values must be provided for each chipset */
+ BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
+
+ BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REG_NUM);
+ BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REG_NUM);
+
+ BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN +
+ (MAX77836_REGULATOR_LDO_VOLTAGE_STEP *
+ (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) !=
+ MAX77836_REGULATOR_LDO_VOLTAGE_MAX);
return platform_driver_register(&max14577_regulator_driver);
}
@@ -262,6 +467,6 @@ static void __exit max14577_regulator_exit(void)
module_exit(max14577_regulator_exit);
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-MODULE_DESCRIPTION("MAXIM 14577 regulator driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max14577-regulator");
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index f08fb59a21a0..621e24fc45df 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -238,10 +238,20 @@ enum maxim_muic_charger_type {
#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000
#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000
+/* MAX77836 regulator current limits (as in MAXIM_CHGCTRL4 register), uA */
+#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN 45000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START 100000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP 25000
+#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX 475000
+
/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000
-
+/* MAX77836 regulator LDOx voltage, uV */
+#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN 800000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX 3950000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP 50000
+#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM 64
/* Slave addr = 0x46: PMIC */
enum max77836_pmic_reg {
@@ -277,6 +287,26 @@ enum max77836_pmic_reg {
#define MAX77836_TOPSYS_INT_T120C_MASK (0x1 << MAX77836_TOPSYS_INT_T120C_SHIFT)
#define MAX77836_TOPSYS_INT_T140C_MASK (0x1 << MAX77836_TOPSYS_INT_T140C_SHIFT)
+/* LDO1/LDO2 CONFIG1 register */
+#define MAX77836_CNFG1_LDO_PWRMD_SHIFT 6
+#define MAX77836_CNFG1_LDO_TV_SHIFT 0
+#define MAX77836_CNFG1_LDO_PWRMD_MASK (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT)
+#define MAX77836_CNFG1_LDO_TV_MASK (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT)
+
+/* LDO1/LDO2 CONFIG2 register */
+#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT 7
+#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT 6
+#define MAX77836_CNFG2_LDO_COMP_SHIFT 4
+#define MAX77836_CNFG2_LDO_POK_SHIFT 3
+#define MAX77836_CNFG2_LDO_ADE_SHIFT 1
+#define MAX77836_CNFG2_LDO_SS_SHIFT 0
+#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK (0x1 << MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT)
+#define MAX77836_CNFG2_LDO_ALPMEN_MASK (0x1 << MAX77836_CNFG2_LDO_ALPMEN_SHIFT)
+#define MAX77836_CNFG2_LDO_COMP_MASK (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT)
+#define MAX77836_CNFG2_LDO_POK_MASK (0x1 << MAX77836_CNFG2_LDO_POK_SHIFT)
+#define MAX77836_CNFG2_LDO_ADE_MASK (0x1 << MAX77836_CNFG2_LDO_ADE_SHIFT)
+#define MAX77836_CNFG2_LDO_SS_MASK (0x1 << MAX77836_CNFG2_LDO_SS_SHIFT)
+
/* Slave addr = 0x6C: Fuel-Gauge/Battery */
enum max77836_fg_reg {
MAX77836_FG_REG_VCELL_MSB = 0x02,
diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h
index 5e5fc77db977..178384dcfed8 100644
--- a/include/linux/mfd/max14577.h
+++ b/include/linux/mfd/max14577.h
@@ -38,6 +38,16 @@ enum max14577_regulators {
MAX14577_REG_NUM,
};
+/* MAX77836 regulator IDs */
+enum max77836_regulators {
+ MAX77836_SAFEOUT = 0,
+ MAX77836_CHARGER,
+ MAX77836_LDO1,
+ MAX77836_LDO2,
+
+ MAX77836_REG_NUM,
+};
+
struct max14577_regulator_platform_data {
int id;
struct regulator_init_data *initdata;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 14/18] extcon: max14577: Add support for max77836
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add support for MAX77836 chipset to the max14577 extcon driver. The
MAX77836 MUIC has additional interrupts (VIDRM, ADC1K) so IRQ handling
is split up into two functions: max14577_parse_irq() and
max77836_parse_irq().
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/extcon/extcon-max14577.c | 107 ++++++++++++++++++++++++++++------
drivers/mfd/max14577.c | 1 +
include/linux/mfd/max14577-private.h | 3 +
3 files changed, 93 insertions(+), 18 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index e986a9b92b60..440b19ac5fba 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -1,8 +1,9 @@
/*
- * extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
+ * extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
*
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
+ * Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -62,6 +63,19 @@ static struct max14577_muic_irq max14577_muic_irqs[] = {
{ MAXIM_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
};
+static struct max14577_muic_irq max77836_muic_irqs[] = {
+ { MAXIM_IRQ_INT1_ADC, "muic-ADC" },
+ { MAXIM_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
+ { MAXIM_IRQ_INT1_ADCERR, "muic-ADCError" },
+ { MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" },
+ { MAXIM_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
+ { MAXIM_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
+ { MAXIM_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
+ { MAXIM_IRQ_INT2_DBCHG, "muic-DBCHG" },
+ { MAXIM_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
+ { MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" },
+};
+
struct max14577_muic_info {
struct device *dev;
struct maxim_core *maxim_core;
@@ -532,21 +546,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
return;
}
-static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
{
- struct max14577_muic_info *info = data;
- int i, irq_type = -1;
-
- /*
- * We may be called multiple times for different nested IRQ-s.
- * Including changes in INT1_ADC and INT2_CGHTYP at once.
- * However we only need to know whether it was ADC, charger
- * or both interrupts so decode IRQ and turn on proper flags.
- */
- for (i = 0; i < info->muic_irqs_num; i++)
- if (irq == info->muic_irqs[i].virq)
- irq_type = info->muic_irqs[i].irq;
-
switch (irq_type) {
case MAXIM_IRQ_INT1_ADC:
case MAXIM_IRQ_INT1_ADCLOW:
@@ -554,7 +559,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
/* Handle all of accessory except for
type of charger accessory */
info->irq_adc = true;
- break;
+ return 1;
case MAXIM_IRQ_INT2_CHGTYP:
case MAXIM_IRQ_INT2_CHGDETRUN:
case MAXIM_IRQ_INT2_DCDTMR:
@@ -562,8 +567,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
case MAXIM_IRQ_INT2_VBVOLT:
/* Handle charger accessory */
info->irq_chg = true;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
+ * Returns 0 if irq_type does not match registered IRQ for this device type.
+ */
+static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
+{
+ /* First check common max14577 interrupts */
+ if (max14577_parse_irq(info, irq_type))
+ return 1;
+
+ switch (irq_type) {
+ case MAX77836_IRQ_INT1_ADC1K:
+ info->irq_adc = true;
+ return 1;
+ case MAX77836_IRQ_INT2_VIDRM:
+ /* Handle charger accessory */
+ info->irq_chg = true;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
+{
+ struct max14577_muic_info *info = data;
+ int i, irq_type = -1;
+ bool irq_parsed;
+
+ /*
+ * We may be called multiple times for different nested IRQ-s.
+ * Including changes in INT1_ADC and INT2_CGHTYP at once.
+ * However we only need to know whether it was ADC, charger
+ * or both interrupts so decode IRQ and turn on proper flags.
+ */
+ for (i = 0; i < info->muic_irqs_num; i++)
+ if (irq == info->muic_irqs[i].virq)
+ irq_type = info->muic_irqs[i].irq;
+
+ switch (info->maxim_core->dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ irq_parsed = max77836_parse_irq(info, irq_type);
break;
+ case MAXIM_DEVICE_TYPE_MAX14577:
default:
+ irq_parsed = max14577_parse_irq(info, irq_type);
+ break;
+ }
+
+ if (!irq_parsed) {
dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
irq_type);
return IRQ_HANDLED;
@@ -649,6 +708,10 @@ static int max14577_muic_probe(struct platform_device *pdev)
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
switch (maxim_core->dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ info->muic_irqs = max77836_muic_irqs;
+ info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
+ break;
case MAXIM_DEVICE_TYPE_MAX14577:
default:
info->muic_irqs = max14577_muic_irqs;
@@ -748,6 +811,13 @@ static int max14577_muic_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max14577_muic_id[] = {
+ { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
+ { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max14577_muic_id);
+
static struct platform_driver max14577_muic_driver = {
.driver = {
.name = "max14577-muic",
@@ -755,11 +825,12 @@ static struct platform_driver max14577_muic_driver = {
},
.probe = max14577_muic_probe,
.remove = max14577_muic_remove,
+ .id_table = max14577_muic_id,
};
module_platform_driver(max14577_muic_driver);
-MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:extcon-max14577");
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 5b10f6f89834..561182e24430 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -146,6 +146,7 @@ static const struct regmap_irq max77836_muic_irqs[] = {
{ .reg_offset = 0, .mask = MAXIM_INT1_ADC_MASK, },
{ .reg_offset = 0, .mask = MAXIM_INT1_ADCLOW_MASK, },
{ .reg_offset = 0, .mask = MAXIM_INT1_ADCERR_MASK, },
+ { .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
/* INT2 interrupts */
{ .reg_offset = 1, .mask = MAXIM_INT2_CHGTYP_MASK, },
{ .reg_offset = 1, .mask = MAXIM_INT2_CHGDETRUN_MASK, },
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index e0dd27d937d6..f08fb59a21a0 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -77,6 +77,7 @@ enum maxim_muic_charger_type {
#define MAXIM_INT1_ADC_MASK (0x1 << 0)
#define MAXIM_INT1_ADCLOW_MASK (0x1 << 1)
#define MAXIM_INT1_ADCERR_MASK (0x1 << 2)
+#define MAX77836_INT1_ADC1K_MASK (0x1 << 3)
#define MAXIM_INT2_CHGTYP_MASK (0x1 << 0)
#define MAXIM_INT2_CHGDETRUN_MASK (0x1 << 1)
@@ -311,6 +312,7 @@ enum maxim_irq {
MAXIM_IRQ_INT1_ADC,
MAXIM_IRQ_INT1_ADCLOW,
MAXIM_IRQ_INT1_ADCERR,
+ MAX77836_IRQ_INT1_ADC1K,
/* INT2 */
MAXIM_IRQ_INT2_CHGTYP,
@@ -318,6 +320,7 @@ enum maxim_irq {
MAXIM_IRQ_INT2_DCDTMR,
MAXIM_IRQ_INT2_DBCHG,
MAXIM_IRQ_INT2_VBVOLT,
+ MAX77836_IRQ_INT2_VIDRM,
/* INT3 */
MAXIM_IRQ_INT3_EOC,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 13/18] mfd: max77836: Add max77836 support to max14577 driver
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add Maxim 77836 support to max14577 driver. The chipsets have same MUIC
component so the extcon, charger and regulators are almost the same. The
max77836 however has also PMIC and Fuel Gauge.
The MAX77836 uses three I2C slave addresses and has additional interrupts
(related to PMIC and Fuel Gauge). It has also Interrupt Source register,
just like MAX77686 and MAX77693.
The MAX77836 PMIC's TOPSYS and INTSRC interrupts are reported in the
PMIC block. The PMIC block has different I2C slave address and uses own
regmap so another regmap_irq_chip is needed.
Since we have two regmap_irq_chip, use shared interrupts on MAX77836.
This patch adds additional defines and functions to the max14577 MFD core
driver so the driver will handle both chipsets.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/mfd/max14577.c | 215 ++++++++++++++++++++++++++++++++--
include/linux/mfd/max14577-private.h | 85 +++++++++++++-
include/linux/mfd/max14577.h | 7 +-
3 files changed, 296 insertions(+), 11 deletions(-)
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 224aba8c5b3f..5b10f6f89834 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -1,7 +1,7 @@
/*
- * max14577.c - mfd core driver for the Maxim 14577
+ * max14577.c - mfd core driver for the Maxim 14577/77836
*
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@@ -37,11 +37,31 @@ static struct mfd_cell max14577_devs[] = {
{ .name = "max14577-charger", },
};
+static struct mfd_cell max77836_devs[] = {
+ {
+ .name = "max77836-muic",
+ .of_compatible = "maxim,max77836-muic",
+ },
+ {
+ .name = "max77836-regulator",
+ .of_compatible = "maxim,max77836-regulator",
+ },
+ { .name = "max77836-charger", },
+ {
+ .name = "max77836-battery",
+ .of_compatible = "maxim,max77836-battery",
+ },
+};
+
static struct of_device_id max14577_dt_match[] = {
{
.compatible = "maxim,max14577",
.data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
},
+ {
+ .compatible = "maxim,max77836",
+ .data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
+ },
{},
};
@@ -56,6 +76,29 @@ static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
+static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* Any max14577 volatile registers are also max77836 volatile. */
+ if (max14577_muic_volatile_reg(dev, reg))
+ return true;
+ switch (reg) {
+ case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
+ case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
+ case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
+ /* fall through */
+ case MAX77836_PMIC_REG_INTSRC:
+ /* fall through */
+ case MAX77836_PMIC_REG_TOPSYS_INT:
+ /* fall through */
+ case MAX77836_PMIC_REG_TOPSYS_STAT:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+
static const struct regmap_config max14577_muic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -63,6 +106,13 @@ static const struct regmap_config max14577_muic_regmap_config = {
.max_register = MAXIM_MUIC_REG_END,
};
+static const struct regmap_config max77836_pmic_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = max77836_muic_volatile_reg,
+ .max_register = MAX77836_PMIC_REG_END,
+};
+
static const struct regmap_irq max14577_irqs[] = {
/* INT1 interrupts */
{ .reg_offset = 0, .mask = MAXIM_INT1_ADC_MASK, },
@@ -91,6 +141,50 @@ static const struct regmap_irq_chip max14577_irq_chip = {
.num_irqs = ARRAY_SIZE(max14577_irqs),
};
+static const struct regmap_irq max77836_muic_irqs[] = {
+ /* INT1 interrupts */
+ { .reg_offset = 0, .mask = MAXIM_INT1_ADC_MASK, },
+ { .reg_offset = 0, .mask = MAXIM_INT1_ADCLOW_MASK, },
+ { .reg_offset = 0, .mask = MAXIM_INT1_ADCERR_MASK, },
+ /* INT2 interrupts */
+ { .reg_offset = 1, .mask = MAXIM_INT2_CHGTYP_MASK, },
+ { .reg_offset = 1, .mask = MAXIM_INT2_CHGDETRUN_MASK, },
+ { .reg_offset = 1, .mask = MAXIM_INT2_DCDTMR_MASK, },
+ { .reg_offset = 1, .mask = MAXIM_INT2_DBCHG_MASK, },
+ { .reg_offset = 1, .mask = MAXIM_INT2_VBVOLT_MASK, },
+ { .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
+ /* INT3 interrupts */
+ { .reg_offset = 2, .mask = MAXIM_INT3_EOC_MASK, },
+ { .reg_offset = 2, .mask = MAXIM_INT3_CGMBC_MASK, },
+ { .reg_offset = 2, .mask = MAXIM_INT3_OVP_MASK, },
+ { .reg_offset = 2, .mask = MAXIM_INT3_MBCCHGERR_MASK, },
+};
+
+static const struct regmap_irq_chip max77836_muic_irq_chip = {
+ .name = "max77836-muic",
+ .status_base = MAXIM_MUIC_REG_INT1,
+ .mask_base = MAXIM_MUIC_REG_INTMASK1,
+ .mask_invert = 1,
+ .num_regs = 3,
+ .irqs = max77836_muic_irqs,
+ .num_irqs = ARRAY_SIZE(max77836_muic_irqs),
+};
+
+static const struct regmap_irq max77836_pmic_irqs[] = {
+ { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
+ { .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
+};
+
+static const struct regmap_irq_chip max77836_pmic_irq_chip = {
+ .name = "max77836-pmic",
+ .status_base = MAX77836_PMIC_REG_TOPSYS_INT,
+ .mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
+ .mask_invert = 0,
+ .num_regs = 1,
+ .irqs = max77836_pmic_irqs,
+ .num_irqs = ARRAY_SIZE(max77836_pmic_irqs),
+};
+
static void max14577_print_dev_type(struct maxim_core *maxim_core)
{
u8 reg_data, vendor_id, device_id;
@@ -111,6 +205,81 @@ static void max14577_print_dev_type(struct maxim_core *maxim_core)
maxim_core->dev_type, device_id, vendor_id);
}
+/*
+ * Max77836 specific initialization code for driver probe.
+ * Adds new I2C dummy device, regmap and regmap IRQ chip.
+ * Unmasks Interrupt Source register.
+ *
+ * On success returns 0.
+ * On failure returns errno and reverts any changes done so far (e.g. remove
+ * I2C dummy device), except masking the INT SRC register.
+ */
+static int max77836_init(struct maxim_core *maxim_core)
+{
+ int ret;
+ u8 intsrc_mask;
+
+ maxim_core->i2c_pmic = i2c_new_dummy(maxim_core->i2c->adapter,
+ I2C_ADDR_PMIC);
+ if (!maxim_core->i2c_pmic) {
+ dev_err(maxim_core->dev, "Failed to register PMIC I2C device\n");
+ return -EPERM;
+ }
+ i2c_set_clientdata(maxim_core->i2c_pmic, maxim_core);
+
+ maxim_core->regmap_pmic = devm_regmap_init_i2c(maxim_core->i2c_pmic,
+ &max77836_pmic_regmap_config);
+ if (IS_ERR(maxim_core->regmap_pmic)) {
+ ret = PTR_ERR(maxim_core->regmap_pmic);
+ dev_err(maxim_core->dev, "Failed to allocate PMIC register map: %d\n",
+ ret);
+ goto err;
+ }
+
+ /* Un-mask MAX77836 Interrupt Source register */
+ ret = max14577_read_reg(maxim_core->regmap_pmic,
+ MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
+ if (ret < 0) {
+ dev_err(maxim_core->dev, "Failed to read PMIC register\n");
+ goto err;
+ }
+
+ intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
+ intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
+ ret = max14577_write_reg(maxim_core->regmap_pmic,
+ MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
+ if (ret < 0) {
+ dev_err(maxim_core->dev, "Failed to write PMIC register\n");
+ goto err;
+ }
+
+ ret = regmap_add_irq_chip(maxim_core->regmap_pmic, maxim_core->irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
+ 0, &max77836_pmic_irq_chip,
+ &maxim_core->irq_data_pmic);
+ if (ret != 0) {
+ dev_err(maxim_core->dev, "Failed to request PMIC IRQ %d: %d\n",
+ maxim_core->irq, ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ i2c_unregister_device(maxim_core->i2c_pmic);
+
+ return ret;
+}
+
+/*
+ * Max77836 specific de-initialization code for driver remove.
+ */
+static void max77836_remove(struct maxim_core *maxim_core)
+{
+ regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data_pmic);
+ i2c_unregister_device(maxim_core->i2c_pmic);
+}
+
static int max14577_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -118,6 +287,10 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
int ret = 0;
+ const struct regmap_irq_chip *irq_chip;
+ struct mfd_cell *mfd_devs;
+ unsigned int mfd_devs_size;
+ int irq_flags;
if (np) {
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
@@ -160,9 +333,24 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
max14577_print_dev_type(maxim_core);
+ switch (maxim_core->dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX77836:
+ irq_chip = &max77836_muic_irq_chip;
+ mfd_devs = max77836_devs;
+ mfd_devs_size = ARRAY_SIZE(max77836_devs);
+ irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
+ break;
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ irq_chip = &max14577_irq_chip;
+ mfd_devs = max14577_devs;
+ mfd_devs_size = ARRAY_SIZE(max14577_devs);
+ irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ break;
+ }
+
ret = regmap_add_irq_chip(maxim_core->regmap_muic, maxim_core->irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
- &max14577_irq_chip,
+ irq_flags, 0, irq_chip,
&maxim_core->irq_data_muic);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
@@ -170,8 +358,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
- ret = mfd_add_devices(maxim_core->dev, -1, max14577_devs,
- ARRAY_SIZE(max14577_devs), NULL, 0,
+ /* Max77836 specific initialization code (additional regmap) */
+ if (maxim_core->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
+ ret = max77836_init(maxim_core);
+ if (ret < 0)
+ goto err_max77836;
+ }
+
+ ret = mfd_add_devices(maxim_core->dev, -1, mfd_devs,
+ mfd_devs_size, NULL, 0,
regmap_irq_get_domain(maxim_core->irq_data_muic));
if (ret < 0)
goto err_mfd;
@@ -181,6 +376,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return 0;
err_mfd:
+ if (maxim_core->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
+ max77836_remove(maxim_core);
+err_max77836:
regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data_muic);
return ret;
@@ -192,12 +390,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(maxim_core->dev);
regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data_muic);
+ if (maxim_core->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
+ max77836_remove(maxim_core);
return 0;
}
static const struct i2c_device_id max14577_i2c_id[] = {
{ "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
+ { "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
{ }
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
@@ -268,5 +469,5 @@ static void __exit max14577_i2c_exit(void)
module_exit(max14577_i2c_exit);
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
-MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver");
+MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index 814bf013d3e8..e0dd27d937d6 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -1,7 +1,7 @@
/*
- * max14577-private.h - Common API for the Maxim 14577 internal sub chip
+ * max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip
*
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@@ -22,9 +22,14 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
+#define I2C_ADDR_PMIC (0x46 >> 1)
+#define I2C_ADDR_MUIC (0x4A >> 1)
+#define I2C_ADDR_FG (0x6C >> 1)
+
enum maxim_device_type {
MAXIM_DEVICE_TYPE_UNKNOWN = 0,
MAXIM_DEVICE_TYPE_MAX14577,
+ MAXIM_DEVICE_TYPE_MAX77836,
MAXIM_DEVICE_TYPE_NUM,
};
@@ -78,6 +83,7 @@ enum maxim_muic_charger_type {
#define MAXIM_INT2_DCDTMR_MASK (0x1 << 2)
#define MAXIM_INT2_DBCHG_MASK (0x1 << 3)
#define MAXIM_INT2_VBVOLT_MASK (0x1 << 4)
+#define MAX77836_INT2_VIDRM_MASK (0x1 << 5)
#define MAXIM_INT3_EOC_MASK (0x1 << 0)
#define MAXIM_INT3_CGMBC_MASK (0x1 << 1)
@@ -94,9 +100,11 @@ enum maxim_muic_charger_type {
#define MAXIM_STATUS1_ADC_SHIFT 0
#define MAXIM_STATUS1_ADCLOW_SHIFT 5
#define MAXIM_STATUS1_ADCERR_SHIFT 6
+#define MAX77836_STATUS1_ADC1K_SHIFT 7
#define MAXIM_STATUS1_ADC_MASK (0x1f << MAXIM_STATUS1_ADC_SHIFT)
#define MAXIM_STATUS1_ADCLOW_MASK (0x1 << MAXIM_STATUS1_ADCLOW_SHIFT)
#define MAXIM_STATUS1_ADCERR_MASK (0x1 << MAXIM_STATUS1_ADCERR_SHIFT)
+#define MAX77836_STATUS1_ADC1K_MASK (0x1 << MAX77836_STATUS1_ADC1K_SHIFT)
/* MAX14577 STATUS2 register */
#define MAXIM_STATUS2_CHGTYP_SHIFT 0
@@ -104,11 +112,13 @@ enum maxim_muic_charger_type {
#define MAXIM_STATUS2_DCDTMR_SHIFT 4
#define MAXIM_STATUS2_DBCHG_SHIFT 5
#define MAXIM_STATUS2_VBVOLT_SHIFT 6
+#define MAX77836_STATUS2_VIDRM_SHIFT 7
#define MAXIM_STATUS2_CHGTYP_MASK (0x7 << MAXIM_STATUS2_CHGTYP_SHIFT)
#define MAXIM_STATUS2_CHGDETRUN_MASK (0x1 << MAXIM_STATUS2_CHGDETRUN_SHIFT)
#define MAXIM_STATUS2_DCDTMR_MASK (0x1 << MAXIM_STATUS2_DCDTMR_SHIFT)
#define MAXIM_STATUS2_DBCHG_MASK (0x1 << MAXIM_STATUS2_DBCHG_SHIFT)
#define MAXIM_STATUS2_VBVOLT_MASK (0x1 << MAXIM_STATUS2_VBVOLT_SHIFT)
+#define MAX77836_STATUS2_VIDRM_MASK (0x1 << MAX77836_STATUS2_VIDRM_SHIFT)
/* MAX14577 STATUS3 register */
#define MAXIM_STATUS3_EOC_SHIFT 0
@@ -232,6 +242,70 @@ enum maxim_muic_charger_type {
+/* Slave addr = 0x46: PMIC */
+enum max77836_pmic_reg {
+ MAX77836_COMP_REG_COMP1 = 0x60,
+
+ MAX77836_LDO_REG_CNFG1_LDO1 = 0x51,
+ MAX77836_LDO_REG_CNFG2_LDO1 = 0x52,
+ MAX77836_LDO_REG_CNFG1_LDO2 = 0x53,
+ MAX77836_LDO_REG_CNFG2_LDO2 = 0x54,
+ MAX77836_LDO_REG_CNFG_LDO_BIAS = 0x55,
+
+ MAX77836_PMIC_REG_PMIC_ID = 0x20,
+ MAX77836_PMIC_REG_PMIC_REV = 0x21,
+ MAX77836_PMIC_REG_INTSRC = 0x22,
+ MAX77836_PMIC_REG_INTSRC_MASK = 0x23,
+ MAX77836_PMIC_REG_TOPSYS_INT = 0x24,
+ MAX77836_PMIC_REG_TOPSYS_INT_MASK = 0x26,
+ MAX77836_PMIC_REG_TOPSYS_STAT = 0x28,
+ MAX77836_PMIC_REG_MRSTB_CNTL = 0x2A,
+ MAX77836_PMIC_REG_LSCNFG = 0x2B,
+
+ MAX77836_PMIC_REG_END,
+};
+
+#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT 1
+#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT 3
+#define MAX77836_INTSRC_MASK_TOP_INT_MASK (0x1 << MAX77836_INTSRC_MASK_TOP_INT_SHIFT)
+#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK (0x1 << MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT)
+
+/* MAX77836 PMIC interrupts */
+#define MAX77836_TOPSYS_INT_T120C_SHIFT 0
+#define MAX77836_TOPSYS_INT_T140C_SHIFT 1
+#define MAX77836_TOPSYS_INT_T120C_MASK (0x1 << MAX77836_TOPSYS_INT_T120C_SHIFT)
+#define MAX77836_TOPSYS_INT_T140C_MASK (0x1 << MAX77836_TOPSYS_INT_T140C_SHIFT)
+
+/* Slave addr = 0x6C: Fuel-Gauge/Battery */
+enum max77836_fg_reg {
+ MAX77836_FG_REG_VCELL_MSB = 0x02,
+ MAX77836_FG_REG_VCELL_LSB = 0x03,
+ MAX77836_FG_REG_SOC_MSB = 0x04,
+ MAX77836_FG_REG_SOC_LSB = 0x05,
+ MAX77836_FG_REG_MODE_H = 0x06,
+ MAX77836_FG_REG_MODE_L = 0x07,
+ MAX77836_FG_REG_VERSION_MSB = 0x08,
+ MAX77836_FG_REG_VERSION_LSB = 0x09,
+ MAX77836_FG_REG_HIBRT_H = 0x0A,
+ MAX77836_FG_REG_HIBRT_L = 0x0B,
+ MAX77836_FG_REG_CONFIG_H = 0x0C,
+ MAX77836_FG_REG_CONFIG_L = 0x0D,
+ MAX77836_FG_REG_VALRT_MIN = 0x14,
+ MAX77836_FG_REG_VALRT_MAX = 0x15,
+ MAX77836_FG_REG_CRATE_MSB = 0x16,
+ MAX77836_FG_REG_CRATE_LSB = 0x17,
+ MAX77836_FG_REG_VRESET = 0x18,
+ MAX77836_FG_REG_FGID = 0x19,
+ MAX77836_FG_REG_STATUS_H = 0x1A,
+ MAX77836_FG_REG_STATUS_L = 0x1B,
+ /*
+ * TODO: TABLE registers
+ * TODO: CMD register
+ */
+
+ MAX77836_FG_REG_END,
+};
+
enum maxim_irq {
/* INT1 */
MAXIM_IRQ_INT1_ADC,
@@ -251,6 +325,10 @@ enum maxim_irq {
MAXIM_IRQ_INT3_OVP,
MAXIM_IRQ_INT3_MBCCHGERR,
+ /* TOPSYS_INT */
+ MAXIM_IRQ_TOPSYS_T140C,
+ MAXIM_IRQ_TOPSYS_T120C,
+
MAXIM_IRQ_NUM,
};
@@ -260,11 +338,14 @@ enum maxim_irq {
struct maxim_core {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
+ struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */
enum maxim_device_type dev_type;
struct regmap *regmap_muic;
+ struct regmap *regmap_pmic;
struct regmap_irq_chip_data *irq_data_muic;
+ struct regmap_irq_chip_data *irq_data_pmic;
int irq;
};
diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h
index 75301be5c548..5e5fc77db977 100644
--- a/include/linux/mfd/max14577.h
+++ b/include/linux/mfd/max14577.h
@@ -1,7 +1,7 @@
/*
- * max14577.h - Driver for the Maxim 14577
+ * max14577.h - Driver for the Maxim 14577/77836
*
- * Copyright (C) 2013 Samsung Electrnoics
+ * Copyright (C) 2013,2014 Samsung Electrnoics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
@@ -20,6 +20,9 @@
* MAX14577 has MUIC, Charger devices.
* The devices share the same I2C bus and interrupt line
* included in this mfd driver.
+ *
+ * MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
+ * addresses.
*/
#ifndef __MAX14577_H__
--
1.7.9.5
^ permalink raw reply related
* [PATCH 12/18] extcon: max14577: Choose muic_irqs according to device type
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
This patch continues the preparation for adding support for max77836
device to existing max14577 driver.
During probe choose muic_irqs according to device type. Currently there
are only "max14577_muic_irqs" but later patch will add max77836
interrupts.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/extcon/extcon-max14577.c | 65 ++++++++++++++++++++++----------------
1 file changed, 37 insertions(+), 28 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index fb343f4042d2..e986a9b92b60 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -39,6 +39,29 @@ enum max14577_muic_status {
MAX14577_MUIC_STATUS_END,
};
+/**
+ * struct max14577_muic_irq
+ * @irq: the index of irq list of MUIC device.
+ * @name: the name of irq.
+ * @virq: the virtual irq to use irq domain
+ */
+struct max14577_muic_irq {
+ unsigned int irq;
+ const char *name;
+ unsigned int virq;
+};
+
+static struct max14577_muic_irq max14577_muic_irqs[] = {
+ { MAXIM_IRQ_INT1_ADC, "muic-ADC" },
+ { MAXIM_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
+ { MAXIM_IRQ_INT1_ADCERR, "muic-ADCError" },
+ { MAXIM_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
+ { MAXIM_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
+ { MAXIM_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
+ { MAXIM_IRQ_INT2_DBCHG, "muic-DBCHG" },
+ { MAXIM_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
+};
+
struct max14577_muic_info {
struct device *dev;
struct maxim_core *maxim_core;
@@ -47,6 +70,8 @@ struct max14577_muic_info {
int prev_chg_type;
u8 status[MAX14577_MUIC_STATUS_END];
+ struct max14577_muic_irq *muic_irqs;
+ unsigned int muic_irqs_num;
bool irq_adc;
bool irq_chg;
struct work_struct irq_work;
@@ -73,29 +98,6 @@ enum max14577_muic_cable_group {
MAX14577_CABLE_GROUP_CHG,
};
-/**
- * struct max14577_muic_irq
- * @irq: the index of irq list of MUIC device.
- * @name: the name of irq.
- * @virq: the virtual irq to use irq domain
- */
-struct max14577_muic_irq {
- unsigned int irq;
- const char *name;
- unsigned int virq;
-};
-
-static struct max14577_muic_irq max14577_muic_irqs[] = {
- { MAXIM_IRQ_INT1_ADC, "muic-ADC" },
- { MAXIM_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
- { MAXIM_IRQ_INT1_ADCERR, "muic-ADCError" },
- { MAXIM_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
- { MAXIM_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
- { MAXIM_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
- { MAXIM_IRQ_INT2_DBCHG, "muic-DBCHG" },
- { MAXIM_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
-};
-
/* Define supported accessory type */
enum max14577_muic_acc_type {
MAX14577_MUIC_ADC_GROUND = 0x0,
@@ -541,9 +543,9 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
*/
- for (i = 0; i < ARRAY_SIZE(max14577_muic_irqs); i++)
- if (irq == max14577_muic_irqs[i].virq)
- irq_type = max14577_muic_irqs[i].irq;
+ for (i = 0; i < info->muic_irqs_num; i++)
+ if (irq == info->muic_irqs[i].virq)
+ irq_type = info->muic_irqs[i].irq;
switch (irq_type) {
case MAXIM_IRQ_INT1_ADC:
@@ -646,9 +648,16 @@ static int max14577_muic_probe(struct platform_device *pdev)
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
+ switch (maxim_core->dev_type) {
+ case MAXIM_DEVICE_TYPE_MAX14577:
+ default:
+ info->muic_irqs = max14577_muic_irqs;
+ info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);
+ }
+
/* Support irq domain for max14577 MUIC device */
- for (i = 0; i < ARRAY_SIZE(max14577_muic_irqs); i++) {
- struct max14577_muic_irq *muic_irq = &max14577_muic_irqs[i];
+ for (i = 0; i < info->muic_irqs_num; i++) {
+ struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
unsigned int virq = 0;
virq = regmap_irq_get_virq(maxim_core->irq_data_muic,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 11/18] extcon: max14577: Add max14577 prefix to muic_irqs
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
Add max14577 prefix to muic_irqs array. This prepares for max77836
support in this extcon driver.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/extcon/extcon-max14577.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index fd48b4909470..fb343f4042d2 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -85,7 +85,7 @@ struct max14577_muic_irq {
unsigned int virq;
};
-static struct max14577_muic_irq muic_irqs[] = {
+static struct max14577_muic_irq max14577_muic_irqs[] = {
{ MAXIM_IRQ_INT1_ADC, "muic-ADC" },
{ MAXIM_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
{ MAXIM_IRQ_INT1_ADCERR, "muic-ADCError" },
@@ -541,9 +541,9 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
* However we only need to know whether it was ADC, charger
* or both interrupts so decode IRQ and turn on proper flags.
*/
- for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
- if (irq == muic_irqs[i].virq)
- irq_type = muic_irqs[i].irq;
+ for (i = 0; i < ARRAY_SIZE(max14577_muic_irqs); i++)
+ if (irq == max14577_muic_irqs[i].virq)
+ irq_type = max14577_muic_irqs[i].irq;
switch (irq_type) {
case MAXIM_IRQ_INT1_ADC:
@@ -647,8 +647,8 @@ static int max14577_muic_probe(struct platform_device *pdev)
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
/* Support irq domain for max14577 MUIC device */
- for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
- struct max14577_muic_irq *muic_irq = &muic_irqs[i];
+ for (i = 0; i < ARRAY_SIZE(max14577_muic_irqs); i++) {
+ struct max14577_muic_irq *muic_irq = &max14577_muic_irqs[i];
unsigned int virq = 0;
virq = regmap_irq_get_virq(maxim_core->irq_data_muic,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 10/18] mfd: max14577: Add detection of device type
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
This patch continues the preparation for adding support for max77836
device to existing max14577 driver.
Add enum for types of devices supported by this driver. The device type
will be detected by matching of_device_id, or i2c_device_id as a
fallback.
The patch also moves to separate function the code related to displaying
DeviceID register values.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/mfd/max14577.c | 61 +++++++++++++++++++++++-----------
include/linux/mfd/max14577-private.h | 12 ++++---
2 files changed, 50 insertions(+), 23 deletions(-)
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 1d8104213b3e..224aba8c5b3f 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max14577.h>
#include <linux/mfd/max14577-private.h>
@@ -36,6 +37,14 @@ static struct mfd_cell max14577_devs[] = {
{ .name = "max14577-charger", },
};
+static struct of_device_id max14577_dt_match[] = {
+ {
+ .compatible = "maxim,max14577",
+ .data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
+ },
+ {},
+};
+
static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -82,13 +91,32 @@ static const struct regmap_irq_chip max14577_irq_chip = {
.num_irqs = ARRAY_SIZE(max14577_irqs),
};
+static void max14577_print_dev_type(struct maxim_core *maxim_core)
+{
+ u8 reg_data, vendor_id, device_id;
+ int ret = max14577_read_reg(maxim_core->regmap_muic,
+ MAXIM_MUIC_REG_DEVICEID, ®_data);
+ if (ret) {
+ dev_err(maxim_core->dev, "Failed to read DEVICEID register: %d\n",
+ ret);
+ return;
+ }
+
+ vendor_id = ((reg_data & MAXIM_DEVID_VENDORID_MASK) >>
+ MAXIM_DEVID_VENDORID_SHIFT);
+ device_id = ((reg_data & MAXIM_DEVID_DEVICEID_MASK) >>
+ MAXIM_DEVID_DEVICEID_SHIFT);
+
+ dev_info(maxim_core->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
+ maxim_core->dev_type, device_id, vendor_id);
+}
+
static int max14577_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct maxim_core *maxim_core;
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
- u8 reg_data;
int ret = 0;
if (np) {
@@ -121,19 +149,16 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return ret;
}
- ret = max14577_read_reg(maxim_core->regmap_muic,
- MAXIM_MUIC_REG_DEVICEID, ®_data);
- if (ret) {
- dev_err(maxim_core->dev, "Device not found on this channel: %d\n",
- ret);
- return ret;
+ if (np) {
+ const struct of_device_id *of_id =
+ of_match_device(max14577_dt_match, &i2c->dev);
+ if (of_id)
+ maxim_core->dev_type = (unsigned int)of_id->data;
+ } else {
+ maxim_core->dev_type = id->driver_data;
}
- maxim_core->vendor_id = ((reg_data & MAXIM_DEVID_VENDORID_MASK) >>
- MAXIM_DEVID_VENDORID_SHIFT);
- maxim_core->device_id = ((reg_data & MAXIM_DEVID_DEVICEID_MASK) >>
- MAXIM_DEVID_DEVICEID_SHIFT);
- dev_info(maxim_core->dev, "Device ID: 0x%x, vendor: 0x%x\n",
- maxim_core->device_id, maxim_core->vendor_id);
+
+ max14577_print_dev_type(maxim_core);
ret = regmap_add_irq_chip(maxim_core->regmap_muic, maxim_core->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
@@ -172,7 +197,7 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id max14577_i2c_id[] = {
- { "max14577", 0 },
+ { "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
{ }
};
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
@@ -213,11 +238,6 @@ static int max14577_resume(struct device *dev)
return 0;
}
-static struct of_device_id max14577_dt_match[] = {
- { .compatible = "maxim,max14577", },
- {},
-};
-
static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
static struct i2c_driver max14577_i2c_driver = {
@@ -234,6 +254,9 @@ static struct i2c_driver max14577_i2c_driver = {
static int __init max14577_i2c_init(void)
{
+ BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
+ BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
+
return i2c_add_driver(&max14577_i2c_driver);
}
subsys_initcall(max14577_i2c_init);
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index 6cf417dc030c..814bf013d3e8 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -22,6 +22,13 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
+enum maxim_device_type {
+ MAXIM_DEVICE_TYPE_UNKNOWN = 0,
+ MAXIM_DEVICE_TYPE_MAX14577,
+
+ MAXIM_DEVICE_TYPE_NUM,
+};
+
/* Slave addr = 0x4A: MUIC and Charger */
enum maxim_muic_reg {
MAXIM_MUIC_REG_DEVICEID = 0x00,
@@ -253,15 +260,12 @@ enum maxim_irq {
struct maxim_core {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
+ enum maxim_device_type dev_type;
struct regmap *regmap_muic;
struct regmap_irq_chip_data *irq_data_muic;
int irq;
-
- /* Device ID */
- u8 vendor_id; /* Vendor Identification */
- u8 device_id; /* Chip Version */
};
/* MAX14577 shared regmap API function */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 09/18] mfd: max14577: Add "muic" suffix to regmap and irq_chip
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
This patch continues the preparation for adding support for max77836
device to existing max14577 driver.
Add "muic" suffix to regmap and irq_data fields in maxim_core state
container to prepare for max77836 support.
This is only a rename-like patch, new code is not added.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/extcon/extcon-max14577.c | 17 +++++++++--------
drivers/mfd/max14577.c | 22 +++++++++++-----------
drivers/power/max14577_charger.c | 8 ++++----
drivers/regulator/max14577.c | 2 +-
include/linux/mfd/max14577-private.h | 4 ++--
5 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 2879cc5844dc..fd48b4909470 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -176,7 +176,7 @@ static int max14577_muic_set_debounce_time(struct max14577_muic_info *info,
case ADC_DEBOUNCE_TIME_10MS:
case ADC_DEBOUNCE_TIME_25MS:
case ADC_DEBOUNCE_TIME_38_62MS:
- ret = max14577_update_reg(info->maxim_core->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_CONTROL3,
MAXIM_CONTROL3_ADCDBSET_MASK,
time << MAXIM_CONTROL3_ADCDBSET_SHIFT);
@@ -210,7 +210,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
u8 ctrl1, ctrl2 = 0;
/* Set open state to path before changing hw path */
- ret = max14577_update_reg(info->maxim_core->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_CONTROL1,
MAXIM_CONTROL1_CLEAR_IDBEN_MICEN_MASK,
MAXIM_CONTROL1_SW_OPEN);
@@ -224,7 +224,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
else
ctrl1 = MAXIM_CONTROL1_SW_OPEN;
- ret = max14577_update_reg(info->maxim_core->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_CONTROL1,
MAXIM_CONTROL1_CLEAR_IDBEN_MICEN_MASK, ctrl1);
if (ret < 0) {
@@ -237,7 +237,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
else
ctrl2 |= MAXIM_CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
- ret = max14577_update_reg(info->maxim_core->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_CONTROL2,
MAXIM_CONTROL2_LOWPWR_MASK | MAXIM_CONTROL2_CPEN_MASK,
ctrl2);
@@ -505,7 +505,7 @@ static void max14577_muic_irq_work(struct work_struct *work)
mutex_lock(&info->mutex);
- ret = max14577_bulk_read(info->maxim_core->regmap,
+ ret = max14577_bulk_read(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_STATUS1, info->status, 2);
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
@@ -581,7 +581,7 @@ static int max14577_muic_detect_accessory(struct max14577_muic_info *info)
mutex_lock(&info->mutex);
/* Read STATUSx register to detect accessory */
- ret = max14577_bulk_read(info->maxim_core->regmap,
+ ret = max14577_bulk_read(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_STATUS1, info->status, 2);
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
@@ -651,7 +651,8 @@ static int max14577_muic_probe(struct platform_device *pdev)
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
unsigned int virq = 0;
- virq = regmap_irq_get_virq(maxim_core->irq_data, muic_irq->irq);
+ virq = regmap_irq_get_virq(maxim_core->irq_data_muic,
+ muic_irq->irq);
if (!virq)
return -EINVAL;
muic_irq->virq = virq;
@@ -693,7 +694,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
max14577_muic_set_path(info, info->path_uart, true);
/* Check revision number of MUIC device*/
- ret = max14577_read_reg(info->maxim_core->regmap,
+ ret = max14577_read_reg(info->maxim_core->regmap_muic,
MAXIM_MUIC_REG_DEVICEID, &id);
if (ret < 0) {
dev_err(&pdev->dev, "failed to read revision number\n");
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index f160e582712d..1d8104213b3e 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -112,17 +112,17 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
maxim_core->i2c = i2c;
maxim_core->irq = i2c->irq;
- maxim_core->regmap = devm_regmap_init_i2c(i2c,
- &max14577_muic_regmap_config);
- if (IS_ERR(maxim_core->regmap)) {
- ret = PTR_ERR(maxim_core->regmap);
+ maxim_core->regmap_muic = devm_regmap_init_i2c(i2c,
+ &max14577_muic_regmap_config);
+ if (IS_ERR(maxim_core->regmap_muic)) {
+ ret = PTR_ERR(maxim_core->regmap_muic);
dev_err(maxim_core->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
- ret = max14577_read_reg(maxim_core->regmap, MAXIM_MUIC_REG_DEVICEID,
- ®_data);
+ ret = max14577_read_reg(maxim_core->regmap_muic,
+ MAXIM_MUIC_REG_DEVICEID, ®_data);
if (ret) {
dev_err(maxim_core->dev, "Device not found on this channel: %d\n",
ret);
@@ -135,10 +135,10 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
dev_info(maxim_core->dev, "Device ID: 0x%x, vendor: 0x%x\n",
maxim_core->device_id, maxim_core->vendor_id);
- ret = regmap_add_irq_chip(maxim_core->regmap, maxim_core->irq,
+ ret = regmap_add_irq_chip(maxim_core->regmap_muic, maxim_core->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
&max14577_irq_chip,
- &maxim_core->irq_data);
+ &maxim_core->irq_data_muic);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
maxim_core->irq, ret);
@@ -147,7 +147,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(maxim_core->dev, -1, max14577_devs,
ARRAY_SIZE(max14577_devs), NULL, 0,
- regmap_irq_get_domain(maxim_core->irq_data));
+ regmap_irq_get_domain(maxim_core->irq_data_muic));
if (ret < 0)
goto err_mfd;
@@ -156,7 +156,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return 0;
err_mfd:
- regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data);
+ regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data_muic);
return ret;
}
@@ -166,7 +166,7 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
struct maxim_core *maxim_core = i2c_get_clientdata(i2c);
mfd_remove_devices(maxim_core->dev);
- regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data);
+ regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data_muic);
return 0;
}
diff --git a/drivers/power/max14577_charger.c b/drivers/power/max14577_charger.c
index 335c42a13136..58cddc3b15d6 100644
--- a/drivers/power/max14577_charger.c
+++ b/drivers/power/max14577_charger.c
@@ -31,7 +31,7 @@ struct max14577_charger {
static int max14577_get_charger_state(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->maxim_core->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap_muic;
int state = POWER_SUPPLY_STATUS_DISCHARGING;
u8 reg_data;
@@ -87,7 +87,7 @@ static int max14577_get_charge_type(struct max14577_charger *chg)
static int max14577_get_online(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->maxim_core->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap_muic;
u8 reg_data;
max14577_read_reg(rmap, MAXIM_MUIC_REG_STATUS2, ®_data);
@@ -116,7 +116,7 @@ static int max14577_get_online(struct max14577_charger *chg)
*/
static int max14577_get_battery_health(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->maxim_core->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap_muic;
int state = POWER_SUPPLY_HEALTH_GOOD;
u8 reg_data;
@@ -156,7 +156,7 @@ static int max14577_get_present(struct max14577_charger *chg)
*/
static void max14577_charger_reg_init(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->maxim_core->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap_muic;
u8 reg_data;
/*
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index ead56ec819b5..8856c660a5da 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -206,7 +206,7 @@ static int max14577_regulator_probe(struct platform_device *pdev)
return ret;
config.dev = &pdev->dev;
- config.regmap = maxim_core->regmap;
+ config.regmap = maxim_core->regmap_muic;
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
struct regulator_dev *regulator;
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index 3fdc32b583be..6cf417dc030c 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -254,9 +254,9 @@ struct maxim_core {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
- struct regmap *regmap;
+ struct regmap *regmap_muic;
- struct regmap_irq_chip_data *irq_data;
+ struct regmap_irq_chip_data *irq_data_muic;
int irq;
/* Device ID */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 08/18] mfd: max14577: Rename state container to maxim_core
From: Krzysztof Kozlowski @ 2014-01-28 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390911522-28209-1-git-send-email-k.kozlowski@samsung.com>
This patch continues the preparation for adding support for max77836
device to existing max14577 driver.
The patch renames the struct "max14577" state container to "maxim_core".
This is only a rename-like patch, new code is not added.
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
---
drivers/extcon/extcon-max14577.c | 22 +++++------
drivers/mfd/max14577.c | 68 +++++++++++++++++-----------------
drivers/power/max14577_charger.c | 16 ++++----
drivers/regulator/max14577.c | 6 +--
include/linux/mfd/max14577-private.h | 5 ++-
5 files changed, 60 insertions(+), 57 deletions(-)
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index 6f7145a929cf..2879cc5844dc 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -41,7 +41,7 @@ enum max14577_muic_status {
struct max14577_muic_info {
struct device *dev;
- struct max14577 *max14577;
+ struct maxim_core *maxim_core;
struct extcon_dev *edev;
int prev_cable_type;
int prev_chg_type;
@@ -176,7 +176,7 @@ static int max14577_muic_set_debounce_time(struct max14577_muic_info *info,
case ADC_DEBOUNCE_TIME_10MS:
case ADC_DEBOUNCE_TIME_25MS:
case ADC_DEBOUNCE_TIME_38_62MS:
- ret = max14577_update_reg(info->max14577->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap,
MAXIM_MUIC_REG_CONTROL3,
MAXIM_CONTROL3_ADCDBSET_MASK,
time << MAXIM_CONTROL3_ADCDBSET_SHIFT);
@@ -210,7 +210,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
u8 ctrl1, ctrl2 = 0;
/* Set open state to path before changing hw path */
- ret = max14577_update_reg(info->max14577->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap,
MAXIM_MUIC_REG_CONTROL1,
MAXIM_CONTROL1_CLEAR_IDBEN_MICEN_MASK,
MAXIM_CONTROL1_SW_OPEN);
@@ -224,7 +224,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
else
ctrl1 = MAXIM_CONTROL1_SW_OPEN;
- ret = max14577_update_reg(info->max14577->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap,
MAXIM_MUIC_REG_CONTROL1,
MAXIM_CONTROL1_CLEAR_IDBEN_MICEN_MASK, ctrl1);
if (ret < 0) {
@@ -237,7 +237,7 @@ static int max14577_muic_set_path(struct max14577_muic_info *info,
else
ctrl2 |= MAXIM_CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */
- ret = max14577_update_reg(info->max14577->regmap,
+ ret = max14577_update_reg(info->maxim_core->regmap,
MAXIM_MUIC_REG_CONTROL2,
MAXIM_CONTROL2_LOWPWR_MASK | MAXIM_CONTROL2_CPEN_MASK,
ctrl2);
@@ -505,7 +505,7 @@ static void max14577_muic_irq_work(struct work_struct *work)
mutex_lock(&info->mutex);
- ret = max14577_bulk_read(info->max14577->regmap,
+ ret = max14577_bulk_read(info->maxim_core->regmap,
MAXIM_MUIC_REG_STATUS1, info->status, 2);
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
@@ -581,7 +581,7 @@ static int max14577_muic_detect_accessory(struct max14577_muic_info *info)
mutex_lock(&info->mutex);
/* Read STATUSx register to detect accessory */
- ret = max14577_bulk_read(info->max14577->regmap,
+ ret = max14577_bulk_read(info->maxim_core->regmap,
MAXIM_MUIC_REG_STATUS1, info->status, 2);
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
@@ -626,7 +626,7 @@ static void max14577_muic_detect_cable_wq(struct work_struct *work)
static int max14577_muic_probe(struct platform_device *pdev)
{
- struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
+ struct maxim_core *maxim_core = dev_get_drvdata(pdev->dev.parent);
struct max14577_muic_info *info;
int delay_jiffies;
int ret;
@@ -639,7 +639,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
return -ENOMEM;
}
info->dev = &pdev->dev;
- info->max14577 = max14577;
+ info->maxim_core = maxim_core;
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
@@ -651,7 +651,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
unsigned int virq = 0;
- virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
+ virq = regmap_irq_get_virq(maxim_core->irq_data, muic_irq->irq);
if (!virq)
return -EINVAL;
muic_irq->virq = virq;
@@ -693,7 +693,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
max14577_muic_set_path(info, info->path_uart, true);
/* Check revision number of MUIC device*/
- ret = max14577_read_reg(info->max14577->regmap,
+ ret = max14577_read_reg(info->maxim_core->regmap,
MAXIM_MUIC_REG_DEVICEID, &id);
if (ret < 0) {
dev_err(&pdev->dev, "failed to read revision number\n");
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index a054f6f6c16d..f160e582712d 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -85,7 +85,7 @@ static const struct regmap_irq_chip max14577_irq_chip = {
static int max14577_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct max14577 *max14577;
+ struct maxim_core *maxim_core;
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
u8 reg_data;
@@ -103,70 +103,70 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
return -EINVAL;
}
- max14577 = devm_kzalloc(&i2c->dev, sizeof(*max14577), GFP_KERNEL);
- if (!max14577)
+ maxim_core = devm_kzalloc(&i2c->dev, sizeof(*maxim_core), GFP_KERNEL);
+ if (!maxim_core)
return -ENOMEM;
- i2c_set_clientdata(i2c, max14577);
- max14577->dev = &i2c->dev;
- max14577->i2c = i2c;
- max14577->irq = i2c->irq;
+ i2c_set_clientdata(i2c, maxim_core);
+ maxim_core->dev = &i2c->dev;
+ maxim_core->i2c = i2c;
+ maxim_core->irq = i2c->irq;
- max14577->regmap = devm_regmap_init_i2c(i2c,
- &max14577_muic_regmap_config);
- if (IS_ERR(max14577->regmap)) {
- ret = PTR_ERR(max14577->regmap);
- dev_err(max14577->dev, "Failed to allocate register map: %d\n",
+ maxim_core->regmap = devm_regmap_init_i2c(i2c,
+ &max14577_muic_regmap_config);
+ if (IS_ERR(maxim_core->regmap)) {
+ ret = PTR_ERR(maxim_core->regmap);
+ dev_err(maxim_core->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
- ret = max14577_read_reg(max14577->regmap, MAXIM_MUIC_REG_DEVICEID,
+ ret = max14577_read_reg(maxim_core->regmap, MAXIM_MUIC_REG_DEVICEID,
®_data);
if (ret) {
- dev_err(max14577->dev, "Device not found on this channel: %d\n",
+ dev_err(maxim_core->dev, "Device not found on this channel: %d\n",
ret);
return ret;
}
- max14577->vendor_id = ((reg_data & MAXIM_DEVID_VENDORID_MASK) >>
+ maxim_core->vendor_id = ((reg_data & MAXIM_DEVID_VENDORID_MASK) >>
MAXIM_DEVID_VENDORID_SHIFT);
- max14577->device_id = ((reg_data & MAXIM_DEVID_DEVICEID_MASK) >>
+ maxim_core->device_id = ((reg_data & MAXIM_DEVID_DEVICEID_MASK) >>
MAXIM_DEVID_DEVICEID_SHIFT);
- dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n",
- max14577->device_id, max14577->vendor_id);
+ dev_info(maxim_core->dev, "Device ID: 0x%x, vendor: 0x%x\n",
+ maxim_core->device_id, maxim_core->vendor_id);
- ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
+ ret = regmap_add_irq_chip(maxim_core->regmap, maxim_core->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
&max14577_irq_chip,
- &max14577->irq_data);
+ &maxim_core->irq_data);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
- max14577->irq, ret);
+ maxim_core->irq, ret);
return ret;
}
- ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
+ ret = mfd_add_devices(maxim_core->dev, -1, max14577_devs,
ARRAY_SIZE(max14577_devs), NULL, 0,
- regmap_irq_get_domain(max14577->irq_data));
+ regmap_irq_get_domain(maxim_core->irq_data));
if (ret < 0)
goto err_mfd;
- device_init_wakeup(max14577->dev, 1);
+ device_init_wakeup(maxim_core->dev, 1);
return 0;
err_mfd:
- regmap_del_irq_chip(max14577->irq, max14577->irq_data);
+ regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data);
return ret;
}
static int max14577_i2c_remove(struct i2c_client *i2c)
{
- struct max14577 *max14577 = i2c_get_clientdata(i2c);
+ struct maxim_core *maxim_core = i2c_get_clientdata(i2c);
- mfd_remove_devices(max14577->dev);
- regmap_del_irq_chip(max14577->irq, max14577->irq_data);
+ mfd_remove_devices(maxim_core->dev);
+ regmap_del_irq_chip(maxim_core->irq, maxim_core->irq_data);
return 0;
}
@@ -180,10 +180,10 @@ MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
static int max14577_suspend(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
- struct max14577 *max14577 = i2c_get_clientdata(i2c);
+ struct maxim_core *maxim_core = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
- enable_irq_wake(max14577->irq);
+ enable_irq_wake(maxim_core->irq);
/*
* MUIC IRQ must be disabled during suspend if this is
* a wake up source because it will be handled before
@@ -194,7 +194,7 @@ static int max14577_suspend(struct device *dev)
* Interrupt handler tries to read registers but this read
* will fail because I2C is still suspended.
*/
- disable_irq(max14577->irq);
+ disable_irq(maxim_core->irq);
}
return 0;
@@ -203,11 +203,11 @@ static int max14577_suspend(struct device *dev)
static int max14577_resume(struct device *dev)
{
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
- struct max14577 *max14577 = i2c_get_clientdata(i2c);
+ struct maxim_core *maxim_core = i2c_get_clientdata(i2c);
if (device_may_wakeup(dev)) {
- disable_irq_wake(max14577->irq);
- enable_irq(max14577->irq);
+ disable_irq_wake(maxim_core->irq);
+ enable_irq(maxim_core->irq);
}
return 0;
diff --git a/drivers/power/max14577_charger.c b/drivers/power/max14577_charger.c
index 66a4e4edea42..335c42a13136 100644
--- a/drivers/power/max14577_charger.c
+++ b/drivers/power/max14577_charger.c
@@ -21,8 +21,8 @@
#include <linux/mfd/max14577-private.h>
struct max14577_charger {
- struct device *dev;
- struct max14577 *max14577;
+ struct device *dev;
+ struct maxim_core *maxim_core;
struct power_supply charger;
unsigned int charging_state;
@@ -31,7 +31,7 @@ struct max14577_charger {
static int max14577_get_charger_state(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->max14577->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap;
int state = POWER_SUPPLY_STATUS_DISCHARGING;
u8 reg_data;
@@ -87,7 +87,7 @@ static int max14577_get_charge_type(struct max14577_charger *chg)
static int max14577_get_online(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->max14577->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap;
u8 reg_data;
max14577_read_reg(rmap, MAXIM_MUIC_REG_STATUS2, ®_data);
@@ -116,7 +116,7 @@ static int max14577_get_online(struct max14577_charger *chg)
*/
static int max14577_get_battery_health(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->max14577->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap;
int state = POWER_SUPPLY_HEALTH_GOOD;
u8 reg_data;
@@ -156,7 +156,7 @@ static int max14577_get_present(struct max14577_charger *chg)
*/
static void max14577_charger_reg_init(struct max14577_charger *chg)
{
- struct regmap *rmap = chg->max14577->regmap;
+ struct regmap *rmap = chg->maxim_core->regmap;
u8 reg_data;
/*
@@ -262,7 +262,7 @@ static int max14577_charger_get_property(struct power_supply *psy,
static int max14577_charger_probe(struct platform_device *pdev)
{
struct max14577_charger *chg;
- struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
+ struct maxim_core *maxim_core = dev_get_drvdata(pdev->dev.parent);
int ret;
chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
@@ -271,7 +271,7 @@ static int max14577_charger_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chg);
chg->dev = &pdev->dev;
- chg->max14577 = max14577;
+ chg->maxim_core = maxim_core;
max14577_charger_reg_init(chg);
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index e65d61bb200f..ead56ec819b5 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -196,8 +196,8 @@ static inline struct device_node *match_of_node(int index)
static int max14577_regulator_probe(struct platform_device *pdev)
{
- struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
- struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
+ struct maxim_core *maxim_core = dev_get_drvdata(pdev->dev.parent);
+ struct max14577_platform_data *pdata = dev_get_platdata(maxim_core->dev);
int i, ret;
struct regulator_config config = {};
@@ -206,7 +206,7 @@ static int max14577_regulator_probe(struct platform_device *pdev)
return ret;
config.dev = &pdev->dev;
- config.regmap = max14577->regmap;
+ config.regmap = maxim_core->regmap;
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
struct regulator_dev *regulator;
diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h
index 9f5ce26cb54e..3fdc32b583be 100644
--- a/include/linux/mfd/max14577-private.h
+++ b/include/linux/mfd/max14577-private.h
@@ -247,7 +247,10 @@ enum maxim_irq {
MAXIM_IRQ_NUM,
};
-struct max14577 {
+/*
+ * State container for max14577-like drivers.
+ */
+struct maxim_core {
struct device *dev;
struct i2c_client *i2c; /* Slave addr = 0x4A */
--
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