* [PATCH net-next v5 08/10] net: bcmgenet: hook into the build system
From: Florian Fainelli @ 2014-02-14 0:08 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q, devicetree-u79uwXL29TY76Z2rM5mHXA,
cernekee-Re5JQEeQqe8AvxtiuMwx3w, mark.rutland-5wv7dgnIgG8,
romieu-W8zweXLXuWQS+FvcfC7Uqw, Florian Fainelli
In-Reply-To: <1392336531-28875-1-git-send-email-f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This patch adds a new configuration symbol: CONFIG_BCMGENET which allows
us to build the Broadcom GENET driver and hook the driver files into the
build system.
Signed-off-by: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
Changes in v5:
- add a dependency on CONFIG_OF
Changes in v4:
- fixed Kconfig dependency against FIXED_PHY which can only be
selected if BCMGENET is not modular
Changes in v1, v2, v3:
- rebased against net-next/master
drivers/net/ethernet/broadcom/Kconfig | 11 +++++++++++
drivers/net/ethernet/broadcom/Makefile | 1 +
drivers/net/ethernet/broadcom/genet/Makefile | 2 ++
3 files changed, 14 insertions(+)
create mode 100644 drivers/net/ethernet/broadcom/genet/Makefile
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 3f97d9f..85dbddd 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -60,6 +60,17 @@ config BCM63XX_ENET
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
+config BCMGENET
+ tristate "Broadcom GENET internal MAC support"
+ depends on OF
+ select MII
+ select PHYLIB
+ select FIXED_PHY if BCMGENET=y
+ select BCM7XXX_PHY
+ help
+ This driver supports the built-in Ethernet MACs found in the
+ Broadcom BCM7xxx Set Top Box family chipset.
+
config BNX2
tristate "Broadcom NetXtremeII support"
depends on PCI
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 68efa1a..fd639a0 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_BCMGENET) += genet/
obj-$(CONFIG_BNX2) += bnx2.o
obj-$(CONFIG_CNIC) += cnic.o
obj-$(CONFIG_BNX2X) += bnx2x/
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile
new file mode 100644
index 0000000..31f55a9
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/genet/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BCMGENET) += genet.o
+genet-objs := bcmgenet.o bcmmii.o
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH net-next v5 09/10] Documentation: add Device tree bindings for Broadcom GENET
From: Florian Fainelli @ 2014-02-14 0:08 UTC (permalink / raw)
To: netdev; +Cc: davem, devicetree, cernekee, mark.rutland, romieu,
Florian Fainelli
In-Reply-To: <1392336531-28875-1-git-send-email-f.fainelli@gmail.com>
This patch adds the Device Tree bindings for the Broadcom GENET Gigabit
Ethernet controller. A bunch of examples are provided to illustrate the
versatile aspect of the hardare.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v5:
- respin due to the CONFIG_OF dependency fix
Changes in v4:
- respin due to the Kconfig dependency
Changes in v3
- improve compatible property description to specify all compatible strings
supported
- move MDIO bus node to a separate section, to separate from the properties
- detail which exact phy-mode strings are supported and that this refers to
the ePAPR 'phy-connection-type' modes
- fixed MDIO bus node compatible string to match what is really provided by
the bootloader and use the same details as for the GENET compatible string
- add address-cells and size-cells required properties for the GENET device
tree node
- add a better description for the 'fixed-link' property with reference to
existing binding documentation
- add a reference to the Ethernet PHY device tree binding
- add a description for the interrupts properties
- add a documentation for the optional clocks properties
- removed unused and deprecated device_type properties
Changes in v2:
- rebased against net-next/master
.../devicetree/bindings/net/broadcom-bcmgenet.txt | 121 +++++++++++++++++++++
1 file changed, 121 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
diff --git a/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt b/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
new file mode 100644
index 0000000..afd31f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
@@ -0,0 +1,121 @@
+* Broadcom BCM7xxx Ethernet Controller (GENET)
+
+Required properties:
+- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
+ "brcm,genet-v3", "brcm,genet-v4".
+- reg: address and length of the register set for the device
+- interrupts: must be two cells, the first cell is the general purpose
+ interrupt line, while the second cell is the interrupt for the ring
+ RX and TX queues operating in ring mode
+- phy-mode: String, operation mode of the PHY interface. Supported values are
+ "mii", "rgmii", "rgmii-txid", "rev-mii", "moca". Analogous to ePAPR
+ "phy-connection-type" values
+- address-cells: should be 1
+- size-cells: should be 1
+
+Optional properties:
+- clocks: When provided, must be two cells, first one is the main GENET clock
+ and the second cell is the Genet Wake-on-LAN clock.
+
+- phy-handle: A phandle to a phy node defining the PHY address (as the reg
+ property, a single integer), used to describe configurations where a PHY
+ (internal or external) is used.
+
+- fixed-link: When the GENET interface is connected to a MoCA hardware block or
+ when operating in a RGMII to RGMII type of connection, or when the MDIO bus is
+ voluntarily disabled, this property should be used to describe the "fixed link".
+ See Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for information on
+ the property specifics
+
+Required child nodes:
+
+- mdio bus node: this node should always be present regarless of the PHY
+ configuration of the GENET instance
+
+MDIO bus node required properties:
+
+- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
+ "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
+ parent node compatible property (e.g: brcm,genet-v4 pairs with
+ brcm,genet-mdio-v4)
+- reg: address and length relative to the parent node base register address
+- address-cells: address cell for MDIO bus addressing, should be 1
+- size-cells: size of the cells for MDIO bus addressing, should be 0
+
+Ethernet PHY node properties:
+
+See Documentation/devicetree/bindings/net/phy.txt for the list of required and
+optional properties.
+
+Internal Gigabit PHY example:
+
+ethernet@f0b60000 {
+ phy-mode = "internal";
+ phy-handle = <&phy1>;
+ mac-address = [ 00 10 18 36 23 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0b60000 0xfc4c>;
+ interrupts = <0x0 0x14 0x0>, <0x0 0x15 0x0>;
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy1: ethernet-phy@1 {
+ max-speed = <1000>;
+ reg = <0x1>;
+ compatible = "brcm,28nm-gphy", "ethernet-phy-ieee802.3-c22";
+ };
+ };
+};
+
+MoCA interface / MAC to MAC example:
+
+ethernet@f0b80000 {
+ phy-mode = "moca";
+ fixed-link = <1 0 1000 0 0>;
+ mac-address = [ 00 10 18 36 24 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0b80000 0xfc4c>;
+ interrupts = <0x0 0x16 0x0>, <0x0 0x17 0x0>;
+
+ mdio@e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+ };
+};
+
+
+External MDIO-connected Gigabit PHY/switch:
+
+ethernet@f0ba0000 {
+ phy-mode = "rgmii";
+ phy-handle = <&phy0>;
+ mac-address = [ 00 10 18 36 26 1a ];
+ compatible = "brcm,genet-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ reg = <0xf0ba0000 0xfc4c>;
+ interrupts = <0x0 0x18 0x0>, <0x0 0x19 0x0>;
+
+ mdio@0e14 {
+ compatible = "brcm,genet-mdio-v4";
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+ reg = <0xe14 0x8>;
+
+ phy0: ethernet-phy@0 {
+ max-speed = <1000>;
+ reg = <0x0>;
+ compatible = "brcm,bcm53125", "ethernet-phy-ieee802.3-c22";
+ };
+ };
+};
--
1.8.3.2
^ permalink raw reply related
* [PATCH net-next v5 10/10] MAINTAINERS: add entry for the Broadcom GENET driver
From: Florian Fainelli @ 2014-02-14 0:08 UTC (permalink / raw)
To: netdev; +Cc: davem, devicetree, cernekee, mark.rutland, romieu,
Florian Fainelli
In-Reply-To: <1392336531-28875-1-git-send-email-f.fainelli@gmail.com>
Add myself as a maintainer of the Broadcom GENET driver.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
Changes in v5:
- respin due to the CONFIG_OF dependency fix
Changes in v4:
- respin due to the Kconfig dependency fix
Changes in v2, v3:
- rebased against latest net-next/master
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 091b50e..5a7b3ec 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1845,6 +1845,12 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/b44.*
+BROADCOM GENET ETHERNET DRIVER
+M: Florian Fainelli <f.fainelli@gmail.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: drivers/net/ethernet/broadcom/genet/
+
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH RESEND v2 00/12] clk/exynos convert clock IDs to macros
From: Kukjin Kim @ 2014-02-14 0:10 UTC (permalink / raw)
To: Mike Turquette
Cc: Tomasz Figa, moderated list:OPEN FIRMWARE AND..., Kukjin Kim,
Andrzej Hajda, Kyungmin Park, moderated list:ARM/S5P EXYNOS AR...,
linux-arm-kernel
In-Reply-To: <20140127214944.4167.58042@quantum>
On 01/28/14 06:49, Mike Turquette wrote:
> Quoting Tomasz Figa (2014-01-07 07:17:22)
>> Hi Mike,
>>
>> On Tuesday 07 of January 2014 15:47:28 Andrzej Hajda wrote:
>>> Hi,
>>>
>>> This patch set adds header files with macros defining exynos clocks.
>>> Then it converts dts files and drivers to use macros instead
>>> of magic numbers or enums to describe clock bindings.
>>>
>>> The patch set is rebased on the latest samsung-clk/samsung-next branch.
>>>
>>> The patches are generated by script.
>>> Many clocks I have verified by hand.
>>> I have also tested it successfully on exynos4 based board.
>>>
>>> This is the 2nd version of the patchset.
>>> Changes:
>>> - corrected devicetree mailing list,
>>> - added comments to include/dt-bindings/clock/exynos4.h for
>>> clocks present only in particular chip,
>>> - added tab alignement in headers,
>>> - added comment to CLK_NR_CLKS,
>>> - added copyright headers,
>>> - split long lines in dts,
>>> - corrected example in bindings/clock/exynos5250-clock.txt, to point
>>> appropriate clocks.
>>
>> I believe this has been already acked before, so could you still take
>> it for 3.14? For now I'd merge only the patches adding headers and
>> updating clock drivers to avoid merge conflicts and then after
>> release of 3.14-rc1 we could early merge dts patches for 3.15.
>
> Hi Tomasz,
>
> Let's go ahead and merge this after 3.14-rc1. I'll take it in when that
> drops and the DTS data will go in during the same merge window.
>
Hi Mike,
As I talked to Tomasz, would be better to us if this series could be
handled in Samsung tree so I'm going to do it. How do you think?
- Kukjin
^ permalink raw reply
* Re: [PATCH RESEND v2 00/12] clk/exynos convert clock IDs to macros
From: Kukjin Kim @ 2014-02-14 0:17 UTC (permalink / raw)
To: Kukjin Kim
Cc: Mike Turquette, Tomasz Figa, moderated list:OPEN FIRMWARE AND...,
Andrzej Hajda, Kyungmin Park, moderated list:ARM/S5P EXYNOS AR...,
linux-arm-kernel
In-Reply-To: <52FD5EDA.60909@samsung.com>
On 02/14/14 09:10, Kukjin Kim wrote:
> On 01/28/14 06:49, Mike Turquette wrote:
>> Quoting Tomasz Figa (2014-01-07 07:17:22)
>>> Hi Mike,
>>>
>>> On Tuesday 07 of January 2014 15:47:28 Andrzej Hajda wrote:
>>>> Hi,
>>>>
>>>> This patch set adds header files with macros defining exynos clocks.
>>>> Then it converts dts files and drivers to use macros instead
>>>> of magic numbers or enums to describe clock bindings.
>>>>
>>>> The patch set is rebased on the latest samsung-clk/samsung-next branch.
>>>>
>>>> The patches are generated by script.
>>>> Many clocks I have verified by hand.
>>>> I have also tested it successfully on exynos4 based board.
>>>>
>>>> This is the 2nd version of the patchset.
>>>> Changes:
>>>> - corrected devicetree mailing list,
>>>> - added comments to include/dt-bindings/clock/exynos4.h for
>>>> clocks present only in particular chip,
>>>> - added tab alignement in headers,
>>>> - added comment to CLK_NR_CLKS,
>>>> - added copyright headers,
>>>> - split long lines in dts,
>>>> - corrected example in bindings/clock/exynos5250-clock.txt, to point
>>>> appropriate clocks.
>>>
>>> I believe this has been already acked before, so could you still take
>>> it for 3.14? For now I'd merge only the patches adding headers and
>>> updating clock drivers to avoid merge conflicts and then after
>>> release of 3.14-rc1 we could early merge dts patches for 3.15.
>>
>> Hi Tomasz,
>>
>> Let's go ahead and merge this after 3.14-rc1. I'll take it in when that
>> drops and the DTS data will go in during the same merge window.
>>
>
> Hi Mike,
>
> As I talked to Tomasz, would be better to us if this series could be
> handled in Samsung tree so I'm going to do it. How do you think?
>
Oops, already merged into mainline ;-)
Sorry, please kindly ignore my previous e-mail.
Thanks,
Kukjin
^ permalink raw reply
* Re: [PATCH RFC v3 3/3] Documentation: arm: define DT idle states bindings
From: Sebastian Capella @ 2014-02-14 0:29 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: Mark Rutland, Mike Turquette, Tomasz Figa, Mark Hambleton,
Russell King, Nicolas Pitre, Daniel Lezcano,
linux-arm-kernel@lists.infradead.org, grant.likely@linaro.org,
Dave P Martin, Charles Garcia-Tobin, devicetree@vger.kernel.org,
Kevin Hilman, linux-pm@vger.kernel.org, Kumar Gala, Rob Herring,
Vincent Guittot, Antti Miettinen, pveerapa@broadcom.com,
Peter De Schrijver
In-Reply-To: <20140213124731.GD26329@e102568-lin.cambridge.arm.com>
Quoting Lorenzo Pieralisi (2014-02-13 04:47:32)
> Such as ? "idle-states" ?
That sounds good to me. Our preference is for idle-states to be used
for name of the idle-states.txt node.
> > During last connect, we'd discussed that the small set of
> > states here could apply to a single node, which can represent a cpu, a
> > cluster with cache etc. Then the complexities of the system power state
> > would be represented using a heirarchy, with each node in the
> > tree having its own state from the list above. This would allow
> > a fairly rich system state while having just a few power states defined
> > at each level. Is this how you're intending these bindings to go?
>
> Yes, CPUs point at states that can be reached by that CPU (eg a CPU core
> gating state is represented by a single node pointed at by all CPUs in the
> system - it the same state data, different power domains though).
>
> States are hierarchical, which means that a parent state implies entry on all
> substates that's how cluster states are defined.
The cpu 0 node, in its cpu-idle-state array is also pointing at a cluster
node right? STATE0 -> power-domains refers to <pd_clusters 0>. Is it
correct that if the cpu's workload is such that it tolerates the
500/1000/2500 entry/exit latency/min-residency, it will call the
entry-method with the psci-power-state of 0x10100000 matching that node?
> > Also, would it be nice to have a name field for each state?
>
> There is:
>
> "The state node name shall be "stateN", where N = {0, 1, ...} is
> the node number; state nodes which are siblings within a single
> common parent node must be given a unique and sequential N value,
> starting from 0."
> I can remove the rule and allow people to call states as they wish
> since they already have a compatible property to match them.
>
> Actually, states can be called with any name, provided it is unique.
Sorry, I was referring to a descriptive name string property. Something
that can be useful to help a human understand what's going on. Naming
the nodes might work too.
> > > + A state node can contain state child nodes. A state node with
> > > + children represents a hierarchical state, which is a superset of
> > > + the child states. Hierarchical states require all CPUs on which
> > > + they are valid to request the state in order for it to be entered.
> >
> > Is it possible for a cpu to request a deeper state and unblock other cpus
> > from entering this state?
>
> That's not DT bindings business, hierarchical states define states that
> require all CPUs on which they are valid to enter that state for it to
> be considered "enabled".
>
> It is a hard nut to crack. In x86 this stuff does not exist and it is
> managed in HW, basically an idle state is always per-cpu (but it might
> end up becoming a package state when all CPUs in a package enter that
> state). On ARM, we want to define hierarchical states explicitly to
> link resources (ie caches) to them.
>
> CPUs are not prevented from requesting a hierarchical state, but the
> state only becomes "enabled" when all CPUs on which it is valid request
> it.
The way we've seen it work, is a cpu tries to enter the lowest state it can
tolerate (including for eg. cluster off). The system level code then looks
at the allowable states from all the cpus and selects the lowest power
state permissible for the heirarchies.
Eg. this way, the last cpu preventing a cluster from going to sleep enters
cluster sleep state (where peer cpu's have already voted for cluster
sleep) and the cluster will sleep. Alternately if the same cpu cannot
tolerate the additional latency of the cluster sleeping, it will vote
only for cpu-sleep, then the cluster remains in a state where all cpu's are
sleeping but the cluster remains up.
> I cannot think of any other way of to express this properly but still in
> a compact way.
You're doing a great job by the way! Thanks! :)
> > "all CPUs on which they are valid" is this determined by seeing which
> > state's phandle is in each cpu->cpu-idle-states?
>
> Yes, does it make sense ?
Yup, maybe adding a little parenthetical text like below may help others
as well?
Hierarchical states require all CPUs on which they are valid (ie. CPU nodes
containing cpu-idle-state arrays having a phandle reference to the state)
to request the state in order for it to be entered.
>
> > Definition: It represents an idle state index.
> >
> > Index 0 and 1 shall not be specified and are reserved for ARM
> > states where index 0 is running, and index 1 is idle_standby
> > entered by executing a wfi instruction (SBSA,[3])
> >
> > What mechanism is used to order the power states WRT power consumption?
>
> I think we should use index for that. The higher the index the lower the
> power consumption.
Ok, I think I get it now.
If we decouple index and SBSA states, do we really need to reserve index
0 and 1 then?
> > Can this field be used to combine both psci and non-psci states in any order?
>
> No. I will enforce a unique entry method.
So a single entry-method for all states in idle-states node?
Should this be specified once only then?
Should we not allow more flexibility here to mix methods where some
states use one method and some use others? Is this mostly a security
concern? What if a vendor wants to introduce a state between wfi and
cpu-sleep?
> > I assume psci will be turning off the powerdomains not Linux right?
>
> This is not a PSCI only document, and even if it was, we still need to deal
> with devices. Which means we need to know what we have to save/restore (PMU,
> arch timer, GIC), and power domains help us detect that.
> > > +
> > > +cpus {
> > > + #size-cells = <0>;
> > > + #address-cells = <2>;
> > > +
> > > + cpu-idle-states {
> > > +
> > > + STATE0: state0 {
> > > + compatible = "arm,cpu-idle-state";
> > > + index = <3>;
> >
> > Are the index fields of nested states independent of each other or
> > sequential?
> ...
> I understand index is misleading and either I remove it, or I
> leave it there to define power savings scale as you mentioned.
I like index, but I was confused. You cleared it up pretty quick with
your earlier comment. Removing the numbering may help, but I think
keeping the index is useful.
Thanks!
Sebastian
^ permalink raw reply
* Re: [PATCH] of: give priority to the compatible match in __of_match_node()
From: Kevin Hao @ 2014-02-14 1:20 UTC (permalink / raw)
To: Rob Herring
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linuxppc-dev,
Sebastian Hesselbarth, Stephen N Chivers, Chris Proctor,
Arnd Bergmann, Scott Wood, Grant Likely, Rob Herring
In-Reply-To: <CAL_JsqKMi2H=vwoxrOt8QRA2xJeiLqBKKfLtt4QRCRoFk6JUHg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1540 bytes --]
On Thu, Feb 13, 2014 at 01:01:42PM -0600, Rob Herring wrote:
> On Wed, Feb 12, 2014 at 5:38 AM, Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > When the device node do have a compatible property, we definitely
> > prefer the compatible match besides the type and name. Only if
> > there is no such a match, we then consider the candidate which
> > doesn't have compatible entry but do match the type or name with
> > the device node.
> >
> > This is based on a patch from Sebastian Hesselbarth.
> > http://patchwork.ozlabs.org/patch/319434/
> >
> > I did some code refactoring and also fixed a bug in the original patch.
>
> I'm inclined to just revert this once again and avoid possibly
> breaking yet another platform.
>
> However, I think I would like to see this structured differently. We
> basically have 2 ways of matching: the existing pre-3.14 way and the
> desired match on best compatible only. All new bindings should match
> with the new way and the old way needs to be kept for compatibility.
> So lets structure the code that way. Search the match table first for
> best compatible with name and type NULL, then search the table the old
> way. I realize it appears you are doing this, but it is not clear this
> is the intent of the code. I would like to see this written as a patch
> with commit 105353145eafb3ea919 reverted first and you add a new match
> function to call first and then fallback to the existing function.
OK, I will git it a try.
Thanks,
Kevin
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: [PATCH] ARM: dts: omap3 clocks: simplify ssi aliases
From: Sebastian Reichel @ 2014-02-14 1:25 UTC (permalink / raw)
To: Tony Lindgren; +Cc: Tero Kristo, mturquette, bcousson, linux-omap, devicetree
In-Reply-To: <20140213224914.GD28216@atomide.com>
[-- Attachment #1: Type: text/plain, Size: 658 bytes --]
On Thu, Feb 13, 2014 at 02:49:14PM -0800, Tony Lindgren wrote:
> * Sebastian Reichel <sre@debian.org> [140121 06:39]:
> > update aliases for the ssi clocks ssi_ssr_fck, ssi_sst_fck and ssi_ick
> > to make them consistent for omap34xx and omap36xx. This makes it
> > possible to reference the clocks from generic omap3 dts files.
>
> Is this needed as a fix for v3.14-rc? If so, please let me know
> and ack if you want me to take it.
The SSI driver will not arrive before 3.15 and 3.14 dts files do not
contain any SSI nodes.
Thus it should be enough to queue it for 3.15 if it goes via the
same tree as the SSI dts patches.
-- Sebastian
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH V2 2/3] ARM: dts: add dts files for exynos5260 SoC
From: Rahul Sharma @ 2014-02-14 3:24 UTC (permalink / raw)
To: Tomasz Figa
Cc: Tomasz Figa, Rahul Sharma, linux-samsung-soc, Kukjin Kim,
sunil joshi, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Rob Herring, Mark Rutland,
Grant Likely, Ian Campbell, Pawel Moll, Kumar Gala
In-Reply-To: <52F9F59D.1090905@gmail.com>
Thanks Tomasz,
I will add these changes to v3.
Regards,
Rahul Sharma.
On 11 February 2014 15:34, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Rahul,
>
>
> On 11.02.2014 06:22, Rahul Sharma wrote:
>>
>> Hi Tomasz,
>>
>> On 6 February 2014 18:51, Tomasz Figa <t.figa@samsung.com> wrote:
>>>
>>> Hi Rahul, Pankaj, Arun,
>>>
>>> [adding linux-arm-kernel, devicetree MLs and DT people on Cc]
>>>
>>> I think it's good time to stop accepting DTS files like this and force
>>> new
>>> ones to use the proper structure with soc node, labels for every node and
>>> node references.
>>
>>
>> I am unable to find information on SoC node and grouping inside SoC node.
>> Please
>> share some pointers.
>
>
> Well, there is not much information needed about this. Basically all the
> devices built into the SoC should be listed under respective bus nodes or a
> single soc node, instead of root level. Such node should be a "simple-bus"
> and just group the components together to separate board-specific devices
> (which are still at root level) from SoC devices.
>
> Even though it might seem useless, it improves DT readability a bit and
> still most of the platforms use this approach, so for consistency, Exynos
> should use too.
>
> Just for reference, back in April 2013, in his review of S3C64xx DT series
> [1], Rob Herring requested that we don't submit any new device trees using
> flat approach and start using bus hierarchy.
>
> [1]
> http://lists.infradead.org/pipermail/linux-arm-kernel/2013-April/163659.html
>
>
>>>
>>>> + spi0_bus: spi0-bus {
>>>> + samsung,pins = "gpa2-0", "gpa2-1", "gpa2-2",
>>>> "gpa2-3";
>>>
>>>
>>>
>>> What is the reason for SPI0 to have 4 pins, while SPI1 has just 3?
>>>
>>
>> I should align SPI1 with SPI0.
>>
>
> Are you sure that SPI0 is the correct one? SPI usually uses four pins - SDI,
> SDO, SCK and nCS, but we always used to treat nCS as a simple GPIO, due to
> the fact that the controller can only support one dedicated chip select and
> with direct GPIO control you can have more.
>
> What is the fourth pin here?
>
>
>>>
>>>> + cpu@1 {
>>>> + device_type = "cpu";
>>>> + compatible = "arm,cortex-a15";
>>>> + reg = <1>;
>>>> + cci-control-port = <&cci_control1>;
>>>> + };
>>>> + cpu@100 {
>>>> + device_type = "cpu";
>>>> + compatible = "arm,cortex-a7";
>>>> + reg = <0x100>;
>>>> + cci-control-port = <&cci_control0>;
>>>> + };
>>>> + cpu@101 {
>>>> + device_type = "cpu";
>>>> + compatible = "arm,cortex-a7";
>>>> + reg = <0x101>;
>>>> + cci-control-port = <&cci_control0>;
>>>> + };
>>>> + cpu@102 {
>>>> + device_type = "cpu";
>>>> + compatible = "arm,cortex-a7";
>>>> + reg = <0x102>;
>>>> + cci-control-port = <&cci_control0>;
>>>> + };
>>>> + cpu@103 {
>>>> + device_type = "cpu";
>>>> + compatible = "arm,cortex-a7";
>>>> + reg = <0x103>;
>>>> + cci-control-port = <&cci_control0>;
>>>> + };
>>>> + };
>>>> +
>>>> + cmus {
>>>> + #address-cells = <1>;
>>>> + #size-cells = <1>;
>>>> + ranges;
>>>> +
>>>
>>>
>>>
>>> I don't think there is a need to group these nodes under a parent node
>>> that
>>> doesn't give any additional information, especially when the CMUs are
>>> scattered trough the whole address space, while we'd like to keep the
>>> nodes
>>> ordered by their addresses, as most platforms do.
>>>
>>
>> This is exactly the same case as "cpus". I mean, "cpus" also doesn't
>> provide
>> any common information about child cpu nodes. This looks to me as a
>> logical
>> grouping and I have implemented same thing for cmu nodes.
>> I am ok with removing this grouping Just want to understand the rational
>> behind
>> grouping cpus which seems similar to cmus.
>
>
> The "cpus" node is a defined standard node that should be present at root of
> device tree and include subnodes for all CPUs. This is a standard binding
> defined for low level code to be able to simply find nodes of all CPUs in
> the system - so they can expect that at /cpus node all the subnodes are
> subsequent CPUs.
>
>
>> Similarly "soc" is just a logical entity used to group SoC elements which
>> looks
>> optional to me. What are we achieving with this? Please help me in
>> understanding
>> this better.
>
>
> Also "soc" has a slightly wider meaning. It is a node grouping all nodes
> from a single address space - the node specifies #address-cells and
> #size-cells of this address space and all the devices under this
> "simple-bus" can be accessed using addresses in this format. In addition, it
> separates board-level devices from generic SoC devices.
>
> Now, in case of "cmus", the only purpose is to group all CMU nodes together
> and, while this improves readability a bit, it doesn't make the DT better
> express the hardware topology, because the CMUs in the hardware are in fact
> scattered through the whole address space, not under a contiguous block of
> it, as the grouping would suggest.
>
> Best regards,
> Tomasz
^ permalink raw reply
* [PATCH 0/2] of: fix a regression when trying to find the best compatible match
From: Kevin Hao @ 2014-02-14 5:22 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
Cc: Kevin Hao, Sebastian Hesselbarth, Stephen N Chivers, Grant Likely,
Rob Herring
Hi,
This fix a regression when trying to find the best compatible match. You can
find the detail of the issue reported by Stephen Chivers at:
https://lists.ozlabs.org/pipermail/linuxppc-dev/2014-February/115278.html
I have made a patch to fix this previously.
http://patchwork.ozlabs.org/patch/319624/
This is another respin with the implementation suggested by Rob Herring.
Kevin Hao (2):
Revert "OF: base: match each node compatible against all given matches
first"
of: search the best compatible match first in __of_match_node()
drivers/of/base.c | 88 ++++++++++++++++++++++++++++++++++---------------------
1 file changed, 54 insertions(+), 34 deletions(-)
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/2] Revert "OF: base: match each node compatible against all given matches first"
From: Kevin Hao @ 2014-02-14 5:22 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
Cc: Kevin Hao, Sebastian Hesselbarth, Stephen N Chivers, Grant Likely,
Rob Herring
In-Reply-To: <1392355366-1445-1-git-send-email-haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This reverts commit 105353145eafb3ea919f5cdeb652a9d8f270228e.
Stephen Chivers reported this is broken as we will get a match
entry '.type = "serial"' instead of the '.compatible = "ns16550"'
in the following scenario:
serial0: serial@4500 {
compatible = "fsl,ns16550", "ns16550";
}
struct of_device_id of_platform_serial_table[] = {
{ .compatible = "ns8250", .data = (void *)PORT_8250, },
{ .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .compatible = "ns16550a", .data = (void *)PORT_16550A, },
{ .compatible = "ns16550", .data = (void *)PORT_16550, },
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
...
{ .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ /* end of list */ },
};
So just revert this patch, we will use another implementation to find
the best compatible match in a follow-on patch.
Reported-by: Stephen N Chivers <schivers-znpAAEhiOVUQrrorzV6ljw@public.gmane.org>
Cc: Sebastian Hesselbarth <sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/of/base.c | 53 ++++++++++++++++-------------------------------------
1 file changed, 16 insertions(+), 37 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ff85450d5683..ba195fbce4c6 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -734,42 +734,24 @@ static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
- const char *cp;
- int cplen, l;
-
if (!matches)
return NULL;
- cp = __of_get_property(node, "compatible", &cplen);
- do {
- const struct of_device_id *m = matches;
-
- /* Check against matches with current compatible string */
- while (m->name[0] || m->type[0] || m->compatible[0]) {
- int match = 1;
- if (m->name[0])
- match &= node->name
- && !strcmp(m->name, node->name);
- if (m->type[0])
- match &= node->type
- && !strcmp(m->type, node->type);
- if (m->compatible[0])
- match &= cp
- && !of_compat_cmp(m->compatible, cp,
- strlen(m->compatible));
- if (match)
- return m;
- m++;
- }
-
- /* Get node's next compatible string */
- if (cp) {
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
- } while (cp && (cplen > 0));
-
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= node->name
+ && !strcmp(matches->name, node->name);
+ if (matches->type[0])
+ match &= node->type
+ && !strcmp(matches->type, node->type);
+ if (matches->compatible[0])
+ match &= __of_device_is_compatible(node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
return NULL;
}
@@ -778,10 +760,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
- * Low level utility function used by device matching. Matching order
- * is to compare each of the node's compatibles with all given matches
- * first. This implies node's compatible is sorted from specific to
- * generic while matches can be in any order.
+ * Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/2] of: search the best compatible match first in __of_match_node()
From: Kevin Hao @ 2014-02-14 5:22 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ
Cc: Kevin Hao, Sebastian Hesselbarth, Stephen N Chivers, Grant Likely,
Rob Herring
In-Reply-To: <1392355366-1445-1-git-send-email-haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Currently, of_match_node compares each given match against all node's
compatible strings with of_device_is_compatible.
To achieve multiple compatible strings per node with ordering from
specific to generic, this requires given matches to be ordered from
specific to generic. For most of the drivers this is not true and also
an alphabetical ordering is more sane there.
Therefore, this patch introduces a function to match each of the node's
compatible strings against all given compatible matches without type and
name first, before checking the next compatible string. This implies
that node's compatibles are ordered from specific to generic while
given matches can be in any order. If we fail to find such a match
entry, then fall-back to the old method in order to keep compatibility.
Cc: Sebastian Hesselbarth <sebastian.hesselbarth-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Kevin Hao <haokexin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/of/base.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ba195fbce4c6..10b51106c854 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -730,13 +730,49 @@ out:
}
EXPORT_SYMBOL(of_find_node_with_property);
+static const struct of_device_id *
+of_match_compatible(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ const char *cp;
+ int cplen, l;
+ const struct of_device_id *m;
+
+ cp = __of_get_property(node, "compatible", &cplen);
+ while (cp && (cplen > 0)) {
+ m = matches;
+ while (m->name[0] || m->type[0] || m->compatible[0]) {
+ /* Only match for the entries without type and name */
+ if (m->name[0] || m->type[0] ||
+ of_compat_cmp(m->compatible, cp,
+ strlen(m->compatible)))
+ m++;
+ else
+ return m;
+ }
+
+ /* Get node's next compatible string */
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return NULL;
+}
+
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
+ const struct of_device_id *m;
+
if (!matches)
return NULL;
+ m = of_match_compatible(matches, node);
+ if (m)
+ return m;
+
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
@@ -760,7 +796,12 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
- * Low level utility function used by device matching.
+ * Low level utility function used by device matching. We have two ways
+ * of matching:
+ * - Try to find the best compatible match by comparing each compatible
+ * string of device node with all the given matches respectively.
+ * - If the above method failed, then try to match the compatible by using
+ * __of_device_is_compatible() besides the match in type and name.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH net-next v5 00/10] Support for the Broadcom GENET driver
From: David Miller @ 2014-02-14 5:29 UTC (permalink / raw)
To: f.fainelli-Re5JQEeQqe8AvxtiuMwx3w
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
cernekee-Re5JQEeQqe8AvxtiuMwx3w, mark.rutland-5wv7dgnIgG8,
romieu-W8zweXLXuWQS+FvcfC7Uqw
In-Reply-To: <1392336531-28875-1-git-send-email-f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Thu, 13 Feb 2014 16:08:41 -0800
> This patchset adds support for the Broadcom GENET Gigabit Ethernet MAC
> controller. This controller is found on the Broadcom BCM7xxx Set Top Box
> System-on-a-chips.
>
> Changes since v4:
> - add dependency on CONFIG_OF
>
> Changes since v3:
> - fixed Kconfig dependency on FIXED_PHY
>
> Changes since v2:
> - dropped the patch that adds an "internal" phy-mode
Series applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V2 0/2] mmc: omap_hsmmc: fix for pre es3.0 OMAP3
From: Nishanth Menon @ 2014-02-14 5:45 UTC (permalink / raw)
To: Tony Lindgren, Balaji T K, Chris Ball
Cc: linux-mmc, linux-omap, linux-kernel, linux-doc, linux-arm-kernel,
devicetree, Felipe Balbi, Nishanth Menon
Originally reported in: https://patchwork.kernel.org/patch/3514851/
https://patchwork.kernel.org/patch/3514881/
ES3.0+ provides MMC controller which is fixed for multi-block reads,
however LDP platform
Looking at the various IP revision register information:
sdp2430: Revision: 1.2, Spec: 0.0, normal interrupt
OMAP3430-ldp: (ES2.1): Revision: 2.6, Spec: 0.0, normal interrupt
SDP3430:(ES3.0) Revision: 2.6, Spec: 0.0, normal interrupt
AM3517-evm: (ES1.1): Revision: 2.6, Spec: 0.0, normal interrupt
AM3517-crane:(ES1.1): Revision: 2.6, Spec: 0.0, normal interrupt
AM37x-evm: (ES1.2) Revision: 2.6, Spec: 0.0, normal interrupt
OMAP3630-beag-xm (ES1.2): Revision: 2.6, Spec: 0.0, normal interrupt
am335x-evm:(ES1.0): Revision: 3.1, Spec: 0.1, normal interrupt
am335x-sk: (ES2.1): Revision: 3.1, Spec: 0.1, normal interrupt
am335x-beaglebone-black:(ES2.0): Revision: 3.1, Spec: 0.1, normal
interrupt
sdp4430: (ES2.2): Revision: 3.1, Spec: 0.1, normal interrupt
OMAP4460-panda-es (ES1.1): Revision: 3.1, Spec: 0.1, normal interrupt
OMAP5uevm:(ES2.0): Revision: 3.3, Spec: 0.2, normal interrupt
dra7-evm (es1.1): Revision: 3.3, Spec: 0.2, normal interrupt
This series has been tested on the following platforms:
1: BeagleBoard-XM: Boot PASS: http://slexy.org/raw/s2ObUDfm5N
2: BeagleBone-Black: Boot PASS: http://slexy.org/raw/s2xmviGgFf
3: dra7: Boot PASS: http://slexy.org/raw/s2Ad6rxaQk
4: ldp: Boot PASS: http://slexy.org/raw/s20kEx9eHg
5: PandaBoard-ES: Boot PASS: http://slexy.org/raw/s2gHT1EWKF
6: sdp2430: Boot PASS: http://slexy.org/raw/s20dvr8yQA (nfs)
7: sdp3430: Boot PASS: http://slexy.org/raw/s2aUEsEemS
8: sdp4430: Boot PASS: http://slexy.org/raw/s20nqL8gjz
9: OMAP5432uEVM: Boot PASS: http://slexy.org/raw/s20O0QfmZw
TOTAL = 9 boards, Booted Boards = 9, No Boot boards = 0
LDP platform prior to the series reports: http://slexy.org/raw/s20qVg17T0
Series is based on v3.14-rc2
Nishanth Menon (2):
mmc: omap_hsmmc: Add support for quirky omap3 hsmmc controller
ARM: dts: omap3-ldp: fix mmc configuration
.../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 1 +
arch/arm/boot/dts/omap3-ldp.dts | 23 +++++++++++++++++
drivers/mmc/host/omap_hsmmc.c | 26 +++++++++++++++++---
3 files changed, 46 insertions(+), 4 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH V2 1/2] mmc: omap_hsmmc: Add support for quirky omap3 hsmmc controller
From: Nishanth Menon @ 2014-02-14 5:45 UTC (permalink / raw)
To: Tony Lindgren, Balaji T K, Chris Ball
Cc: linux-mmc, linux-omap, linux-kernel, linux-doc, linux-arm-kernel,
devicetree, Felipe Balbi, Nishanth Menon
In-Reply-To: <1392356749-32091-1-git-send-email-nm@ti.com>
When device is booted using devicetree, platforms impacted by Erratum
2.1.1.128 is not detected easily in the mmc driver. This erratum
indicates that the module cannot do multi-block transfers. Platforms
such as LDP which use OMAP3 ES revision prior to ES3.0 are impacted by
this.
Provide a new compatible property "ti,omap3-pre-es3-hsmmc" to allow
driver to determine if driver needs to implement quirks associated
with the specific module version (primarily because the IP revision
information is not sufficient for the same).
Signed-off-by: Nishanth Menon <nm@ti.com>
---
Changes since v1:
- new compatible flag as suggested by Tony which contains
the relevant controller flag to work around the erratum
V1: https://patchwork.kernel.org/patch/3514851/
.../devicetree/bindings/mmc/ti-omap-hsmmc.txt | 1 +
drivers/mmc/host/omap_hsmmc.c | 26 +++++++++++++++++---
2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
index 8c8908a..ce80561 100644
--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
@@ -10,6 +10,7 @@ Required properties:
- compatible:
Should be "ti,omap2-hsmmc", for OMAP2 controllers
Should be "ti,omap3-hsmmc", for OMAP3 controllers
+ Should be "ti,omap3-pre-es3-hsmmc" for OMAP3 controllers pre ES3.0
Should be "ti,omap4-hsmmc", for OMAP4 controllers
- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 575f9cc..390f421 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -192,6 +192,11 @@ struct omap_hsmmc_host {
struct omap_mmc_platform_data *pdata;
};
+struct omap_mmc_of_data {
+ u32 reg_offset;
+ u8 controller_flags;
+};
+
static int omap_hsmmc_card_detect(struct device *dev, int slot)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -1678,18 +1683,29 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
#endif
#ifdef CONFIG_OF
-static u16 omap4_reg_offset = 0x100;
+static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
+ /* See 35xx errata 2.1.1.128 in SPRZ278F */
+ .controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
+};
+
+static const struct omap_mmc_of_data omap4_mmc_of_data = {
+ .reg_offset = 0x100,
+};
static const struct of_device_id omap_mmc_of_match[] = {
{
.compatible = "ti,omap2-hsmmc",
},
{
+ .compatible = "ti,omap3-pre-es3-hsmmc",
+ .data = &omap3_pre_es3_mmc_of_data,
+ },
+ {
.compatible = "ti,omap3-hsmmc",
},
{
.compatible = "ti,omap4-hsmmc",
- .data = &omap4_reg_offset,
+ .data = &omap4_mmc_of_data,
},
{},
};
@@ -1759,6 +1775,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
dma_cap_mask_t mask;
unsigned tx_req, rx_req;
struct pinctrl *pinctrl;
+ const struct omap_mmc_of_data *data;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) {
@@ -1768,8 +1785,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return PTR_ERR(pdata);
if (match->data) {
- const u16 *offsetp = match->data;
- pdata->reg_offset = *offsetp;
+ data = match->data;
+ pdata->reg_offset = data->reg_offset;
+ pdata->controller_flags |= data->controller_flags;
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 2/2] ARM: dts: omap3-ldp: fix mmc configuration
From: Nishanth Menon @ 2014-02-14 5:45 UTC (permalink / raw)
To: Tony Lindgren, Balaji T K, Chris Ball
Cc: linux-mmc, linux-omap, linux-kernel, linux-doc, linux-arm-kernel,
devicetree, Felipe Balbi, Nishanth Menon
In-Reply-To: <1392356749-32091-1-git-send-email-nm@ti.com>
MMC1 is the only MMC interface available on the platform. Further,
since the platform is based on older revision of SoC which is not
capable of doing multi-block reads, mark it with compatibility for the
same and add pinmux to ensure that all relevant pins are configured
for non-MMC boot mode.
Signed-off-by: Nishanth Menon <nm@ti.com>
---
Changes since V1:
- fixed commit message as suggested by Balaji.
- update to use new compatible match for the erratum.
V1: https://patchwork.kernel.org/patch/3514881/
arch/arm/boot/dts/omap3-ldp.dts | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index ddce0d8..0abe986 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -174,8 +174,20 @@
};
&mmc1 {
+ /* See 35xx errata 2.1.1.128 in SPRZ278F */
+ compatible = "ti,omap3-pre-es3-hsmmc";
vmmc-supply = <&vmmc1>;
bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+};
+
+&mmc2 {
+ status="disabled";
+};
+
+&mmc3 {
+ status="disabled";
};
&omap3_pmx_core {
@@ -209,6 +221,17 @@
0x174 (PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */
>;
};
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.mmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.mmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.mmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214A, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.mmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214C, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.mmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.mmc1_dat3 */
+ >;
+ };
};
&usb_otg_hs {
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] mmc: omap_hsmmc: Add support for Erratum 2.1.1.128 in device tree boot
From: Nishanth Menon @ 2014-02-14 5:48 UTC (permalink / raw)
To: Tony Lindgren
Cc: Balaji T K, Chris Ball, devicetree, linux-mmc, linux-omap,
linux-arm-kernel
In-Reply-To: <20140213230554.GI28216@atomide.com>
On 02/13/2014 05:05 PM, Tony Lindgren wrote:
> * Nishanth Menon <nm@ti.com> [140205 06:15]:
>> On Wed 05 Feb 2014 08:10:34 AM CST, Balaji T K wrote:
>>>>>
>>>>> Rather than ti,errata.. specific property, something like
>>>>> caps no/disable multiblock read is more readable in my opinion, Otherwise
>>>>
>>>> Is'nt the better definition to state i have quirk X and allow the
>>>> driver to do the necessary thing/things needed to handle quirk X? in
>>>> this case, there is just one thing to do: broken multi_block_read, in
>>>> the case of other quirks, there might be more than 1 thing to do.. let
>>>> driver figure that out, dts just states the h/w capabilty or in this
>>>> case, the quirk capability.
>>>>
>>>
>>> But in this case there is only one. disable multi block read is more readable
>>> than the errata reference, No strong feelings though.
>>
>> Considering this might set an precedence for other quirk description,
>> I'd like to leave it as it stands.
>
> Hmm if this really depends on the hardware version, how about
> just add new compatible flag ti,omap3430-rev-xyz-hsmmc that
> allows the driver to deal with the errata?
>
yep - that is a very good idea. updated v2 series tested and posted:
http://marc.info/?l=linux-omap&m=139235682727541&w=2
https://patchwork.kernel.org/patch/3650061/
https://patchwork.kernel.org/patch/3650031/
--
Regards,
Nishanth Menon
^ permalink raw reply
* [PATCH 1/2] clk: fixed-rate: use full DT node name
From: Stephen Warren @ 2014-02-14 6:16 UTC (permalink / raw)
To: Mike Turquette
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren
clk-fixed-rate currently names clocks according to a node's name without
the unit address. When faced with the legal and technically correct DT
structure below, this causes rgistration attempts for 3 clocks with the
same name, 2 of which fail.
clocks {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
clk_mmc: clock@0 {
compatible = "fixed-clock";
reg = <0>;
...
clk_i2c: clock@1 {
compatible = "fixed-clock";
reg = <1>;
...
clk_spi: clock@2 {
compatible = "fixed-clock";
reg = <2>;
...
Solve this by naming the clocks after the full node name rather than the
short version (e.g. /clocks/clock@0).
Signed-off-by: Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
---
Note that if this is accepted, I intend to submit a patch for the RPi DTS
which uses the naming structure above, so it might be useful to place this
patch in its own branch. Or, I could submit the cleanup after 3.15-rc1.
---
drivers/clk/clk-fixed-rate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index 0fc56ab..3335b3c 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -115,7 +115,7 @@ EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
void of_fixed_clk_setup(struct device_node *node)
{
struct clk *clk;
- const char *clk_name = node->name;
+ const char *clk_name = node->full_name;
u32 rate;
u32 accuracy = 0;
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/2] ARM: bcm2835: fix clock DT node names
From: Stephen Warren @ 2014-02-14 6:16 UTC (permalink / raw)
To: Mike Turquette
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Stephen Warren
In-Reply-To: <1392358613-19962-1-git-send-email-swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
DT nodes should be named according to the type of object that they
represent rather than the identity. DT nodes that contain a reg
property should include a unit address in their name. Fix these issues.
Signed-off-by: Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
---
This is the bcm2835 patch which depends on patch 1. I guess this could
also go through the clk tree if that makes it easier, although there's
always the small risk of conflicts if you do that.
arch/arm/boot/dts/bcm2835.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index a2d4889..1cf1ae7 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -155,21 +155,21 @@
#address-cells = <1>;
#size-cells = <0>;
- clk_mmc: mmc {
+ clk_mmc: clock@0 {
compatible = "fixed-clock";
reg = <0>;
#clock-cells = <0>;
clock-frequency = <100000000>;
};
- clk_i2c: i2c {
+ clk_i2c: clock@1 {
compatible = "fixed-clock";
reg = <1>;
#clock-cells = <0>;
clock-frequency = <250000000>;
};
- clk_spi: spi {
+ clk_spi: clock@2 {
compatible = "fixed-clock";
reg = <2>;
#clock-cells = <0>;
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 00/10] Support TI Light Management Unit devices
From: Milo Kim @ 2014-02-14 6:30 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Samuel Ortiz, Milo Kim
TI LMU (Lighting Management Unit) driver supports lighting devices such like
LM3532, LM3631, LM3633, LM3695 and LM3697.
Enable pin Backlights PWM control Light effects Others
---------- ---------- ----------- ------------- ------
LM3532 Yes Yes Yes ramp up/down
LM3631 Yes Yes Yes slope 5 regulators
LM3633 Yes Yes Yes ramp up/down LEDs
/pattern
LM3695 Yes Yes No
LM3697 Yes Yes Yes ramp up/down
This patch-set consists of several parts below.
TI LMU : HW enable pin control. I2C register access
TI LMU effect : Light effect support for backlight and LED
TI LMU backlight : Backlight subsystem, PWM, control bank assignment
Each backlight driver : Chip dependent code
LM3633 LED : LED subsystem, pattern generation
LM3631 regulator : Regulator drivers for the display bias
Device tree documentation is also included.
Milo Kim (10):
mfd: Add TI LMU driver
backlight: Add TI LMU backlight common driver
backlight: ti-lmu-backlight: Add LM3532 driver
backlight: ti-lmu-backlight: Add LM3631 driver
backlight: ti-lmu-backlight: Add LM3633 driver
backlight: ti-lmu-backlight: Add LM3695 driver
backlight: ti-lmu-backlight: Add LM3697 driver
leds: Add LM3633 driver
regulator: Add LM3631 driver
Documentation: Add device tree bindings for TI LMU devices
.../devicetree/bindings/leds/leds-lm3633.txt | 39 ++
Documentation/devicetree/bindings/mfd/ti-lmu.txt | 182 ++++++
.../bindings/regulator/lm3631-regulator.txt | 49 ++
.../bindings/video/backlight/ti-lmu-backlight.txt | 127 ++++
Documentation/leds/leds-lm3633.txt | 38 ++
drivers/leds/Kconfig | 10 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-lm3633.c | 661 ++++++++++++++++++++
drivers/mfd/Kconfig | 12 +
drivers/mfd/Makefile | 1 +
drivers/mfd/ti-lmu-effect.c | 328 ++++++++++
drivers/mfd/ti-lmu.c | 464 ++++++++++++++
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 1 +
drivers/regulator/lm3631-regulator.c | 285 +++++++++
drivers/video/backlight/Kconfig | 51 ++
drivers/video/backlight/Makefile | 6 +
drivers/video/backlight/lm3532_bl.c | 240 +++++++
drivers/video/backlight/lm3631_bl.c | 186 ++++++
drivers/video/backlight/lm3633_bl.c | 244 ++++++++
drivers/video/backlight/lm3695_bl.c | 143 +++++
drivers/video/backlight/lm3697_bl.c | 224 +++++++
drivers/video/backlight/ti-lmu-backlight.c | 369 +++++++++++
drivers/video/backlight/ti-lmu-backlight.h | 78 +++
include/linux/mfd/ti-lmu-effect.h | 109 ++++
include/linux/mfd/ti-lmu-register.h | 269 ++++++++
include/linux/mfd/ti-lmu.h | 150 +++++
27 files changed, 4275 insertions(+)
create mode 100644 Documentation/devicetree/bindings/leds/leds-lm3633.txt
create mode 100644 Documentation/devicetree/bindings/mfd/ti-lmu.txt
create mode 100644 Documentation/devicetree/bindings/regulator/lm3631-regulator.txt
create mode 100644 Documentation/devicetree/bindings/video/backlight/ti-lmu-backlight.txt
create mode 100644 Documentation/leds/leds-lm3633.txt
create mode 100644 drivers/leds/leds-lm3633.c
create mode 100644 drivers/mfd/ti-lmu-effect.c
create mode 100644 drivers/mfd/ti-lmu.c
create mode 100644 drivers/regulator/lm3631-regulator.c
create mode 100644 drivers/video/backlight/lm3532_bl.c
create mode 100644 drivers/video/backlight/lm3631_bl.c
create mode 100644 drivers/video/backlight/lm3633_bl.c
create mode 100644 drivers/video/backlight/lm3695_bl.c
create mode 100644 drivers/video/backlight/lm3697_bl.c
create mode 100644 drivers/video/backlight/ti-lmu-backlight.c
create mode 100644 drivers/video/backlight/ti-lmu-backlight.h
create mode 100644 include/linux/mfd/ti-lmu-effect.h
create mode 100644 include/linux/mfd/ti-lmu-register.h
create mode 100644 include/linux/mfd/ti-lmu.h
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 01/10] mfd: Add TI LMU driver
From: Milo Kim @ 2014-02-14 6:30 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Samuel Ortiz, Milo Kim
TI LMU (Lighting Management Unit) driver supports lighting devices such like
LM3532, LM3631, LM3633, LM3695 and LM3697.
LMU devices has common features as below.
- I2C interface for accessing device registers
- Hardware enable pin control
- Backlight brightness control
- Light effect driver for backlight and LED patterns
It contains backlight, light effect, LED and regulator driver.
Backlight
---------
It's handled by TI LMU backlight common driver and chip dependent driver.
Please refer to separate patches for ti-lmu-backlight.
Light effect
------------
LMU effect driver is used for setting any light effects.
Each device has specific time value and register map.
Backlight and LED driver can use consitent APIs for light effects.
There are two lists for effect management. LMU effect list and pending list.
Light effect list is added when ti-lmu-effect driver is loaded by referencing
platform resource data.
However, it can be a problem because some LMU device requests the effect
in advance of loading ti-lmu-effect driver.
For example, LM3532 backlight driver requests light ramp effects before
ti-lmu-effect is loaded.
Then, requested effect can not be handled because it doesn't exist in the list.
To solve this situation, pending request list is used.
If requested effect is not in the list, just insert it into the pending list.
And then pending request is handled as soon as the effect is added.
LED indicator
-------------
LM3633 has 6 indicator LEDs. Programmable pattern is supported.
Regulator
---------
LM3631 has 5 regulators for the display bias.
Cc: Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
---
drivers/mfd/Kconfig | 12 +
drivers/mfd/Makefile | 1 +
drivers/mfd/ti-lmu-effect.c | 328 +++++++++++++++++++++++++
drivers/mfd/ti-lmu.c | 464 +++++++++++++++++++++++++++++++++++
include/linux/mfd/ti-lmu-effect.h | 109 ++++++++
include/linux/mfd/ti-lmu-register.h | 269 ++++++++++++++++++++
include/linux/mfd/ti-lmu.h | 150 +++++++++++
7 files changed, 1333 insertions(+)
create mode 100644 drivers/mfd/ti-lmu-effect.c
create mode 100644 drivers/mfd/ti-lmu.c
create mode 100644 include/linux/mfd/ti-lmu-effect.h
create mode 100644 include/linux/mfd/ti-lmu-register.h
create mode 100644 include/linux/mfd/ti-lmu.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d4be491..e7e1e6b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -784,6 +784,18 @@ config MFD_PALMAS
If you say yes here you get support for the Palmas
series of PMIC chips from Texas Instruments.
+config MFD_TI_LMU
+ tristate "TI Lighting Management Unit driver"
+ depends on I2C
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Say yes here to enable support for TI LMU chips.
+
+ TI LMU MFD supports LM3532, LM3631, LM3633, LM3695 and LM3697.
+ It consists of backlight, light effect, LED and regulator driver.
+ It provides consistent device controls for lighting functions.
+
config MFD_TI_SSP
tristate "TI Sequencer Serial Port support"
depends on ARCH_DAVINCI_TNETV107X
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 93c7cad..02dc65a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
+obj-$(CONFIG_MFD_TI_LMU) += ti-lmu.o ti-lmu-effect.o
obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o
diff --git a/drivers/mfd/ti-lmu-effect.c b/drivers/mfd/ti-lmu-effect.c
new file mode 100644
index 0000000..a4a3d26
--- /dev/null
+++ b/drivers/mfd/ti-lmu-effect.c
@@ -0,0 +1,328 @@
+/*
+ * TI LMU Effect Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LMU effect driver is used for setting any light effects.
+ * Each device has specific time value and register map.
+ * Light effect can be controlled with consistent APIs.
+ *
+ * Examples:
+ * Backlight ramp time control - LM3532, LM3631, LM3633 and LM3697
+ * LED pattern display - LM3633
+ *
+ * Flow:
+ * 1) LMU backlight and LED drivers request to the light effect driver
+ * by using ti_lmu_effect_request().
+ * 2) Call ti_lmu_effect_set_* APIs in each callback function.
+ */
+
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define LMU_EFFECT_MAX_TIME_PERIOD 9700
+
+struct ti_lmu_effect_req {
+ struct list_head list;
+ const char *name;
+ ti_lmu_effect_cb_t *cbfunc;
+ int req_id;
+ void *data;
+};
+
+struct ti_lmu_effect {
+ struct list_head list;
+ struct ti_lmu *lmu;
+
+ const char *name;
+ u8 addr;
+ u8 mask;
+ u8 shift;
+ unsigned int val;
+};
+
+static DEFINE_MUTEX(lmu_effect_list_mutex);
+static LIST_HEAD(lmu_effect_list);
+static LIST_HEAD(lmu_effect_pending_list);
+
+static const int lm3532_ramp_table[] = { 0, 1, 2, 4, 8, 16, 32, 65 };
+static const int lm3631_ramp_table[] = {
+ 0, 1, 2, 5, 10, 20, 50, 100,
+ 250, 500, 750, 1000, 1500, 2000, 3000, 4000,
+};
+static const int lm3633_ramp_table[] = {
+ 2, 250, 500, 1000, 2000, 4000, 8000, 16000,
+};
+
+static u8 ti_lmu_effect_get_ramp_index(struct ti_lmu_effect *lmu_effect,
+ int msec)
+{
+ const int *table = NULL;
+ int size = 0;
+ int index = 0;
+ int i;
+
+ switch (lmu_effect->lmu->id) {
+ case LM3532:
+ table = lm3532_ramp_table;
+ size = ARRAY_SIZE(lm3532_ramp_table);
+ break;
+ case LM3631:
+ table = lm3631_ramp_table;
+ size = ARRAY_SIZE(lm3631_ramp_table);
+ break;
+ case LM3633:
+ case LM3697: /* LM3697 has same ramp table as LM3633 */
+ table = lm3633_ramp_table;
+ size = ARRAY_SIZE(lm3633_ramp_table);
+ break;
+ default:
+ break;
+ }
+
+ if (msec <= table[0]) {
+ index = 0;
+ goto out;
+ }
+
+ if (msec >= table[size-1]) {
+ index = size - 1;
+ goto out;
+ }
+
+ /* Find appropriate register index from the table */
+ for (i = 1; i < size; i++) {
+ if (msec >= table[i-1] && msec < table[i]) {
+ index = i - 1;
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ return index;
+}
+
+static u8 ti_lmu_effect_get_time_index(struct ti_lmu_effect *lmu_effect,
+ int msec)
+{
+ u8 idx, offset;
+
+ /*
+ * Find appropriate register index around input time value
+ *
+ * 0 <= time <= 1000 : 16ms step
+ * 1000 < time <= 9700 : 131ms step, base index is 61
+ */
+
+ msec = min_t(int, msec, LMU_EFFECT_MAX_TIME_PERIOD);
+
+ if (msec >= 0 && msec <= 1000) {
+ idx = msec / 16;
+ if (idx > 1)
+ idx--;
+ offset = 0;
+ } else {
+ idx = (msec - 1000) / 131;
+ offset = 61;
+ }
+
+ return idx + offset;
+}
+
+static struct ti_lmu_effect *ti_lmu_effect_lookup(const char *name)
+{
+ struct ti_lmu_effect *lmu_effect;
+
+ list_for_each_entry(lmu_effect, &lmu_effect_list, list)
+ if (!strcmp(lmu_effect->name, name))
+ return lmu_effect;
+
+ return NULL;
+}
+
+int ti_lmu_effect_request(const char *name, ti_lmu_effect_cb_t cbfunc,
+ int req_id, void *data)
+{
+ struct ti_lmu_effect *lmu_effect;
+ struct ti_lmu_effect_req *lmu_effect_req;
+
+ if (!cbfunc || !name)
+ return -EINVAL;
+
+ /* If requested effect is in the list, handle it immediately */
+ lmu_effect = ti_lmu_effect_lookup(name);
+ if (lmu_effect) {
+ cbfunc(lmu_effect, req_id, data);
+ goto out;
+ }
+
+ /*
+ * If requested effect is not in the list yet,
+ * add it into pending request list to handle it later.
+ */
+
+ lmu_effect_req = kzalloc(sizeof(*lmu_effect_req), GFP_KERNEL);
+ if (!lmu_effect_req)
+ return -ENOMEM;
+
+ lmu_effect_req->name = name;
+ lmu_effect_req->cbfunc = cbfunc;
+ lmu_effect_req->req_id = req_id;
+ lmu_effect_req->data = data;
+
+ mutex_lock(&lmu_effect_list_mutex);
+ list_add(&lmu_effect_req->list, &lmu_effect_pending_list);
+ mutex_unlock(&lmu_effect_list_mutex);
+
+out:
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ti_lmu_effect_request);
+
+int ti_lmu_effect_set_ramp(struct ti_lmu_effect *lmu_effect, int msec)
+{
+ u8 val = ti_lmu_effect_get_ramp_index(lmu_effect, msec);
+
+ return ti_lmu_update_bits(lmu_effect->lmu, lmu_effect->addr,
+ lmu_effect->mask, val << lmu_effect->shift);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_effect_set_ramp);
+
+int ti_lmu_effect_set_time(struct ti_lmu_effect *lmu_effect, int msec,
+ u8 reg_offset)
+{
+ u8 val = ti_lmu_effect_get_time_index(lmu_effect, msec);
+
+ return ti_lmu_update_bits(lmu_effect->lmu,
+ lmu_effect->addr + reg_offset,
+ lmu_effect->mask, val << lmu_effect->shift);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_effect_set_time);
+
+int ti_lmu_effect_set_level(struct ti_lmu_effect *lmu_effect, u8 val,
+ u8 reg_offset)
+{
+ return ti_lmu_update_bits(lmu_effect->lmu,
+ lmu_effect->addr + reg_offset,
+ lmu_effect->mask, val << lmu_effect->shift);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_effect_set_level);
+
+static void ti_lmu_effect_handle_pending_list(struct ti_lmu_effect *lmu_effect)
+{
+ struct ti_lmu_effect_req *req, *n;
+
+ /*
+ * If an effect driver is requested before, then handle it.
+ * Then, requested list and memory should be released.
+ */
+
+ mutex_lock(&lmu_effect_list_mutex);
+
+ list_for_each_entry_safe(req, n, &lmu_effect_pending_list, list) {
+ if (!strcmp(req->name, lmu_effect->name)) {
+ req->cbfunc(lmu_effect, req->req_id, req->data);
+ list_del(&req->list);
+ kfree(req);
+ }
+ }
+
+ mutex_unlock(&lmu_effect_list_mutex);
+}
+
+static int ti_lmu_effect_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct ti_lmu_effect *lmu_effect;
+ struct ti_lmu_effect *each;
+ struct resource *r;
+ int num_res = pdev->num_resources;
+ int i;
+
+ if (num_res <= 0) {
+ dev_err(&pdev->dev, "Invalid numbers of resources: %d\n",
+ num_res);
+ return -EINVAL;
+ }
+
+ lmu_effect = devm_kzalloc(&pdev->dev, sizeof(*lmu_effect) * num_res,
+ GFP_KERNEL);
+ if (!lmu_effect)
+ return -ENOMEM;
+
+ for (i = 0; i < num_res; i++) {
+ r = platform_get_resource(pdev, IORESOURCE_REG, i);
+ if (!r)
+ continue;
+
+ each = lmu_effect + i;
+
+ each->name = r->name;
+ each->lmu = lmu;
+ each->addr = LMU_EFFECT_GET_ADDR(r->start);
+ each->mask = LMU_EFFECT_GET_MASK(r->start);
+ each->shift = LMU_EFFECT_GET_SHIFT(r->start);
+
+ mutex_lock(&lmu_effect_list_mutex);
+ list_add(&each->list, &lmu_effect_list);
+ mutex_unlock(&lmu_effect_list_mutex);
+
+ /*
+ * If an effect driver is requested when the driver is not
+ * ready, the effect driver is inserted into the pending list.
+ * Then, pending requested driver is handled here.
+ */
+
+ ti_lmu_effect_handle_pending_list(each);
+ }
+
+ platform_set_drvdata(pdev, lmu_effect);
+
+ return 0;
+}
+
+static int ti_lmu_effect_remove(struct platform_device *pdev)
+{
+ struct ti_lmu_effect *lmu_effect, *n;
+ struct ti_lmu_effect_req *req, *m;
+
+ mutex_lock(&lmu_effect_list_mutex);
+
+ list_for_each_entry_safe(lmu_effect, n, &lmu_effect_list, list)
+ list_del(&lmu_effect->list);
+
+ /* Remove pending list forcedly */
+ list_for_each_entry_safe(req, m, &lmu_effect_pending_list, list) {
+ list_del(&req->list);
+ kfree(req);
+ }
+
+ mutex_unlock(&lmu_effect_list_mutex);
+
+ return 0;
+}
+
+static struct platform_driver ti_lmu_effect_driver = {
+ .probe = ti_lmu_effect_probe,
+ .remove = ti_lmu_effect_remove,
+ .driver = {
+ .name = "lmu-effect",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(ti_lmu_effect_driver);
+
+MODULE_DESCRIPTION("TI LMU Effect Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lmu-effect");
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
new file mode 100644
index 0000000..e97d686
--- /dev/null
+++ b/drivers/mfd/ti-lmu.c
@@ -0,0 +1,464 @@
+/*
+ * TI LMU(Lighting Management Unit) Core Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LMU MFD supports LM3532, LM3631, LM3633, LM3695 and LM3697.
+ *
+ * LM3532: backlight + light effect
+ * LM3631: backlight + light effect + regulators
+ * LM3633: backlight + light effect + LED indicators
+ * LM3695: backlight
+ * LM3697: backlight + light effect
+ *
+ * Those devices have common features as below.
+ *
+ * - I2C interface for accessing device registers
+ * - Hardware enable pin control
+ * - Backlight brightness control with current settings
+ * - Light effect driver for backlight and LED patterns
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+
+#define LMU_IMAX_OFFSET 6
+
+static const struct resource lm3532_effect_resources[] = {
+ {
+ .name = LM3532_EFFECT_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3532_EFFECT_REGISTER(RAMPUP),
+ },
+ {
+ .name = LM3532_EFFECT_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3532_EFFECT_REGISTER(RAMPDN),
+ },
+};
+
+static struct mfd_cell lm3532_devices[] = {
+ {
+ .name = "lm3532-backlight",
+ .of_compatible = "ti,lmu-backlight",
+ },
+ {
+ .name = "lmu-effect",
+ .id = LM3532,
+ .resources = lm3532_effect_resources,
+ .num_resources = ARRAY_SIZE(lm3532_effect_resources),
+ },
+};
+
+static const struct resource lm3631_effect_resources[] = {
+ {
+ .name = LM3631_EFFECT_SLOPE,
+ .flags = IORESOURCE_REG,
+ .start = LM3631_EFFECT_REGISTER(SLOPE),
+ },
+};
+
+#define LM3631_REGULATOR(_id) \
+{ \
+ .name = "lm3631-regulator", \
+ .id = _id, \
+ .of_compatible = "ti,lm3631-regulator", \
+} \
+
+static struct mfd_cell lm3631_devices[] = {
+ LM3631_REGULATOR(0),
+ LM3631_REGULATOR(1),
+ LM3631_REGULATOR(2),
+ LM3631_REGULATOR(3),
+ LM3631_REGULATOR(4),
+ {
+ .name = "lm3631-backlight",
+ .of_compatible = "ti,lmu-backlight",
+ },
+ {
+ .name = "lmu-effect",
+ .id = LM3631,
+ .resources = lm3631_effect_resources,
+ .num_resources = ARRAY_SIZE(lm3631_effect_resources),
+ },
+};
+
+static const struct resource lm3633_effect_resources[] = {
+ {
+ .name = LM3633_EFFECT_BL0_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(BL0_RAMPUP),
+ },
+ {
+ .name = LM3633_EFFECT_BL0_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(BL0_RAMPDN),
+ },
+ {
+ .name = LM3633_EFFECT_BL1_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(BL1_RAMPUP),
+ },
+ {
+ .name = LM3633_EFFECT_BL1_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(BL1_RAMPDN),
+ },
+ {
+ .name = LM3633_EFFECT_PTN_DELAY,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(DELAY),
+ },
+ {
+ .name = LM3633_EFFECT_PTN_HIGHTIME,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(HIGHTIME),
+ },
+ {
+ .name = LM3633_EFFECT_PTN_LOWTIME,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(LOWTIME),
+ },
+ {
+ .name = LM3633_EFFECT_PTN0_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(PTN0_RAMPUP),
+ },
+ {
+ .name = LM3633_EFFECT_PTN0_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(PTN0_RAMPDN),
+ },
+ {
+ .name = LM3633_EFFECT_PTN1_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(PTN1_RAMPUP),
+ },
+ {
+ .name = LM3633_EFFECT_PTN1_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(PTN1_RAMPDN),
+ },
+ {
+ .name = LM3633_EFFECT_PTN_LOWBRT,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(LOWBRT),
+ },
+ {
+ .name = LM3633_EFFECT_PTN_HIGHBRT,
+ .flags = IORESOURCE_REG,
+ .start = LM3633_EFFECT_REGISTER(HIGHBRT),
+ },
+};
+
+static struct mfd_cell lm3633_devices[] = {
+ {
+ .name = "lm3633-backlight",
+ .of_compatible = "ti,lmu-backlight",
+ },
+ {
+ .name = "lm3633-leds",
+ .of_compatible = "ti,lm3633-leds",
+ },
+ {
+ .name = "lmu-effect",
+ .id = LM3633,
+ .resources = lm3633_effect_resources,
+ .num_resources = ARRAY_SIZE(lm3633_effect_resources),
+ },
+};
+
+static struct mfd_cell lm3695_devices[] = {
+ {
+ .name = "lm3695-backlight",
+ .of_compatible = "ti,lmu-backlight",
+ },
+};
+
+static const struct resource lm3697_effect_resources[] = {
+ {
+ .name = LM3697_EFFECT_BL0_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3697_EFFECT_REGISTER(BL0_RAMPUP),
+ },
+ {
+ .name = LM3697_EFFECT_BL0_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3697_EFFECT_REGISTER(BL0_RAMPDN),
+ },
+ {
+ .name = LM3697_EFFECT_BL1_RAMPUP,
+ .flags = IORESOURCE_REG,
+ .start = LM3697_EFFECT_REGISTER(BL1_RAMPUP),
+ },
+ {
+ .name = LM3697_EFFECT_BL1_RAMPDOWN,
+ .flags = IORESOURCE_REG,
+ .start = LM3697_EFFECT_REGISTER(BL1_RAMPDN),
+ },
+};
+
+static struct mfd_cell lm3697_devices[] = {
+ {
+ .name = "lm3697-backlight",
+ .of_compatible = "ti,lmu-backlight",
+ },
+ {
+ .name = "lmu-effect",
+ .id = LM3697,
+ .resources = lm3697_effect_resources,
+ .num_resources = ARRAY_SIZE(lm3697_effect_resources),
+ },
+};
+
+static struct mfd_cell *ti_lmu_cell[] = {
+ lm3532_devices,
+ lm3631_devices,
+ lm3633_devices,
+ lm3695_devices,
+ lm3697_devices,
+};
+
+static const int ti_lmu_num_cells[] = {
+ ARRAY_SIZE(lm3532_devices),
+ ARRAY_SIZE(lm3631_devices),
+ ARRAY_SIZE(lm3633_devices),
+ ARRAY_SIZE(lm3695_devices),
+ ARRAY_SIZE(lm3697_devices),
+};
+
+int ti_lmu_read_byte(struct ti_lmu *lmu, u8 reg, u8 *read)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(lmu->regmap, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ *read = (u8)val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ti_lmu_read_byte);
+
+int ti_lmu_write_byte(struct ti_lmu *lmu, u8 reg, u8 data)
+{
+ return regmap_write(lmu->regmap, reg, data);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_write_byte);
+
+int ti_lmu_update_bits(struct ti_lmu *lmu, u8 reg, u8 mask, u8 data)
+{
+ if (mask == LMU_FULL_MASKBIT)
+ return regmap_write(lmu->regmap, reg, data);
+ else
+ return regmap_update_bits(lmu->regmap, reg, mask, data);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_update_bits);
+
+enum ti_lmu_max_current ti_lmu_get_current_code(u8 imax_mA)
+{
+ const enum ti_lmu_max_current imax_table[] = {
+ LMU_IMAX_6mA, LMU_IMAX_7mA, LMU_IMAX_8mA, LMU_IMAX_9mA,
+ LMU_IMAX_10mA, LMU_IMAX_11mA, LMU_IMAX_12mA, LMU_IMAX_13mA,
+ LMU_IMAX_14mA, LMU_IMAX_15mA, LMU_IMAX_16mA, LMU_IMAX_17mA,
+ LMU_IMAX_18mA, LMU_IMAX_19mA, LMU_IMAX_20mA, LMU_IMAX_21mA,
+ LMU_IMAX_22mA, LMU_IMAX_23mA, LMU_IMAX_24mA, LMU_IMAX_25mA,
+ LMU_IMAX_26mA, LMU_IMAX_27mA, LMU_IMAX_28mA, LMU_IMAX_29mA,
+ };
+
+ /*
+ * Convert milliampere to appropriate enum code value.
+ * Input range : 5 ~ 30mA
+ */
+
+ if (imax_mA <= 5)
+ return LMU_IMAX_5mA;
+
+ if (imax_mA >= 30)
+ return LMU_IMAX_30mA;
+
+ return imax_table[imax_mA - LMU_IMAX_OFFSET];
+}
+EXPORT_SYMBOL_GPL(ti_lmu_get_current_code);
+
+static int ti_lmu_enable_hw(struct ti_lmu *lmu)
+{
+ int ret;
+
+ ret = devm_gpio_request_one(lmu->dev, lmu->pdata->en_gpio,
+ GPIOF_OUT_INIT_HIGH, "lmu_hwen");
+ if (ret)
+ return ret;
+
+ /*
+ * LM3631 Powerup Sequence
+ *
+ * 1) Enable nRST pin : GPIO control
+ * 2) Delay about 1ms : bias delay 200us + EPROM read time 700us
+ * 3) Set LCD_EN bit to 1
+ */
+
+ if (lmu->id == LM3631) {
+ usleep_range(1000, 1500);
+
+ return ti_lmu_update_bits(lmu, LM3631_REG_DEVCTRL,
+ LM3631_LCD_EN_MASK,
+ 1 << LM3631_LCD_EN_SHIFT);
+ }
+
+ return 0;
+}
+
+static void ti_lmu_disable_hw(struct ti_lmu *lmu)
+{
+ gpio_set_value(lmu->pdata->en_gpio, 0);
+}
+
+static struct regmap_config lmu_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ti_lmu_parse_dt(struct device *dev, struct ti_lmu *lmu)
+{
+ struct device_node *node = dev->of_node;
+ struct ti_lmu_platform_data *pdata;
+
+ if (!node)
+ return -EINVAL;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->en_gpio = of_get_named_gpio(node, "ti,enable-gpio", 0);
+ if (pdata->en_gpio < 0)
+ return pdata->en_gpio;
+
+ lmu->pdata = pdata;
+
+ return 0;
+}
+
+static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+ struct device *dev = &cl->dev;
+ struct ti_lmu_platform_data *pdata = dev_get_platdata(dev);
+ struct ti_lmu *lmu;
+ int ret;
+
+ lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL);
+ if (!lmu)
+ return -ENOMEM;
+
+ lmu->pdata = pdata;
+ if (!lmu->pdata) {
+ if (IS_ENABLED(CONFIG_OF))
+ ret = ti_lmu_parse_dt(dev, lmu);
+ else
+ ret = -ENODEV;
+
+ if (ret)
+ return ret;
+ }
+
+ lmu->id = id->driver_data;
+ switch (lmu->id) {
+ case LM3532:
+ lmu_regmap_config.max_register = LM3532_MAX_REGISTERS;
+ break;
+ case LM3631:
+ lmu_regmap_config.max_register = LM3631_MAX_REGISTERS;
+ break;
+ case LM3633:
+ lmu_regmap_config.max_register = LM3633_MAX_REGISTERS;
+ break;
+ case LM3695:
+ lmu_regmap_config.max_register = LM3695_MAX_REGISTERS;
+ break;
+ case LM3697:
+ lmu_regmap_config.max_register = LM3697_MAX_REGISTERS;
+ break;
+ default:
+ break;
+ }
+
+ lmu_regmap_config.name = id->name;
+ lmu->regmap = devm_regmap_init_i2c(cl, &lmu_regmap_config);
+ if (IS_ERR(lmu->regmap))
+ return PTR_ERR(lmu->regmap);
+
+ lmu->dev = &cl->dev;
+ i2c_set_clientdata(cl, lmu);
+
+ ret = ti_lmu_enable_hw(lmu);
+ if (ret)
+ return ret;
+
+ return mfd_add_devices(lmu->dev, 0, ti_lmu_cell[lmu->id],
+ ti_lmu_num_cells[lmu->id], NULL, 0, NULL);
+}
+
+static int ti_lmu_remove(struct i2c_client *cl)
+{
+ struct ti_lmu *lmu = i2c_get_clientdata(cl);
+
+ ti_lmu_disable_hw(lmu);
+ mfd_remove_devices(lmu->dev);
+ return 0;
+}
+
+static const struct i2c_device_id ti_lmu_ids[] = {
+ { "lm3532", LM3532 },
+ { "lm3631", LM3631 },
+ { "lm3633", LM3633 },
+ { "lm3695", LM3695 },
+ { "lm3697", LM3697 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ti_lmu_of_match[] = {
+ { .compatible = "ti,lm3532", },
+ { .compatible = "ti,lm3631", },
+ { .compatible = "ti,lm3633", },
+ { .compatible = "ti,lm3695", },
+ { .compatible = "ti,lm3697", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
+#endif
+
+static struct i2c_driver ti_lmu_driver = {
+ .probe = ti_lmu_probe,
+ .remove = ti_lmu_remove,
+ .driver = {
+ .name = "ti-lmu",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ti_lmu_of_match),
+ },
+ .id_table = ti_lmu_ids,
+};
+module_i2c_driver(ti_lmu_driver);
+
+MODULE_DESCRIPTION("TI LMU MFD Core Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/ti-lmu-effect.h b/include/linux/mfd/ti-lmu-effect.h
new file mode 100644
index 0000000..24d50d2
--- /dev/null
+++ b/include/linux/mfd/ti-lmu-effect.h
@@ -0,0 +1,109 @@
+/*
+ * TI LMU(Lighting Management Unit) Effect Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __MFD_TI_LMU_EFFECT_H__
+#define __MFD_TI_LMU_EFFECT_H__
+
+#include <linux/mfd/ti-lmu.h>
+
+/*
+ * LMU effect IO resource structure
+ *
+ * shift[23:16] | mask[15:8] | address[7:0]
+ *
+ * All TI LMU device is 8-bit register base. address, mask and shift are 8-bit.
+ * To activate a light effect, updating registers is required.
+ * However, register information depends on the device.
+ * In other words, each chip driver should manage own its register address,
+ * mask and shift bits.
+ * To make it simpler, registers are configured with IORESOURCE_REG.
+ * LMU uses bit combination for efficient IO resource.
+ *
+ * LMU MFD : Register configuration by combining address/mask/shift.
+ * XXX_LMU_EFFECT_REGISTER() macros are used.
+ * LMU effect : Get address/mask/shift by using platform_get_resource().
+ * LMU_EFFECT_GET_XXX() macros are used.
+ */
+
+#define _LMU_EFFECT_REGISTER(addr, mask, shift) \
+ ((shift << 16) | (mask << 8) | addr)
+
+#define LMU_EFFECT_REGISTER(chip, effect) \
+ _LMU_EFFECT_REGISTER(chip##_REG_##effect, \
+ chip##_##effect##_MASK, \
+ chip##_##effect##_SHIFT) \
+
+#define LM3532_EFFECT_REGISTER(effect) \
+ LMU_EFFECT_REGISTER(LM3532, effect)
+#define LM3631_EFFECT_REGISTER(effect) \
+ LMU_EFFECT_REGISTER(LM3631, effect)
+#define LM3633_EFFECT_REGISTER(effect) \
+ LMU_EFFECT_REGISTER(LM3633, effect)
+#define LM3697_EFFECT_REGISTER(effect) \
+ LMU_EFFECT_REGISTER(LM3697, effect)
+
+#define LMU_EFFECT_GET_ADDR(x) (x & 0xFF)
+#define LMU_EFFECT_GET_MASK(x) ((x >> 8) & 0xFF)
+#define LMU_EFFECT_GET_SHIFT(x) ((x >> 16) & 0xFF)
+
+#define LM3532_EFFECT_RAMPUP "lm3532:ramp_up"
+#define LM3532_EFFECT_RAMPDOWN "lm3532:ramp_down"
+#define LM3631_EFFECT_SLOPE "lm3631:slope"
+#define LM3633_EFFECT_BL0_RAMPUP "lm3633_bl:0:ramp_up"
+#define LM3633_EFFECT_BL0_RAMPDOWN "lm3633_bl:0:ramp_down"
+#define LM3633_EFFECT_BL1_RAMPUP "lm3633_bl:1:ramp_up"
+#define LM3633_EFFECT_BL1_RAMPDOWN "lm3633_bl:1:ramp_down"
+#define LM3633_EFFECT_PTN_DELAY "lm3633_ptn:delay"
+#define LM3633_EFFECT_PTN_HIGHTIME "lm3633_ptn:high_time"
+#define LM3633_EFFECT_PTN_LOWTIME "lm3633_ptn:low_time"
+#define LM3633_EFFECT_PTN0_RAMPUP "lm3633_ptn:0:ramp_up"
+#define LM3633_EFFECT_PTN0_RAMPDOWN "lm3633_ptn:0:ramp_down"
+#define LM3633_EFFECT_PTN1_RAMPUP "lm3633_ptn:1:ramp_up"
+#define LM3633_EFFECT_PTN1_RAMPDOWN "lm3633_ptn:1:ramp_down"
+#define LM3633_EFFECT_PTN_LOWBRT "lm3633_ptn:low_brt"
+#define LM3633_EFFECT_PTN_HIGHBRT "lm3633_ptn:high_brt"
+#define LM3697_EFFECT_BL0_RAMPUP "lm3697:0:ramp_up"
+#define LM3697_EFFECT_BL0_RAMPDOWN "lm3697:0:ramp_down"
+#define LM3697_EFFECT_BL1_RAMPUP "lm3697:1:ramp_up"
+#define LM3697_EFFECT_BL1_RAMPDOWN "lm3697:1:ramp_down"
+
+enum lmu_effect_request_id {
+ /* Backlight effect */
+ BL_EFFECT_RAMPUP,
+ BL_EFFECT_RAMPDN,
+
+ /* LED pattern effect */
+ LED_EFFECT_DELAY,
+ LED_EFFECT_HIGHTIME,
+ LED_EFFECT_LOWTIME,
+ LED_EFFECT_PTN0_RAMPUP,
+ LED_EFFECT_PTN0_RAMPDN,
+ LED_EFFECT_PTN1_RAMPUP,
+ LED_EFFECT_PTN1_RAMPDN,
+ LED_EFFECT_LOWBRT,
+ LED_EFFECT_HIGHBRT,
+};
+
+struct ti_lmu_effect;
+
+typedef void (ti_lmu_effect_cb_t)(struct ti_lmu_effect *, int, void *);
+
+int ti_lmu_effect_request(const char *name, ti_lmu_effect_cb_t cbfunc,
+ int req_id, void *data);
+int ti_lmu_effect_set_ramp(struct ti_lmu_effect *lmu_effect, int msec);
+int ti_lmu_effect_set_time(struct ti_lmu_effect *lmu_effect, int msec,
+ u8 reg_offset);
+int ti_lmu_effect_set_level(struct ti_lmu_effect *lmu_effect, u8 val,
+ u8 reg_offset);
+
+#endif
diff --git a/include/linux/mfd/ti-lmu-register.h b/include/linux/mfd/ti-lmu-register.h
new file mode 100644
index 0000000..27eb20c
--- /dev/null
+++ b/include/linux/mfd/ti-lmu-register.h
@@ -0,0 +1,269 @@
+/*
+ * TI LMU(Lighting Management Unit) Device Register Map
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __MFD_TI_LMU_REGISTER_H__
+#define __MFD_TI_LMU_REGISTER_H__
+
+#include <linux/mfd/ti-lmu.h>
+
+#define LMU_FULL_MASKBIT 0xFF
+
+/* LM3532 */
+#define LM3532_REG_OUTPUT_CFG 0x10
+#define LM3532_ILED1_CFG_MASK 0x03
+#define LM3532_ILED2_CFG_MASK 0x0C
+#define LM3532_ILED3_CFG_MASK 0x30
+#define LM3532_ILED1_CFG_SHIFT 0
+#define LM3532_ILED2_CFG_SHIFT 2
+#define LM3532_ILED3_CFG_SHIFT 4
+
+#define LM3532_REG_RAMPUP 0x12
+#define LM3532_REG_RAMPDN LM3532_REG_RAMPUP
+#define LM3532_RAMPUP_MASK 0x07
+#define LM3532_RAMPUP_SHIFT 0
+#define LM3532_RAMPDN_MASK 0x38
+#define LM3532_RAMPDN_SHIFT 3
+
+#define LM3532_REG_ENABLE 0x1D
+
+#define LM3532_REG_PWM_CFG_BASE 0x13
+#define LM3532_PWM_SEL_A_MASK 0x05 /* zone 0 */
+#define LM3532_PWM_SEL_B_MASK 0x09 /* zone 1 */
+#define LM3532_PWM_SEL_C_MASK 0x11 /* zone 2 */
+#define LM3532_PWM_SEL_A_SHIFT 2
+#define LM3532_PWM_SEL_B_SHIFT 3
+#define LM3532_PWM_SEL_C_SHIFT 4
+
+#define LM3532_REG_ZONE_CFG_A 0x16
+#define LM3532_REG_ZONE_CFG_B 0x18
+#define LM3532_REG_ZONE_CFG_C 0x1A
+#define LM3532_ZONE_CFG_MASK (BIT(2) | BIT(3) | BIT(4))
+#define LM3532_ZONE_CFG_SHIFT 2
+
+#define LM3532_REG_IMAX_A 0x17
+#define LM3532_REG_IMAX_B 0x19
+#define LM3532_REG_IMAX_C 0x1B
+
+#define LM3532_REG_BRT_A 0x70 /* zone 0 */
+#define LM3532_REG_BRT_B 0x76 /* zone 1 */
+#define LM3532_REG_BRT_C 0x7C /* zone 2 */
+
+#define LM3532_MAX_REGISTERS 0x7E
+
+/* LM3631 */
+#define LM3631_REG_DEVCTRL 0x00
+#define LM3631_LCD_EN_MASK BIT(1)
+#define LM3631_LCD_EN_SHIFT 1
+#define LM3631_BL_EN_MASK BIT(0)
+#define LM3631_BL_EN_SHIFT 0
+
+#define LM3631_REG_BRT_LSB 0x01
+#define LM3631_BRT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LM3631_REG_BRT_MSB 0x02
+#define LM3631_BRT_MSB_SHIFT 3
+
+#define LM3631_REG_BL_CFG 0x06
+#define LM3631_BL_STRING_MASK BIT(3)
+#define LM3631_BL_TWO_STRINGS 0
+#define LM3631_BL_ONE_STRING BIT(3)
+#define LM3631_MAP_MASK BIT(5)
+#define LM3631_EXPONENTIAL_MAP 0
+
+#define LM3631_REG_BL_BOOST 0x07
+#define LM3631_BOOST_OVP_MASK (BIT(1) | BIT(2))
+#define LM3631_BOOST_OVP_25V 0x04
+
+#define LM3631_REG_BRT_MODE 0x08
+#define LM3631_EN_SLOPE_MASK BIT(1)
+#define LM3631_MODE_MASK (BIT(2) | BIT(3))
+#define LM3631_MODE_I2C (0 << 2)
+#define LM3631_MODE_PWM (1 << 2)
+#define LM3631_MODE_COMB1 (2 << 2) /* PWM x I2C before sloping */
+#define LM3631_MODE_COMB2 (3 << 2) /* PWM x Sloped I2C */
+
+#define LM3631_REG_SLOPE 0x09
+#define LM3631_SLOPE_MASK 0xF0
+#define LM3631_SLOPE_SHIFT 4
+
+#define LM3631_REG_LDO_CTRL1 0x0A
+#define LM3631_EN_OREF_MASK BIT(0)
+#define LM3631_EN_VNEG_MASK BIT(1)
+#define LM3631_EN_VPOS_MASK BIT(2)
+
+#define LM3631_REG_LDO_CTRL2 0x0B
+#define LM3631_EN_CONT_MASK BIT(0)
+
+#define LM3631_REG_VOUT_CONT 0x0C
+#define LM3631_VOUT_CONT_MASK (BIT(6) | BIT(7))
+
+#define LM3631_REG_VOUT_BOOST 0x0C
+#define LM3631_REG_VOUT_POS 0x0D
+#define LM3631_REG_VOUT_NEG 0x0E
+#define LM3631_REG_VOUT_OREF 0x0F
+#define LM3631_VOUT_MASK 0x3F
+
+#define LM3631_REG_ENTIME_VCONT 0x0B
+#define LM3631_ENTIME_CONT_MASK 0x70
+
+#define LM3631_REG_ENTIME_VOREF 0x0F
+#define LM3631_REG_ENTIME_VPOS 0x10
+#define LM3631_REG_ENTIME_VNEG 0x11
+#define LM3631_ENTIME_MASK 0xF0
+#define LM3631_ENTIME_SHIFT 4
+
+#define LM3631_MAX_REGISTERS 0x16
+
+/* LM3633 */
+#define LM3633_REG_HVLED_OUTPUT_CFG 0x10
+
+#define LM3633_REG_BANK_SEL 0x11
+
+#define LM3633_REG_BL0_RAMPUP 0x12
+#define LM3633_REG_BL0_RAMPDN LM3633_REG_BL0_RAMPUP
+#define LM3633_BL0_RAMPUP_MASK 0xF0
+#define LM3633_BL0_RAMPUP_SHIFT 4
+#define LM3633_BL0_RAMPDN_MASK 0x0F
+#define LM3633_BL0_RAMPDN_SHIFT 0
+
+#define LM3633_REG_BL1_RAMPUP 0x13
+#define LM3633_REG_BL1_RAMPDN LM3633_REG_BL1_RAMPUP
+#define LM3633_BL1_RAMPUP_MASK LM3633_BL0_RAMPUP_MASK
+#define LM3633_BL1_RAMPUP_SHIFT LM3633_BL0_RAMPUP_SHIFT
+#define LM3633_BL1_RAMPDN_MASK LM3633_BL0_RAMPDN_MASK
+#define LM3633_BL1_RAMPDN_SHIFT LM3633_BL0_RAMPDN_SHIFT
+
+#define LM3633_REG_BL_RAMP_CONF 0x1B
+#define LM3633_BL_RAMP_MASK 0x0F
+#define LM3633_BL_RAMP_EACH 0x05
+
+#define LM3633_REG_PTN0_RAMPUP 0x1C
+#define LM3633_REG_PTN0_RAMPDN LM3633_REG_PTN0_RAMPUP
+#define LM3633_PTN0_RAMPUP_MASK 0x70
+#define LM3633_PTN0_RAMPUP_SHIFT 4
+#define LM3633_PTN0_RAMPDN_MASK 0x07
+#define LM3633_PTN0_RAMPDN_SHIFT 0
+
+#define LM3633_REG_PTN1_RAMPUP 0x1D
+#define LM3633_REG_PTN1_RAMPDN LM3633_REG_PTN1_RAMPUP
+#define LM3633_PTN1_RAMPUP_MASK LM3633_PTN0_RAMPUP_MASK
+#define LM3633_PTN1_RAMPUP_SHIFT LM3633_PTN0_RAMPUP_SHIFT
+#define LM3633_PTN1_RAMPDN_MASK LM3633_PTN0_RAMPDN_MASK
+#define LM3633_PTN1_RAMPDN_SHIFT LM3633_PTN0_RAMPDN_SHIFT
+
+#define LM3633_REG_IMAX_HVLED_A 0x20
+#define LM3633_REG_IMAX_HVLED_B 0x21
+#define LM3633_REG_IMAX_LVLED_BASE 0x22
+
+#define LM3633_REG_ENABLE 0x2B
+#define LM3633_LED_BANK_OFFSET 2
+
+#define LM3633_REG_PATTERN 0x2C
+#define LM3633_PATTERN_EN 1
+
+#define LM3633_REG_BOOST_CFG 0x2D
+#define LM3633_BOOST_OVP_MASK (BIT(1) | BIT(2))
+
+#define LM3633_REG_PWM_CFG 0x2F
+
+#define LM3633_REG_BRT_HVLED_A_LSB 0x40
+#define LM3633_REG_BRT_HVLED_A_MSB 0x41
+#define LM3633_REG_BRT_HVLED_B_LSB 0x42
+#define LM3633_REG_BRT_HVLED_B_MSB 0x43
+#define LM3633_BRT_HVLED_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LM3633_BRT_HVLED_MSB_SHIFT 3
+
+#define LM3633_REG_BRT_LVLED_BASE 0x44
+
+#define LM3633_REG_DELAY 0x50
+#define LM3633_DELAY_MASK LMU_FULL_MASKBIT
+#define LM3633_DELAY_SHIFT 0
+
+#define LM3633_REG_LOWTIME 0x51
+#define LM3633_LOWTIME_MASK LMU_FULL_MASKBIT
+#define LM3633_LOWTIME_SHIFT 0
+
+#define LM3633_REG_HIGHTIME 0x52
+#define LM3633_HIGHTIME_MASK LMU_FULL_MASKBIT
+#define LM3633_HIGHTIME_SHIFT 0
+
+#define LM3633_REG_LOWBRT 0x53
+#define LM3633_LOWBRT_MASK LMU_FULL_MASKBIT
+#define LM3633_LOWBRT_SHIFT 0
+
+#define LM3633_REG_HIGHBRT LM3633_REG_BRT_LVLED_BASE
+#define LM3633_HIGHBRT_MASK LMU_FULL_MASKBIT
+#define LM3633_HIGHBRT_SHIFT 0
+
+#define LM3633_PATTERN_REG_OFFSET 16
+
+#define LM3633_MAX_REGISTERS 0xB4
+
+/* LM3695 */
+#define LM3695_REG_GP 0x10
+#define LM3695_BL_STRING_MASK BIT(3)
+#define LM3695_BL_TWO_STRINGS 0
+#define LM3695_BL_ONE_STRING BIT(3)
+#define LM3695_BRT_RW_MASK BIT(2)
+#define LM3695_BRT_SET_RW BIT(2)
+#define LM3695_BL_EN_MASK BIT(0)
+
+#define LM3695_REG_BRT_LSB 0x13
+#define LM3695_BRT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LM3695_REG_BRT_MSB 0x14
+#define LM3695_BRT_MSB_SHIFT 3
+
+#define LM3695_MAX_REGISTERS 0x14
+
+/* LM3697 */
+#define LM3697_REG_HVLED_OUTPUT_CFG 0x10
+
+#define LM3697_REG_BL0_RAMPUP 0x11
+#define LM3697_REG_BL0_RAMPDN LM3697_REG_BL0_RAMPUP
+#define LM3697_BL0_RAMPUP_MASK 0xF0
+#define LM3697_BL0_RAMPUP_SHIFT 4
+#define LM3697_BL0_RAMPDN_MASK 0x0F
+#define LM3697_BL0_RAMPDN_SHIFT 0
+
+#define LM3697_REG_BL1_RAMPUP 0x12
+#define LM3697_REG_BL1_RAMPDN LM3697_REG_BL1_RAMPUP
+#define LM3697_BL1_RAMPUP_MASK LM3697_BL0_RAMPUP_MASK
+#define LM3697_BL1_RAMPUP_SHIFT LM3697_BL0_RAMPUP_SHIFT
+#define LM3697_BL1_RAMPDN_MASK LM3697_BL0_RAMPDN_MASK
+#define LM3697_BL1_RAMPDN_SHIFT LM3697_BL0_RAMPDN_SHIFT
+
+#define LM3697_REG_RAMP_CONF 0x14
+#define LM3697_RAMP_MASK 0x0F
+#define LM3697_RAMP_EACH 0x05
+
+#define LM3697_REG_PWM_CFG 0x1C
+
+#define LM3697_REG_IMAX_A 0x17
+#define LM3697_REG_IMAX_B 0x18
+
+#define LM3697_REG_BOOST_CFG 0x1A
+#define LM3697_BOOST_FREQ_MASK BIT(0)
+#define LM3697_BOOST_FREQ_SHIFT 0
+#define LM3697_BOOST_OVP_MASK (BIT(1) | BIT(2))
+#define LM3697_BOOST_OVP_SHIFT 1
+
+#define LM3697_REG_BRT_A_LSB 0x20
+#define LM3697_REG_BRT_A_MSB 0x21
+#define LM3697_REG_BRT_B_LSB 0x22
+#define LM3697_REG_BRT_B_MSB 0x23
+#define LM3697_BRT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LM3697_BRT_MSB_SHIFT 3
+
+#define LM3697_REG_ENABLE 0x24
+
+#define LM3697_MAX_REGISTERS 0xB4
+#endif
diff --git a/include/linux/mfd/ti-lmu.h b/include/linux/mfd/ti-lmu.h
new file mode 100644
index 0000000..c785a0d
--- /dev/null
+++ b/include/linux/mfd/ti-lmu.h
@@ -0,0 +1,150 @@
+/*
+ * TI LMU(Lighting Management Unit) Devices
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim-l0cyMroinI0@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __MFD_TI_LMU_H__
+#define __MFD_TI_LMU_H__
+
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+
+#define LM3631_NUM_REGULATORS 5
+
+enum ti_lmu_id {
+ LM3532,
+ LM3631,
+ LM3633,
+ LM3695,
+ LM3697,
+};
+
+enum ti_lmu_max_current {
+ LMU_IMAX_5mA,
+ LMU_IMAX_6mA,
+ LMU_IMAX_7mA = 0x03,
+ LMU_IMAX_8mA,
+ LMU_IMAX_9mA,
+ LMU_IMAX_10mA = 0x07,
+ LMU_IMAX_11mA,
+ LMU_IMAX_12mA,
+ LMU_IMAX_13mA,
+ LMU_IMAX_14mA,
+ LMU_IMAX_15mA = 0x0D,
+ LMU_IMAX_16mA,
+ LMU_IMAX_17mA,
+ LMU_IMAX_18mA,
+ LMU_IMAX_19mA,
+ LMU_IMAX_20mA = 0x13,
+ LMU_IMAX_21mA,
+ LMU_IMAX_22mA,
+ LMU_IMAX_23mA = 0x17,
+ LMU_IMAX_24mA,
+ LMU_IMAX_25mA,
+ LMU_IMAX_26mA,
+ LMU_IMAX_27mA = 0x1C,
+ LMU_IMAX_28mA,
+ LMU_IMAX_29mA,
+ LMU_IMAX_30mA,
+};
+
+/*
+ * struct lm3633_bl_platform_data
+ * @name: Backlight device name
+ * @bl_string: Bit mask of backlight output string
+ * @imax: Max current for backlight output string
+ * @init_brightness: Initial brightness value
+ * @ramp_up_ms: Backlight light effect for ramp up or slope rate
+ * @ramp_down_ms: Backlight light effect for ramp down rate
+ * @pwm_period: Platform specific PWM period value. unit is nano
+ */
+struct ti_lmu_backlight_platform_data {
+ const char *name;
+
+ unsigned long bl_string; /* bit OR mask of LMU_HVLEDx */
+#define LMU_HVLED1 BIT(0)
+#define LMU_HVLED2 BIT(1)
+#define LMU_HVLED3 BIT(2)
+
+ enum ti_lmu_max_current imax;
+ u8 init_brightness;
+
+ /* Used for light effect */
+ unsigned int ramp_up_ms;
+ unsigned int ramp_down_ms;
+
+ /* Only valid in case of PWM mode */
+ unsigned int pwm_period;
+};
+
+/*
+ * struct lmu_led_platform_data
+ * @name: LED channel name
+ * @led_string: Bit mask of LED output string
+ * @imax: LED max current
+ */
+struct ti_lmu_led_platform_data {
+ const char *name;
+
+ unsigned long led_string; /* bit OR mask of LMU_LVLEDx */;
+#define LMU_LVLED1 BIT(0)
+#define LMU_LVLED2 BIT(1)
+#define LMU_LVLED3 BIT(2)
+#define LMU_LVLED4 BIT(3)
+#define LMU_LVLED5 BIT(4)
+#define LMU_LVLED6 BIT(5)
+
+ enum ti_lmu_max_current imax;
+};
+
+/*
+ * struct lmu_platform_data
+ * @en_gpio: GPIO for HWEN pin
+ * @bl_pdata: Backlight platform data
+ * @num_backlights: Number of backlight outputs
+ * @led_pdata: LED platform data
+ * @num_leds: Number of LED outputs
+ * @regulator_data: Regulator init data
+ */
+struct ti_lmu_platform_data {
+ int en_gpio;
+
+ /* Backlight */
+ struct ti_lmu_backlight_platform_data *bl_pdata;
+ int num_backlights;
+
+ /* LEDs */
+ struct ti_lmu_led_platform_data *led_pdata;
+ int num_leds;
+
+ /* Regulators of LM3631 */
+ struct regulator_init_data *regulator_data[LM3631_NUM_REGULATORS];
+};
+
+/*
+ * struct ti_lmu
+ * @id: Chip ID
+ * @dev: Parent device pointer
+ * @regmap: Used for i2c communcation on accessing registers
+ * @pdata: LMU platform specific data
+ */
+struct ti_lmu {
+ int id;
+ struct device *dev;
+ struct regmap *regmap;
+ struct ti_lmu_platform_data *pdata;
+};
+
+int ti_lmu_read_byte(struct ti_lmu *lmu, u8 reg, u8 *read);
+int ti_lmu_write_byte(struct ti_lmu *lmu, u8 reg, u8 data);
+int ti_lmu_update_bits(struct ti_lmu *lmu, u8 reg, u8 mask, u8 data);
+enum ti_lmu_max_current ti_lmu_get_current_code(u8 imax);
+#endif
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 02/10] backlight: Add TI LMU backlight common driver
From: Milo Kim @ 2014-02-14 6:31 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel, devicetree, Samuel Ortiz, Milo Kim
TI LMU backlight driver provides common driver features.
Chip specific configuration is handled by each backlight driver such like
LM3532, LM3631, LM3633, LM3695 and LM3697.
It supports common features as below.
- Consistent device control flow
- Control bank assignment from the platform data
- Backlight subsystem control
- PWM brightness control
- Shared device tree node
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
drivers/video/backlight/Kconfig | 7 +
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/ti-lmu-backlight.c | 369 ++++++++++++++++++++++++++++
drivers/video/backlight/ti-lmu-backlight.h | 78 ++++++
4 files changed, 455 insertions(+)
create mode 100644 drivers/video/backlight/ti-lmu-backlight.c
create mode 100644 drivers/video/backlight/ti-lmu-backlight.h
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 5a3eb2e..3641698 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -384,6 +384,13 @@ config BACKLIGHT_LM3639
help
This supports TI LM3639 Backlight + 1.5A Flash LED Driver
+config TI_LMU_BACKLIGHT
+ tristate "Backlight driver for TI LMU"
+ depends on BACKLIGHT_LM3532 || BACKLIGHT_LM3631 || BACKLIGHT_LM3633 || BACKLIGHT_LM3695 || BACKLIGHT_LM3697
+ help
+ TI LMU backlight driver provides common driver features.
+ Chip specific configuration is handled by each backlight driver.
+
config BACKLIGHT_LP855X
tristate "Backlight driver for TI LP855X"
depends on BACKLIGHT_CLASS_DEVICE && I2C
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index bb82002..f80e046 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
+obj-$(CONFIG_TI_LMU_BACKLIGHT) += ti-lmu-backlight.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o
diff --git a/drivers/video/backlight/ti-lmu-backlight.c b/drivers/video/backlight/ti-lmu-backlight.c
new file mode 100644
index 0000000..5ceb5e8
--- /dev/null
+++ b/drivers/video/backlight/ti-lmu-backlight.c
@@ -0,0 +1,369 @@
+/*
+ * TI LMU Backlight Common Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LMU backlight driver supports common features as below.
+ *
+ * - Consistent device control flow by using ti_lmu_bl_ops
+ * - Control bank assignment from the platform data
+ * - Backlight subsystem control
+ * - PWM brightness control
+ * - Shared device tree node
+ *
+ * Sequence of LMU backlight control
+ *
+ * (Chip dependent backlight driver) (TI LMU Backlight Common)
+ *
+ * Operation configuration
+ * ti_lmu_backlight_init_device() --->
+ * Initialization <--- ops->init()
+ *
+ * ti_lmu_backlight_register() --->
+ * Backlight configuration <--- ops->configure()
+ *
+ * Runtime brightness control
+ * Enable register control <--- ops->bl_enable()
+ * Brightness register control <--- ops->update_brightness()
+ *
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include "ti-lmu-backlight.h"
+
+#define DEFAULT_BL_NAME "lcd-backlight"
+
+static int ti_lmu_backlight_enable(struct ti_lmu_bl *lmu_bl, int enable)
+{
+ const struct ti_lmu_bl_ops *ops = lmu_bl->chip->ops;
+
+ if (ops->bl_enable)
+ return ops->bl_enable(lmu_bl, enable);
+
+ return 0;
+}
+
+static void ti_lmu_backlight_pwm_ctrl(struct ti_lmu_bl *lmu_bl, int br,
+ int max_br)
+{
+ struct pwm_device *pwm;
+ unsigned int duty, period;
+
+ /* Request a PWM device with the consumer name */
+ if (!lmu_bl->pwm) {
+ pwm = devm_pwm_get(lmu_bl->chip->dev, lmu_bl->pwm_name);
+ if (IS_ERR(pwm)) {
+ dev_err(lmu_bl->chip->dev,
+ "Can not get PWM device: %s\n",
+ lmu_bl->pwm_name);
+ return;
+ }
+ lmu_bl->pwm = pwm;
+ }
+
+ period = lmu_bl->bl_pdata->pwm_period;
+ duty = br * period / max_br;
+
+ pwm_config(lmu_bl->pwm, duty, period);
+ if (duty)
+ pwm_enable(lmu_bl->pwm);
+ else
+ pwm_disable(lmu_bl->pwm);
+}
+
+static int ti_lmu_backlight_update_status(struct backlight_device *bl_dev)
+{
+ struct ti_lmu_bl *lmu_bl = bl_get_data(bl_dev);
+ const struct ti_lmu_bl_ops *ops = lmu_bl->chip->ops;
+ int ret = 0;
+ int brt;
+
+ if (bl_dev->props.state & BL_CORE_SUSPENDED)
+ bl_dev->props.brightness = 0;
+
+ brt = bl_dev->props.brightness;
+ if (brt > 0)
+ ret = ti_lmu_backlight_enable(lmu_bl, 1);
+ else
+ ret = ti_lmu_backlight_enable(lmu_bl, 0);
+
+ if (ret)
+ return ret;
+
+ if (lmu_bl->mode == BL_PWM_BASED)
+ ti_lmu_backlight_pwm_ctrl(lmu_bl, brt,
+ bl_dev->props.max_brightness);
+
+ /*
+ * In some devices, additional handling is required after PWM control.
+ * So, just call device-specific brightness function.
+ */
+ if (ops->update_brightness)
+ return ops->update_brightness(lmu_bl, brt);
+
+ return 0;
+}
+
+static int ti_lmu_backlight_get_brightness(struct backlight_device *bl_dev)
+{
+ return bl_dev->props.brightness;
+}
+
+static const struct backlight_ops lmu_bl_common_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = ti_lmu_backlight_update_status,
+ .get_brightness = ti_lmu_backlight_get_brightness,
+};
+
+static int ti_lmu_backlight_parse_dt(struct device *dev, struct ti_lmu *lmu)
+{
+ struct ti_lmu_backlight_platform_data *pdata;
+ struct device_node *node = dev->of_node;
+ struct device_node *child;
+ int num_backlights;
+ int i = 0;
+ u8 imax_mA;
+
+ if (!node) {
+ dev_err(dev, "No device node exists\n");
+ return -ENODEV;
+ }
+
+ num_backlights = of_get_child_count(node);
+ if (num_backlights == 0) {
+ dev_err(dev, "No backlight strings\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata) * num_backlights, GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ for_each_child_of_node(node, child) {
+ of_property_read_string(child, "bl-name", &pdata[i].name);
+
+ /* Make backlight strings */
+ pdata[i].bl_string = 0;
+ if (of_find_property(child, "hvled1-used", NULL))
+ pdata[i].bl_string |= LMU_HVLED1;
+ if (of_find_property(child, "hvled2-used", NULL))
+ pdata[i].bl_string |= LMU_HVLED2;
+ if (of_find_property(child, "hvled3-used", NULL))
+ pdata[i].bl_string |= LMU_HVLED3;
+
+ of_property_read_u8(child, "max-current-milliamp", &imax_mA);
+ pdata[i].imax = ti_lmu_get_current_code(imax_mA);
+
+ of_property_read_u8(child, "initial-brightness",
+ &pdata[i].init_brightness);
+
+ /* Light effect */
+ of_property_read_u32(child, "ramp-up", &pdata[i].ramp_up_ms);
+ of_property_read_u32(child, "ramp-down",
+ &pdata[i].ramp_down_ms);
+
+ /* PWM mode */
+ of_property_read_u32(child, "pwm-period", &pdata[i].pwm_period);
+
+ i++;
+ }
+
+ lmu->pdata->bl_pdata = pdata;
+ lmu->pdata->num_backlights = num_backlights;
+
+ return 0;
+}
+
+struct ti_lmu_bl_chip *
+ti_lmu_backlight_init_device(struct device *dev, struct ti_lmu *lmu,
+ const struct ti_lmu_bl_ops *ops)
+{
+ struct ti_lmu_bl_chip *chip;
+ int ret;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return ERR_PTR(-ENOMEM);
+
+ chip->dev = dev;
+ chip->lmu = lmu;
+ chip->ops = ops;
+
+ if (!lmu->pdata->bl_pdata) {
+ if (IS_ENABLED(CONFIG_OF))
+ ret = ti_lmu_backlight_parse_dt(dev, lmu);
+ else
+ return ERR_PTR(-ENODEV);
+
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ if (chip->ops->init) {
+ ret = chip->ops->init(chip);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ return chip;
+}
+EXPORT_SYMBOL_GPL(ti_lmu_backlight_init_device);
+
+static void ti_lmu_backlight_set_ctrl_mode(struct ti_lmu_bl *lmu_bl)
+{
+ struct ti_lmu_backlight_platform_data *pdata = lmu_bl->bl_pdata;
+
+ if (pdata->pwm_period > 0)
+ lmu_bl->mode = BL_PWM_BASED;
+ else
+ lmu_bl->mode = BL_REGISTER_BASED;
+}
+
+static int ti_lmu_backlight_configure(struct ti_lmu_bl *lmu_bl)
+{
+ const struct ti_lmu_bl_ops *ops = lmu_bl->chip->ops;
+
+ if (ops->configure)
+ return ops->configure(lmu_bl);
+
+ return 0;
+}
+
+static int ti_lmu_backlight_add_device(struct ti_lmu_bl *lmu_bl)
+{
+ struct backlight_device *bl_dev;
+ struct backlight_properties props;
+ struct ti_lmu_backlight_platform_data *pdata = lmu_bl->bl_pdata;
+ int max_brightness = lmu_bl->chip->ops->max_brightness;
+ char name[20];
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_PLATFORM;
+ props.brightness = pdata ? pdata->init_brightness : 0;
+ props.max_brightness = max_brightness;
+
+ /* Backlight device name */
+ if (!pdata->name)
+ snprintf(name, sizeof(name), "%s:%d", DEFAULT_BL_NAME,
+ lmu_bl->bank_id);
+ else
+ snprintf(name, sizeof(name), "%s", pdata->name);
+
+ bl_dev = backlight_device_register(name, lmu_bl->chip->dev, lmu_bl,
+ &lmu_bl_common_ops, &props);
+ if (IS_ERR(bl_dev))
+ return PTR_ERR(bl_dev);
+
+ lmu_bl->bl_dev = bl_dev;
+
+ return 0;
+}
+
+struct ti_lmu_bl *
+ti_lmu_backlight_register(struct ti_lmu_bl_chip *chip,
+ struct ti_lmu_backlight_platform_data *pdata,
+ int num_backlights)
+{
+ struct ti_lmu_bl *lmu_bl, *each;
+ int i, ret;
+
+ lmu_bl = devm_kzalloc(chip->dev, sizeof(*lmu_bl) * num_backlights,
+ GFP_KERNEL);
+ if (!lmu_bl)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < num_backlights; i++) {
+ each = lmu_bl + i;
+ each->bank_id = i;
+ each->chip = chip;
+ each->bl_pdata = pdata + i;
+
+ ti_lmu_backlight_set_ctrl_mode(lmu_bl);
+
+ ret = ti_lmu_backlight_configure(each);
+ if (ret) {
+ dev_err(chip->dev, "Backlight config err: %d\n", ret);
+ goto err;
+ }
+
+ ret = ti_lmu_backlight_add_device(each);
+ if (ret) {
+ dev_err(chip->dev, "Backlight device err: %d\n", ret);
+ goto cleanup_backlights;
+ }
+
+ backlight_update_status(each->bl_dev);
+ }
+
+ chip->num_backlights = num_backlights;
+
+ return lmu_bl;
+
+cleanup_backlights:
+ while (--i >= 0) {
+ each = lmu_bl + i;
+ backlight_device_unregister(each->bl_dev);
+ }
+err:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_backlight_register);
+
+int ti_lmu_backlight_unregister(struct ti_lmu_bl *lmu_bl)
+{
+ struct ti_lmu_bl *each;
+ struct backlight_device *bl_dev;
+ int num_backlights = lmu_bl->chip->num_backlights;
+ int i;
+
+ for (i = 0; i < num_backlights; i++) {
+ each = lmu_bl + i;
+
+ bl_dev = each->bl_dev;
+ bl_dev->props.brightness = 0;
+ backlight_update_status(bl_dev);
+ backlight_device_unregister(bl_dev);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ti_lmu_backlight_unregister);
+
+/*
+ * This callback function is invoked in case the LMU effect driver is
+ * requested successfully.
+ */
+void ti_lmu_backlight_effect_callback(struct ti_lmu_effect *lmu_effect,
+ int req_id, void *data)
+{
+ struct ti_lmu_bl *lmu_bl = data;
+ unsigned int ramp_time;
+
+ if (req_id == BL_EFFECT_RAMPUP)
+ ramp_time = lmu_bl->bl_pdata->ramp_up_ms;
+ else if (req_id == BL_EFFECT_RAMPDN)
+ ramp_time = lmu_bl->bl_pdata->ramp_down_ms;
+ else
+ return;
+
+ ti_lmu_effect_set_ramp(lmu_effect, ramp_time);
+}
+EXPORT_SYMBOL_GPL(ti_lmu_backlight_effect_callback);
+
+MODULE_DESCRIPTION("TI LMU Backlight Common Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ti-lmu-backlight.h b/drivers/video/backlight/ti-lmu-backlight.h
new file mode 100644
index 0000000..7dd2fa5d
--- /dev/null
+++ b/drivers/video/backlight/ti-lmu-backlight.h
@@ -0,0 +1,78 @@
+/*
+ * TI LMU Backlight Common Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __TI_LMU_BACKLIGHT_H__
+#define __TI_LMU_BACKLIGHT_H__
+
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+
+#define LMU_BL_DEFAULT_PWM_NAME "lmu-backlight"
+
+enum ti_lmu_bl_ctrl_mode {
+ BL_REGISTER_BASED,
+ BL_PWM_BASED,
+};
+
+struct ti_lmu_bl;
+struct ti_lmu_bl_chip;
+
+/*
+ * struct ti_lmu_bl_ops
+ * @init: Device specific initialization
+ * @configure: Device specific string configuration
+ * @update_brightness: Device specific brightness control
+ * @bl_enable: Device specific backlight enable/disable control
+ * @max_brightness: Max brightness value of backlight device
+ */
+struct ti_lmu_bl_ops {
+ int (*init)(struct ti_lmu_bl_chip *lmu_chip);
+ int (*configure)(struct ti_lmu_bl *lmu_bl);
+ int (*update_brightness)(struct ti_lmu_bl *lmu_bl, int brightness);
+ int (*bl_enable)(struct ti_lmu_bl *lmu_bl, int enable);
+ const int max_brightness;
+};
+
+/* One backlight chip can have multiple backlight strings */
+struct ti_lmu_bl_chip {
+ struct device *dev;
+ struct ti_lmu *lmu;
+ const struct ti_lmu_bl_ops *ops;
+ int num_backlights;
+};
+
+/* Backlight string structure */
+struct ti_lmu_bl {
+ int bank_id;
+ struct backlight_device *bl_dev;
+ struct ti_lmu_bl_chip *chip;
+ struct ti_lmu_backlight_platform_data *bl_pdata;
+ enum ti_lmu_bl_ctrl_mode mode;
+ struct pwm_device *pwm;
+ char pwm_name[20];
+};
+
+struct ti_lmu_bl_chip *
+ti_lmu_backlight_init_device(struct device *dev, struct ti_lmu *lmu,
+ const struct ti_lmu_bl_ops *ops);
+
+struct ti_lmu_bl *
+ti_lmu_backlight_register(struct ti_lmu_bl_chip *chip,
+ struct ti_lmu_backlight_platform_data *pdata,
+ int num_backlights);
+
+int ti_lmu_backlight_unregister(struct ti_lmu_bl *lmu_bl);
+
+void ti_lmu_backlight_effect_callback(struct ti_lmu_effect *lmu_effect,
+ int req_id, void *data);
+#endif
--
1.7.9.5
^ permalink raw reply related
* [PATCH 03/10] backlight: ti-lmu-backlight: Add LM3532 driver
From: Milo Kim @ 2014-02-14 6:31 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel, devicetree, Samuel Ortiz, Milo Kim
LM3532 has 3 backlight strings and 8 bit dimming is supported.
PWM brightness control is also supported.
Common backlight driver is controlled by TI LMU backlight driver.
Only LM3532 specific code is implemented here.
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
drivers/video/backlight/Kconfig | 9 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/lm3532_bl.c | 240 +++++++++++++++++++++++++++++++++++
3 files changed, 250 insertions(+)
create mode 100644 drivers/video/backlight/lm3532_bl.c
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 3641698..d841057 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -384,6 +384,15 @@ config BACKLIGHT_LM3639
help
This supports TI LM3639 Backlight + 1.5A Flash LED Driver
+config BACKLIGHT_LM3532
+ tristate "Backlight driver for TI LM3532"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU
+ select TI_LMU_BACKLIGHT
+ help
+ Say Y to enable the backlight driver for TI LM3532.
+ Up to 3 backlight strings and 8 bit dimming is supported.
+ PWM brightness control is also supported.
+
config TI_LMU_BACKLIGHT
tristate "Backlight driver for TI LMU"
depends on BACKLIGHT_LM3532 || BACKLIGHT_LM3631 || BACKLIGHT_LM3633 || BACKLIGHT_LM3695 || BACKLIGHT_LM3697
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index f80e046..51354d1 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3532) += lm3532_bl.o
obj-$(CONFIG_TI_LMU_BACKLIGHT) += ti-lmu-backlight.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
diff --git a/drivers/video/backlight/lm3532_bl.c b/drivers/video/backlight/lm3532_bl.c
new file mode 100644
index 0000000..c4cf636
--- /dev/null
+++ b/drivers/video/backlight/lm3532_bl.c
@@ -0,0 +1,240 @@
+/*
+ * TI LM3532 Backlight Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LM3532 backlight driver consists of three parts
+ *
+ * 1) LM3532 chip specific part: this file
+ * Define device specific operations
+ * Register LMU backlight driver
+ *
+ * 2) LMU backlight common driver: ti-lmu-backlight
+ * General backlight subsystem control
+ *
+ * 3) LMU effect driver
+ * Backlight ramp time configuration
+ *
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include "ti-lmu-backlight.h"
+
+#define LM3532_PWM1 0
+#define LM3532_PWM2 1
+#define LM3532_BL_MAX_STRINGS 3
+#define LM3532_MAX_ZONE_CFG 3
+#define LM3532_MAX_BRIGHTNESS 255
+
+static int lm3532_bl_init(struct ti_lmu_bl_chip *chip)
+{
+ int i, ret;
+ u8 lm3532_regs[] = { LM3532_REG_ZONE_CFG_A, LM3532_REG_ZONE_CFG_B,
+ LM3532_REG_ZONE_CFG_C, };
+
+ /*
+ * Assign zone targets as below.
+ * Zone target 0 for control A
+ * Zone target 1 for control B
+ * Zone target 2 for control C
+ */
+
+ for (i = 0; i < LM3532_MAX_ZONE_CFG; i++) {
+ ret = ti_lmu_update_bits(chip->lmu, lm3532_regs[i],
+ LM3532_ZONE_CFG_MASK,
+ i << LM3532_ZONE_CFG_SHIFT);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int lm3532_bl_enable(struct ti_lmu_bl *lmu_bl, int enable)
+{
+ return ti_lmu_update_bits(lmu_bl->chip->lmu, LM3532_REG_ENABLE,
+ BIT(lmu_bl->bank_id),
+ enable << lmu_bl->bank_id);
+}
+
+static int lm3532_bl_set_brightness(struct ti_lmu_bl *lmu_bl, int brightness)
+{
+ u8 reg[] = { LM3532_REG_BRT_A, LM3532_REG_BRT_B, LM3532_REG_BRT_C, };
+
+ return ti_lmu_write_byte(lmu_bl->chip->lmu, reg[lmu_bl->bank_id],
+ brightness);
+}
+
+static int lm3532_bl_select_pwm_bank(struct ti_lmu_bl *lmu_bl, int bank_id)
+{
+ struct ti_lmu *lmu = lmu_bl->chip->lmu;
+ static int num_pwms;
+ u8 pwm_sel;
+ u8 mask[] = { LM3532_PWM_SEL_A_MASK, LM3532_PWM_SEL_B_MASK,
+ LM3532_PWM_SEL_C_MASK, };
+ u8 shift[] = { LM3532_PWM_SEL_A_SHIFT, LM3532_PWM_SEL_B_SHIFT,
+ LM3532_PWM_SEL_C_SHIFT, };
+
+ if (num_pwms > 0)
+ pwm_sel = LM3532_PWM2;
+ else
+ pwm_sel = LM3532_PWM1;
+
+ num_pwms++;
+
+ snprintf(lmu_bl->pwm_name, sizeof(lmu_bl->pwm_name), "%s:%d",
+ LMU_BL_DEFAULT_PWM_NAME, pwm_sel);
+
+ return ti_lmu_update_bits(lmu, LM3532_REG_PWM_CFG_BASE + bank_id,
+ mask[bank_id],
+ (1 << shift[bank_id]) | pwm_sel);
+}
+
+static int lm3532_bl_string_configure(struct ti_lmu_bl *lmu_bl)
+{
+ struct ti_lmu *lmu = lmu_bl->chip->lmu;
+ int bank_id = lmu_bl->bank_id;
+ int is_detected = 0;
+ int i, ret;
+ u8 mask[] = { LM3532_ILED1_CFG_MASK, LM3532_ILED2_CFG_MASK,
+ LM3532_ILED3_CFG_MASK, };
+ u8 shift[] = { LM3532_ILED1_CFG_SHIFT, LM3532_ILED2_CFG_SHIFT,
+ LM3532_ILED3_CFG_SHIFT, };
+
+ /* Assign control bank from backlight string configuration */
+ for (i = 0; i < LM3532_BL_MAX_STRINGS; i++) {
+ if (test_bit(i, &lmu_bl->bl_pdata->bl_string)) {
+ ret = ti_lmu_update_bits(lmu, LM3532_REG_OUTPUT_CFG,
+ mask[i], bank_id << shift[i]);
+ if (ret)
+ return ret;
+
+ is_detected = 1;
+ }
+ }
+
+ if (!is_detected) {
+ dev_err(lmu_bl->chip->dev, "No backlight string found\n");
+ return -EINVAL;
+ }
+
+ if (lmu_bl->mode == BL_PWM_BASED)
+ return lm3532_bl_select_pwm_bank(lmu_bl, bank_id);
+
+ return 0;
+}
+
+static int lm3532_bl_set_current(struct ti_lmu_bl *lmu_bl)
+{
+ u8 reg[] = { LM3532_REG_IMAX_A, LM3532_REG_IMAX_B, LM3532_REG_IMAX_C };
+
+ return ti_lmu_write_byte(lmu_bl->chip->lmu, reg[lmu_bl->bank_id],
+ lmu_bl->bl_pdata->imax);
+}
+
+static void lm3532_bl_effect_request(struct ti_lmu_bl *lmu_bl)
+{
+ int i;
+ const char *name[] = {
+ [BL_EFFECT_RAMPUP] = LM3532_EFFECT_RAMPUP,
+ [BL_EFFECT_RAMPDN] = LM3532_EFFECT_RAMPDOWN,
+ };
+
+ for (i = BL_EFFECT_RAMPUP; i <= BL_EFFECT_RAMPDN; i++)
+ ti_lmu_effect_request(name[i],
+ ti_lmu_backlight_effect_callback,
+ i, lmu_bl);
+}
+
+static int lm3532_bl_configure(struct ti_lmu_bl *lmu_bl)
+{
+ int ret;
+
+ ret = lm3532_bl_string_configure(lmu_bl);
+ if (ret)
+ return ret;
+
+ ret = lm3532_bl_set_current(lmu_bl);
+ if (ret)
+ return ret;
+
+ /* LMU effect is optional, checking return value is not required */
+ lm3532_bl_effect_request(lmu_bl);
+
+ return 0;
+}
+
+static const struct ti_lmu_bl_ops lm3532_lmu_ops = {
+ .init = lm3532_bl_init,
+ .configure = lm3532_bl_configure,
+ .update_brightness = lm3532_bl_set_brightness,
+ .bl_enable = lm3532_bl_enable,
+ .max_brightness = LM3532_MAX_BRIGHTNESS,
+};
+
+static int lm3532_bl_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct ti_lmu_bl_chip *chip;
+ struct ti_lmu_bl *lmu_bl;
+
+ chip = ti_lmu_backlight_init_device(&pdev->dev, lmu, &lm3532_lmu_ops);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ lmu_bl = ti_lmu_backlight_register(chip, lmu->pdata->bl_pdata,
+ lmu->pdata->num_backlights);
+ if (IS_ERR(lmu_bl))
+ return PTR_ERR(lmu_bl);
+
+ platform_set_drvdata(pdev, lmu_bl);
+
+ return 0;
+}
+
+static int lm3532_bl_remove(struct platform_device *pdev)
+{
+ struct ti_lmu_bl *lmu_bl = platform_get_drvdata(pdev);
+
+ return ti_lmu_backlight_unregister(lmu_bl);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3532_bl_of_match[] = {
+ { .compatible = "ti,lm3532-backlight", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3532_bl_of_match);
+#endif
+
+static struct platform_driver lm3532_bl_driver = {
+ .probe = lm3532_bl_probe,
+ .remove = lm3532_bl_remove,
+ .driver = {
+ .name = "lm3532-backlight",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3532_bl_of_match),
+ },
+};
+module_platform_driver(lm3532_bl_driver);
+
+MODULE_DESCRIPTION("TI LM3532 Backlight Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3532-backlight");
--
1.7.9.5
^ permalink raw reply related
* [PATCH 04/10] backlight: ti-lmu-backlight: Add LM3631 driver
From: Milo Kim @ 2014-02-14 6:31 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel, devicetree, Samuel Ortiz, Milo Kim
LM3631 has 2 backlight strings and 11 bit dimming is supported.
PWM brightness control is also supported.
Common backlight driver is controlled by TI LMU backlight driver.
Only LM3631 specific code is implemented here.
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
drivers/video/backlight/Kconfig | 9 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/lm3631_bl.c | 186 +++++++++++++++++++++++++++++++++++
3 files changed, 196 insertions(+)
create mode 100644 drivers/video/backlight/lm3631_bl.c
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index d841057..a43a015 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -393,6 +393,15 @@ config BACKLIGHT_LM3532
Up to 3 backlight strings and 8 bit dimming is supported.
PWM brightness control is also supported.
+config BACKLIGHT_LM3631
+ tristate "Backlight driver for TI LM3631"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU
+ select TI_LMU_BACKLIGHT
+ help
+ Say Y to enable the backlight driver for TI LM3631.
+ Up to 2 backlight strings and 11 bit dimming is supported.
+ PWM brightness control is also supported.
+
config TI_LMU_BACKLIGHT
tristate "Backlight driver for TI LMU"
depends on BACKLIGHT_LM3532 || BACKLIGHT_LM3631 || BACKLIGHT_LM3633 || BACKLIGHT_LM3695 || BACKLIGHT_LM3697
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 51354d1..2a17f8b 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
obj-$(CONFIG_BACKLIGHT_LM3532) += lm3532_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3631) += lm3631_bl.o
obj-$(CONFIG_TI_LMU_BACKLIGHT) += ti-lmu-backlight.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
diff --git a/drivers/video/backlight/lm3631_bl.c b/drivers/video/backlight/lm3631_bl.c
new file mode 100644
index 0000000..45693c0
--- /dev/null
+++ b/drivers/video/backlight/lm3631_bl.c
@@ -0,0 +1,186 @@
+/*
+ * TI LM3631 Backlight Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LM3631 backlight driver consists of three parts
+ *
+ * 1) LM3631 chip specific part: this file
+ * Define device specific operations
+ * Register LMU backlight driver
+ *
+ * 2) LMU backlight common driver: ti-lmu-backlight
+ * General backlight subsystem control
+ *
+ * 3) LMU effect driver
+ * Backlight slope time configuration
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include "ti-lmu-backlight.h"
+
+#define LM3631_FULL_STRINGS (LMU_HVLED1 | LMU_HVLED2)
+#define LM3631_DEFAULT_MODE LM3631_MODE_COMB1
+#define LM3631_MAX_BRIGHTNESS 2047
+
+static int lm3631_bl_init(struct ti_lmu_bl_chip *chip)
+{
+ int ret;
+
+ /* Set OVP to 25V by default */
+ ret = ti_lmu_update_bits(chip->lmu, LM3631_REG_BL_BOOST,
+ LM3631_BOOST_OVP_MASK, LM3631_BOOST_OVP_25V);
+ if (ret)
+ return ret;
+
+ /* Set the brightness mode to 'comb1' by default */
+ return ti_lmu_update_bits(chip->lmu, LM3631_REG_BRT_MODE,
+ LM3631_MODE_MASK, LM3631_DEFAULT_MODE);
+}
+
+static int lm3631_bl_enable(struct ti_lmu_bl *lmu_bl, int enable)
+{
+ return ti_lmu_update_bits(lmu_bl->chip->lmu, LM3631_REG_DEVCTRL,
+ LM3631_BL_EN_MASK,
+ enable << LM3631_BL_EN_SHIFT);
+}
+
+static int lm3631_bl_set_brightness(struct ti_lmu_bl *lmu_bl, int brightness)
+{
+ u8 data;
+ int ret;
+
+ if (lmu_bl->mode == BL_PWM_BASED)
+ return 0;
+
+ data = brightness & LM3631_BRT_LSB_MASK;
+ ret = ti_lmu_update_bits(lmu_bl->chip->lmu, LM3631_REG_BRT_LSB,
+ LM3631_BRT_LSB_MASK, data);
+ if (ret)
+ return ret;
+
+ data = (brightness >> LM3631_BRT_MSB_SHIFT) & 0xFF;
+ return ti_lmu_write_byte(lmu_bl->chip->lmu, LM3631_REG_BRT_MSB,
+ data);
+}
+
+static int lm3631_bl_string_configure(struct ti_lmu_bl *lmu_bl)
+{
+ u8 val;
+
+ if (lmu_bl->bl_pdata->bl_string == LM3631_FULL_STRINGS)
+ val = LM3631_BL_TWO_STRINGS;
+ else
+ val = LM3631_BL_ONE_STRING;
+
+ return ti_lmu_update_bits(lmu_bl->chip->lmu, LM3631_REG_BL_CFG,
+ LM3631_BL_STRING_MASK, val);
+}
+
+static void lm3631_bl_effect_request(struct ti_lmu_bl *lmu_bl)
+{
+ /* Set exponential mapping */
+ ti_lmu_update_bits(lmu_bl->chip->lmu, LM3631_REG_BL_CFG,
+ LM3631_MAP_MASK, LM3631_EXPONENTIAL_MAP);
+
+ /* Enable slope bit before updating slope time value */
+ ti_lmu_update_bits(lmu_bl->chip->lmu, LM3631_REG_BRT_MODE,
+ LM3631_EN_SLOPE_MASK, LM3631_EN_SLOPE_MASK);
+
+ ti_lmu_effect_request(LM3631_EFFECT_SLOPE,
+ ti_lmu_backlight_effect_callback,
+ BL_EFFECT_RAMPUP, lmu_bl);
+}
+
+static int lm3631_bl_configure(struct ti_lmu_bl *lmu_bl)
+{
+ int ret;
+
+ ret = lm3631_bl_string_configure(lmu_bl);
+ if (ret)
+ return ret;
+
+ if (lmu_bl->mode == BL_PWM_BASED) {
+ snprintf(lmu_bl->pwm_name, sizeof(lmu_bl->pwm_name),
+ "%s", LMU_BL_DEFAULT_PWM_NAME);
+ }
+
+ /* LMU effect is optional, checking return value is not required */
+ lm3631_bl_effect_request(lmu_bl);
+
+ return 0;
+}
+
+static const struct ti_lmu_bl_ops lm3631_lmu_ops = {
+ .init = lm3631_bl_init,
+ .configure = lm3631_bl_configure,
+ .update_brightness = lm3631_bl_set_brightness,
+ .bl_enable = lm3631_bl_enable,
+ .max_brightness = LM3631_MAX_BRIGHTNESS,
+};
+
+static int lm3631_bl_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct ti_lmu_bl *lmu_bl;
+ struct ti_lmu_bl_chip *chip;
+
+ chip = ti_lmu_backlight_init_device(&pdev->dev, lmu, &lm3631_lmu_ops);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ lmu_bl = ti_lmu_backlight_register(chip, lmu->pdata->bl_pdata, 1);
+ if (IS_ERR(lmu_bl))
+ return PTR_ERR(lmu_bl);
+
+ platform_set_drvdata(pdev, lmu_bl);
+
+ return 0;
+}
+
+static int lm3631_bl_remove(struct platform_device *pdev)
+{
+ struct ti_lmu_bl *lmu_bl = platform_get_drvdata(pdev);
+
+ return ti_lmu_backlight_unregister(lmu_bl);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3631_bl_of_match[] = {
+ { .compatible = "ti,lm3631-backlight", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3631_bl_of_match);
+#endif
+
+static struct platform_driver lm3631_bl_driver = {
+ .probe = lm3631_bl_probe,
+ .remove = lm3631_bl_remove,
+ .driver = {
+ .name = "lm3631-backlight",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3631_bl_of_match),
+ },
+};
+module_platform_driver(lm3631_bl_driver);
+
+MODULE_DESCRIPTION("TI LM3631 Backlight Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3631-backlight");
--
1.7.9.5
^ permalink raw reply related
* [PATCH 05/10] backlight: ti-lmu-backlight: Add LM3633 driver
From: Milo Kim @ 2014-02-14 6:31 UTC (permalink / raw)
To: Lee Jones, Jingoo Han, Bryan Wu, Mark Brown
Cc: linux-kernel, devicetree, Samuel Ortiz, Milo Kim
LM3633 has 3 backlight strings and 11 bit dimming is supported.
PWM brightness control is also supported.
Common backlight driver is controlled by TI LMU backlight driver.
Only LM3633 specific code is implemented here.
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Bryan Wu <cooloney@gmail.com>
Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
drivers/video/backlight/Kconfig | 9 ++
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/lm3633_bl.c | 244 +++++++++++++++++++++++++++++++++++
3 files changed, 254 insertions(+)
create mode 100644 drivers/video/backlight/lm3633_bl.c
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a43a015..aa012a3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -402,6 +402,15 @@ config BACKLIGHT_LM3631
Up to 2 backlight strings and 11 bit dimming is supported.
PWM brightness control is also supported.
+config BACKLIGHT_LM3633
+ tristate "Backlight driver for TI LM3633"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU
+ select TI_LMU_BACKLIGHT
+ help
+ Say Y to enable the backlight driver for TI LM3633.
+ Up to 3 backlight strings and 11 bit dimming is supported.
+ PWM brightness control is also supported.
+
config TI_LMU_BACKLIGHT
tristate "Backlight driver for TI LMU"
depends on BACKLIGHT_LM3532 || BACKLIGHT_LM3631 || BACKLIGHT_LM3633 || BACKLIGHT_LM3695 || BACKLIGHT_LM3697
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 2a17f8b..842a256 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
obj-$(CONFIG_BACKLIGHT_LM3532) += lm3532_bl.o
obj-$(CONFIG_BACKLIGHT_LM3631) += lm3631_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3633) += lm3633_bl.o
obj-$(CONFIG_TI_LMU_BACKLIGHT) += ti-lmu-backlight.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
diff --git a/drivers/video/backlight/lm3633_bl.c b/drivers/video/backlight/lm3633_bl.c
new file mode 100644
index 0000000..c12fd42
--- /dev/null
+++ b/drivers/video/backlight/lm3633_bl.c
@@ -0,0 +1,244 @@
+/*
+ * TI LM3633 Backlight Driver
+ *
+ * Copyright 2014 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * LM3633 backlight driver consists of two parts
+ *
+ * 1) LM3633 chip specific part: this file
+ * Define device specific operations
+ * Register LMU backlight driver
+ *
+ * 2) LMU backlight common driver: ti-lmu-backlight
+ * General backlight subsystem control
+ *
+ * 3) LMU effect driver
+ * Backlight slope time configuration
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-effect.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#include "ti-lmu-backlight.h"
+
+#define LM3633_BOOST_OVP_40V 0x6
+#define LM3633_BL_MAX_STRINGS 3
+#define LM3633_BL_MAX_BRIGHTNESS 2047
+
+static int lm3633_bl_init(struct ti_lmu_bl_chip *chip)
+{
+ /* Configure ramp selection for each bank */
+ return ti_lmu_update_bits(chip->lmu, LM3633_REG_BL_RAMP_CONF,
+ LM3633_BL_RAMP_MASK, LM3633_BL_RAMP_EACH);
+}
+
+static int lm3633_bl_enable(struct ti_lmu_bl *lmu_bl, int enable)
+{
+ return ti_lmu_update_bits(lmu_bl->chip->lmu, LM3633_REG_ENABLE,
+ BIT(lmu_bl->bank_id),
+ enable << lmu_bl->bank_id);
+}
+
+static int lm3633_bl_set_brightness(struct ti_lmu_bl *lmu_bl, int brightness)
+{
+ int ret;
+ u8 data;
+ u8 reg_lsb[] = { LM3633_REG_BRT_HVLED_A_LSB,
+ LM3633_REG_BRT_HVLED_B_LSB, };
+ u8 reg_msb[] = { LM3633_REG_BRT_HVLED_A_MSB,
+ LM3633_REG_BRT_HVLED_B_MSB, };
+
+ if (lmu_bl->mode == BL_PWM_BASED) {
+ /*
+ * PWM can start from any non-zero code and dim down to zero.
+ * So, brightness register should be updated even in PWM mode.
+ */
+ if (brightness > 0)
+ brightness = LM3633_BL_MAX_BRIGHTNESS;
+ else
+ brightness = 0;
+ }
+
+ data = brightness & LM3633_BRT_HVLED_LSB_MASK;
+ ret = ti_lmu_update_bits(lmu_bl->chip->lmu, reg_lsb[lmu_bl->bank_id],
+ LM3633_BRT_HVLED_LSB_MASK, data);
+ if (ret)
+ return ret;
+
+ data = (brightness >> LM3633_BRT_HVLED_MSB_SHIFT) & 0xFF;
+ return ti_lmu_write_byte(lmu_bl->chip->lmu, reg_msb[lmu_bl->bank_id],
+ data);
+}
+
+static int lm3633_bl_boost_configure(struct ti_lmu_bl *lmu_bl)
+{
+ return ti_lmu_update_bits(lmu_bl->chip->lmu, LM3633_REG_BOOST_CFG,
+ LM3633_BOOST_OVP_MASK, LM3633_BOOST_OVP_40V);
+}
+
+static int lm3633_bl_set_ctrl_mode(struct ti_lmu_bl *lmu_bl)
+{
+ int bank_id = lmu_bl->bank_id;
+
+ if (lmu_bl->mode == BL_PWM_BASED)
+ return ti_lmu_update_bits(lmu_bl->chip->lmu,
+ LM3633_REG_PWM_CFG,
+ BIT(bank_id), 1 << bank_id);
+
+ return 0;
+}
+
+static int lm3633_bl_string_configure(struct ti_lmu_bl *lmu_bl)
+{
+ struct ti_lmu *lmu = lmu_bl->chip->lmu;
+ int is_detected = 0;
+ int i, ret;
+
+ /* Assign control bank from backlight string configuration */
+ for (i = 0; i < LM3633_BL_MAX_STRINGS; i++) {
+ if (test_bit(i, &lmu_bl->bl_pdata->bl_string)) {
+ ret = ti_lmu_update_bits(lmu,
+ LM3633_REG_HVLED_OUTPUT_CFG,
+ BIT(i), lmu_bl->bank_id << i);
+ if (ret)
+ return ret;
+
+ is_detected = 1;
+ }
+ }
+
+ if (!is_detected) {
+ dev_err(lmu_bl->chip->dev, "No backlight string found\n");
+ return -EINVAL;
+ }
+
+ if (lmu_bl->mode == BL_PWM_BASED) {
+ snprintf(lmu_bl->pwm_name, sizeof(lmu_bl->pwm_name),
+ "%s", LMU_BL_DEFAULT_PWM_NAME);
+ }
+
+ return 0;
+}
+
+static int lm3633_bl_set_current(struct ti_lmu_bl *lmu_bl)
+{
+ u8 reg[] = { LM3633_REG_IMAX_HVLED_A, LM3633_REG_IMAX_HVLED_B, };
+
+ return ti_lmu_write_byte(lmu_bl->chip->lmu, reg[lmu_bl->bank_id],
+ lmu_bl->bl_pdata->imax);
+}
+
+static void lm3633_bl_effect_request(enum lmu_effect_request_id id,
+ struct ti_lmu_bl *lmu_bl)
+{
+ const char *name[][2] = {
+ { LM3633_EFFECT_BL0_RAMPUP, LM3633_EFFECT_BL0_RAMPDOWN },
+ { LM3633_EFFECT_BL1_RAMPUP, LM3633_EFFECT_BL1_RAMPDOWN },
+ };
+
+ ti_lmu_effect_request(name[lmu_bl->bank_id][id],
+ ti_lmu_backlight_effect_callback, id, lmu_bl);
+}
+
+static int lm3633_bl_configure(struct ti_lmu_bl *lmu_bl)
+{
+ int ret;
+
+ ret = lm3633_bl_boost_configure(lmu_bl);
+ if (ret)
+ return ret;
+
+ ret = lm3633_bl_set_ctrl_mode(lmu_bl);
+ if (ret)
+ return ret;
+
+ ret = lm3633_bl_string_configure(lmu_bl);
+ if (ret)
+ return ret;
+
+ ret = lm3633_bl_set_current(lmu_bl);
+ if (ret)
+ return ret;
+
+ /* LMU effect is optional, checking return value is not required */
+ if (lmu_bl->bl_pdata->ramp_up_ms)
+ lm3633_bl_effect_request(BL_EFFECT_RAMPUP, lmu_bl);
+
+ if (lmu_bl->bl_pdata->ramp_down_ms)
+ lm3633_bl_effect_request(BL_EFFECT_RAMPDN, lmu_bl);
+
+ return 0;
+}
+
+static const struct ti_lmu_bl_ops lm3633_lmu_ops = {
+ .init = lm3633_bl_init,
+ .configure = lm3633_bl_configure,
+ .update_brightness = lm3633_bl_set_brightness,
+ .bl_enable = lm3633_bl_enable,
+ .max_brightness = LM3633_BL_MAX_BRIGHTNESS,
+};
+
+static int lm3633_bl_probe(struct platform_device *pdev)
+{
+ struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+ struct ti_lmu_bl *lmu_bl;
+ struct ti_lmu_bl_chip *chip;
+
+ chip = ti_lmu_backlight_init_device(&pdev->dev, lmu, &lm3633_lmu_ops);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ lmu_bl = ti_lmu_backlight_register(chip, lmu->pdata->bl_pdata,
+ lmu->pdata->num_backlights);
+ if (IS_ERR(lmu_bl))
+ return PTR_ERR(lmu_bl);
+
+ platform_set_drvdata(pdev, lmu_bl);
+
+ return 0;
+}
+
+static int lm3633_bl_remove(struct platform_device *pdev)
+{
+ struct ti_lmu_bl *lmu_bl = platform_get_drvdata(pdev);
+
+ return ti_lmu_backlight_unregister(lmu_bl);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id lm3633_bl_of_match[] = {
+ { .compatible = "ti,lm3633-backlight", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lm3633_bl_of_match);
+#endif
+
+static struct platform_driver lm3633_bl_driver = {
+ .probe = lm3633_bl_probe,
+ .remove = lm3633_bl_remove,
+ .driver = {
+ .name = "lm3633-backlight",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lm3633_bl_of_match),
+ },
+};
+module_platform_driver(lm3633_bl_driver);
+
+MODULE_DESCRIPTION("TI LM3633 Backlight Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lm3633-backlight");
--
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