Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 3/9] Doc/DT: Add DT binding documentation for DVI Connector
From: Geert Uytterhoeven @ 2014-03-11  8:00 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: devicetree@vger.kernel.org, Linux Fbdev development list,
	Russell King - ARM Linux, DRI Development, Andrzej Hajda,
	Rob Herring, Laurent Pinchart,
	linux-arm-kernel@lists.infradead.org, Sebastian Hesselbarth
In-Reply-To: <531EAF8F.2040400@ti.com>

On Tue, Mar 11, 2014 at 7:39 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> On 10/03/14 23:45, Rob Herring wrote:
>> I like this proposal over the others. Although, would dual link be a
>
> I don't like inferring the information. With the above, you can't find
> out that the DVI connector has digital and analog support before all the
> drivers are loaded.
>
>> single endpoint or 2 endpoints? How would you differentiate that?
>
> Hmm, well endpoints for a single port are exclusive. So it's either a
> single port and a single endpoint, or two ports and two endpoints. I
> think dual link has to be single port & endpoint, as the TMDS links need
> to be driven together as a single bus.
>
> And dual-link is not really "two links". DVI dual-link means 1 clock
> lane and 6 data lanes, compared to 1 clock lane and 3 data lanes for
> single-link.

What about having a property for the number of data lanes?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 3/9] Doc/DT: Add DT binding documentation for DVI Connector
From: Tomi Valkeinen @ 2014-03-11  8:04 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: devicetree@vger.kernel.org, Linux Fbdev development list,
	Russell King - ARM Linux, Sascha Hauer, Tomasz Figa,
	DRI Development, Inki Dae, Andrzej Hajda, Rob Clark,
	Thierry Reding, Laurent Pinchart, Philipp Zabel,
	linux-arm-kernel@lists.infradead.org, Sebastian Hesselbarth
In-Reply-To: <CAMuHMdWqt4M5OEXp8y_DR8UEA8GPxJg99cz-HcmMPQB+h+Rh0A@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]

On 11/03/14 10:00, Geert Uytterhoeven wrote:
> On Tue, Mar 11, 2014 at 7:39 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
>> On 10/03/14 23:45, Rob Herring wrote:
>>> I like this proposal over the others. Although, would dual link be a
>>
>> I don't like inferring the information. With the above, you can't find
>> out that the DVI connector has digital and analog support before all the
>> drivers are loaded.
>>
>>> single endpoint or 2 endpoints? How would you differentiate that?
>>
>> Hmm, well endpoints for a single port are exclusive. So it's either a
>> single port and a single endpoint, or two ports and two endpoints. I
>> think dual link has to be single port & endpoint, as the TMDS links need
>> to be driven together as a single bus.
>>
>> And dual-link is not really "two links". DVI dual-link means 1 clock
>> lane and 6 data lanes, compared to 1 clock lane and 3 data lanes for
>> single-link.
> 
> What about having a property for the number of data lanes?

That was already suggested by Philipp in this thread. I don't see
anything wrong with that, but I don't really see benefit either.
"dual-link" is a standard term for 6 data lanes for the DVI connector.
And the choices are 3 or 6 data lanes, nothing else.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCHv3 00/41] OMAPDSS: DT support v3
From: Tomi Valkeinen @ 2014-03-11 10:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140310154105.GA4882@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 3067 bytes --]

On 10/03/14 17:41, Tony Lindgren wrote:

>>> How about do a pull request for just the .dts changes against current
>>> omap-for-v3.15/dt branch ASAP for me so I can pull it in? That is assuming
>>> that just the .dts changes alone won't break anything.
>>
>> Unfortunately they do break. At least pinmuxing is moved from the global
>> definitions to be handled by the respective display drivers, and there
>> are some regulator_name hacks that the DT patches remove.
> 
> OK. Will that cause regressions for omap3 as that's still also booting
> in legacy mode?

No, I don't think so. The problems revolve around the pdata-quirks, with
current DSS support when booting with DT. It's rather difficult to split
the series so that it could be merged freely in multiple parts.

If I split the series into three parts: 1) .dts changes 2) main DSS DT
changes 3) removal of pdata-quirks etc, I run into problems. Both 1) and
2) work fine individually, but when both are merged, there are two
competing systems, the proper DT stuff and the pdata-quirks stuff. And I
haven't found out a simple way to manage that, as the whole display
support is split into multiple independent devices.

One option would be to combine 1) and 3), so that when they are merged,
there would be proper DT data, and the pdata-quirks would be removed so
that it wouldn't be messing everything up. But that would, of course,
mean that after merging 1+3, the display wouldn't work on those boards
that rely on pdata-quirks, until 2) is merged.

>> I think those changes could be removed from my patches, and then added
>> back later when everything else has been merged.
> 
> Or you could have a second branch that also merges in omap-for-v3.15/dt
> branch that you can send later towards the merge window after the arm-soc
> changes have been merged. If you want to do that, then feel free to add
> my ack also for the .dts changes:
> 
> Acked-by: Tony Lindgren <tony@atomide.com>
> 
> If however those changes get postponed to v3.16, it's best that you'll
> redo the branch as I'm sure we'll have other merge issues for v3.16.

Ok. At the moment I feel that the easiest option would be to keep the
DSS DT series as it is, but merge omap-for-v3.15/dt to it and solve the
conflicts. I'd keep that branch separate from the fbdev changes, so that
I could send the DSS DT pull request later, when arm-soc has been pulled.

>> The bigger issue is that suddenly there's lots of discussion about the
>> display DT bindings. If those are not resolved very soon, I guess I have
>> no choice but to again skip the merge window for the DSS DT changes.
> 
> OK, some of these more bindings can take easily six months to reach
> some kind of resolution. You may be able to use TI specific unstable
> bindings meanwhile if that makese sense.

Yep. I don't know... If the whole port/endpoint system that I currently
use is changed totally, it might be painful to support both the TI
specific bindings with the old format and the newer format.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCH 3/9] Doc/DT: Add DT binding documentation for DVI Connector
From: Philipp Zabel @ 2014-03-11 11:19 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: devicetree@vger.kernel.org, Linux Fbdev development list,
	Russell King - ARM Linux, DRI Development, Andrzej Hajda,
	Rob Herring, Laurent Pinchart, Geert Uytterhoeven,
	linux-arm-kernel@lists.infradead.org, Sebastian Hesselbarth
In-Reply-To: <531EC385.7090001@ti.com>

Am Dienstag, den 11.03.2014, 10:04 +0200 schrieb Tomi Valkeinen:
> On 11/03/14 10:00, Geert Uytterhoeven wrote:
> > On Tue, Mar 11, 2014 at 7:39 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> >> On 10/03/14 23:45, Rob Herring wrote:
> >>> I like this proposal over the others. Although, would dual link be a
> >>
> >> I don't like inferring the information. With the above, you can't find
> >> out that the DVI connector has digital and analog support before all the
> >> drivers are loaded.
> >>
> >>> single endpoint or 2 endpoints? How would you differentiate that?
> >>
> >> Hmm, well endpoints for a single port are exclusive. So it's either a
> >> single port and a single endpoint, or two ports and two endpoints. I
> >> think dual link has to be single port & endpoint, as the TMDS links need
> >> to be driven together as a single bus.
> >>
> >> And dual-link is not really "two links". DVI dual-link means 1 clock
> >> lane and 6 data lanes, compared to 1 clock lane and 3 data lanes for
> >> single-link.
> > 
> > What about having a property for the number of data lanes?
> 
> That was already suggested by Philipp in this thread. I don't see
> anything wrong with that, but I don't really see benefit either.
> "dual-link" is a standard term for 6 data lanes for the DVI connector.
> And the choices are 3 or 6 data lanes, nothing else.

The number of lanes of a DisplayPort connector could be 1 to 4. Also,
there's dual-mode DP which can use four lanes to drive
somewhat-like-HDMI single link TMDS signals.

regards
Philipp


^ permalink raw reply

* Fwd: Addition to https://www.kernel.org/doc/Documentation/fb/deferred_io.txt
From: Geert Uytterhoeven @ 2014-03-11 16:05 UTC (permalink / raw)
  To: linux-fbdev

--------- Forwarded message ----------
From: Conor O <falling174fps@gmail.com>
Date: Tue, Mar 11, 2014 at 4:36 PM
Subject: Addition to https://www.kernel.org/doc/Documentation/fb/deferred_io.txt
To: Geert Uytterhoeven <geert@linux-m68k.org>


Dear Geert,

Having run into this problem myself
(http://stackoverflow.com/questions/22285151/kernel-panic-using-deferred-io-on-kmalloced-buffer)
I'd like to suggest an addendum to the deferred_io.txt document to
note the difference in treatment between a framebuffer allocated with
vmalloc and one allocated with, say, kmalloc. I've pasted in the diff
below.

Thanks,

Conor O'Rourke.

$ diff deferred_io.txt deferred_io_changes.txt
75a76,89
>
> 5. Bear in mind the following:
>
>   - deferred_io changes info->fp_ops->fb_mmap to its own function that
>     sets up fault handlers etc. In the fault handler it checks bounds
>     against info->fix.smem_len
>
>   - when it gets the page written, it checks the address in info->screen_base
>     to see if that address is one from vmalloc. If so it uses that address
>     as the one to get the page number. If not, the assumption is that the
>     address of interest is the physical framebuffer address stored in
>     info->fix.smem_start. You can get an physical address from, say, a
>     kmalloced pointer by using virt_to_phys().
>

^ permalink raw reply

* Re: [PATCHv3 00/41] OMAPDSS: DT support v3
From: Tony Lindgren @ 2014-03-11 16:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <531EE25B.9060201@ti.com>

* Tomi Valkeinen <tomi.valkeinen@ti.com> [140311 03:19]:
> On 10/03/14 17:41, Tony Lindgren wrote:
> 
> >>> How about do a pull request for just the .dts changes against current
> >>> omap-for-v3.15/dt branch ASAP for me so I can pull it in? That is assuming
> >>> that just the .dts changes alone won't break anything.
> >>
> >> Unfortunately they do break. At least pinmuxing is moved from the global
> >> definitions to be handled by the respective display drivers, and there
> >> are some regulator_name hacks that the DT patches remove.
> > 
> > OK. Will that cause regressions for omap3 as that's still also booting
> > in legacy mode?
> 
> No, I don't think so. The problems revolve around the pdata-quirks, with
> current DSS support when booting with DT. It's rather difficult to split
> the series so that it could be merged freely in multiple parts.
> 
> If I split the series into three parts: 1) .dts changes 2) main DSS DT
> changes 3) removal of pdata-quirks etc, I run into problems. Both 1) and
> 2) work fine individually, but when both are merged, there are two
> competing systems, the proper DT stuff and the pdata-quirks stuff. And I
> haven't found out a simple way to manage that, as the whole display
> support is split into multiple independent devices.
> 
> One option would be to combine 1) and 3), so that when they are merged,
> there would be proper DT data, and the pdata-quirks would be removed so
> that it wouldn't be messing everything up. But that would, of course,
> mean that after merging 1+3, the display wouldn't work on those boards
> that rely on pdata-quirks, until 2) is merged.

OK, best to keep the series together then.
 
> >> I think those changes could be removed from my patches, and then added
> >> back later when everything else has been merged.
> > 
> > Or you could have a second branch that also merges in omap-for-v3.15/dt
> > branch that you can send later towards the merge window after the arm-soc
> > changes have been merged. If you want to do that, then feel free to add
> > my ack also for the .dts changes:
> > 
> > Acked-by: Tony Lindgren <tony@atomide.com>
> > 
> > If however those changes get postponed to v3.16, it's best that you'll
> > redo the branch as I'm sure we'll have other merge issues for v3.16.
> 
> Ok. At the moment I feel that the easiest option would be to keep the
> DSS DT series as it is, but merge omap-for-v3.15/dt to it and solve the
> conflicts. I'd keep that branch separate from the fbdev changes, so that
> I could send the DSS DT pull request later, when arm-soc has been pulled.

OK makes sense to me.
 
> >> The bigger issue is that suddenly there's lots of discussion about the
> >> display DT bindings. If those are not resolved very soon, I guess I have
> >> no choice but to again skip the merge window for the DSS DT changes.
> > 
> > OK, some of these more bindings can take easily six months to reach
> > some kind of resolution. You may be able to use TI specific unstable
> > bindings meanwhile if that makese sense.
> 
> Yep. I don't know... If the whole port/endpoint system that I currently
> use is changed totally, it might be painful to support both the TI
> specific bindings with the old format and the newer format.

OK that's up you guys in the display land, I have not followed the
latest bindings discussion.

Regards,

Tony

^ permalink raw reply

* Re: [PATCH 0/9] Doc/DT: DT bindings for various display components
From: Tomi Valkeinen @ 2014-03-12  8:15 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Philipp Zabel,
	Laurent Pinchart, Russell King - ARM Linux, Sascha Hauer,
	Sebastian Hesselbarth, Rob Clark, Inki Dae, Andrzej Hajda,
	Tomasz Figa, Thierry Reding
In-Reply-To: <1393590016-9361-1-git-send-email-tomi.valkeinen-l0cyMroinI0@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]

Hi Grant,

On 28/02/14 14:20, Tomi Valkeinen wrote:
> Hi,
> 
> This series is a re-send of
> http://article.gmane.org/gmane.linux.drivers.devicetree/61739
> 
> I'm cc'ing more people, and I want to clarify the contents of the series:
> 
> While this has been developed for OMAP, only the first patch is about OMAP
> bindings. The rest are generic bindings for video components, which can be used
> on any platform.
> 
> The bindings use the V4L2 style video port/endpoint system, described in
> Documentation/devicetree/bindings/media/video-interfaces.txt, to connect the
> components. The same port/endpoint bindings are used by Philipp Zabel in his
> imx-drm patch series.

This series is a piece of bigger series, which brings DT support for
OMAP display subsystem. This uses the same V4L2 style ports/endpoints as
has been discussed recently regarding the series from Philipp. It
doesn't use the helper code from Philipp, but a custom one as Philipp's
code didn't exist when I made this, and also because I needed extra
functionality not present in Philipp's series (which aimed to just move
the current V4L2 code to a common place).

The main concerns with the ports/endpoints has been the optional 'port'
node for the case where we have a single endpoint, and the
double-linking of the endpoints.

If I remove the optional 'port' usage from my series, are you ok with me
proceeding with this series for 3.15, with the double-linked endpoints?

As far as I see, when we come to a conclusion how the linking should be
made, it's trivial to change the bindings in this series to match it,
even without needing any compatibility code. I just need to remove the
other link, and old dts files having double-linking will still work fine.

The reason I want to push this forward asap is that omap4 and omap5 are
already DT only, and for omap5 we don't have working display without DT
support for display. For omap4, we have a really hacky way to add
display support for a few boards, but that is causing major headaches
and I want to get rid of it.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCH] video: atmel_lcdfb: ensure the hardware is initialized with the correct mode
From: Nicolas Ferre @ 2014-03-12  9:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1394209254-23797-1-git-send-email-antoine.tenart@free-electrons.com>

On 07/03/2014 17:20, Antoine Ténart :
> If no driver takeover the atmel_lcdfb, the lcd won't be in a working state
> since atmel_lcdfb_set_par() will never be called. Enabling a driver which does,
> like fbcon, will call the function and put atmel_lcdfb in a working state.
> 
> Fixes: b985172b328a (video: atmel_lcdfb: add device tree suport)
> 
> Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
> Reported-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Thanks for having fixing this.

Bye,

> ---
>  drivers/video/atmel_lcdfb.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index cd96162..b74e5f5d 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -1298,6 +1298,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  		goto unregister_irqs;
>  	}
>  
> +	ret = atmel_lcdfb_set_par(info);
> +	if (ret < 0) {
> +		dev_err(dev, "set par failed: %d\n", ret);
> +		goto unregister_irqs;
> +	}
> +
>  	dev_set_drvdata(dev, info);
>  
>  	/*
> 


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH] video: atmel_lcdfb: ensure the hardware is initialized with the correct mode
From: Tomi Valkeinen @ 2014-03-12 11:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1394209254-23797-1-git-send-email-antoine.tenart@free-electrons.com>

[-- Attachment #1: Type: text/plain, Size: 1143 bytes --]

On 07/03/14 18:20, Antoine Ténart wrote:
> If no driver takeover the atmel_lcdfb, the lcd won't be in a working state
> since atmel_lcdfb_set_par() will never be called. Enabling a driver which does,
> like fbcon, will call the function and put atmel_lcdfb in a working state.
> 
> Fixes: b985172b328a (video: atmel_lcdfb: add device tree suport)
> 
> Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
> Reported-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
>  drivers/video/atmel_lcdfb.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index cd96162..b74e5f5d 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -1298,6 +1298,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  		goto unregister_irqs;
>  	}
>  
> +	ret = atmel_lcdfb_set_par(info);
> +	if (ret < 0) {
> +		dev_err(dev, "set par failed: %d\n", ret);
> +		goto unregister_irqs;
> +	}
> +
>  	dev_set_drvdata(dev, info);
>  
>  	/*
> 

Thanks, queued for 3.15.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCH] backlight: add new LP8860 backlight driver
From: Daniel Jeong @ 2014-03-13  5:01 UTC (permalink / raw)
  To: Jingoo Han
  Cc: linux-fbdev, linux-kernel,
	'Jean-Christophe Plagniol-Villard',
	'Tomi Valkeinen', 'Bryan Wu', 'Lee Jones'
In-Reply-To: <001b01cf3c40$a4b347e0$ee19d7a0$%han@samsung.com>

Thank you for your comments

> On Monday, March 03, 2014 6:15 PM, Daniel Jeong wrote:
> (+CC Bryan Wu, Lee Jones)
>
> Please add Bryan Wu, Lee Jones to CC list, when you send
> patches for backlight.
>
>>   This patch adds LP8860 backlight device driver.
>> LP8860 is a low EMI and High performance 4 channel LED Driver of TI.
>> This device driver provide the way to control brightness and currnet
> (+CC Bryan Wu, Lee Jones)
>
> s/provide/provides
> s/currnet/current
>
>> of each channel and provide the way to write eeprom.
> s/provide/provides
>
>> To support dt structure, another patch file will be sent.
>>
>> Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
>> ---
> 'To support dt structure, another patch file will be sent.' is
> NOT appropriate for the commit message. So, please move it as below.
> Then, this message will not be included to the commit message, when
> this patch will be merged to maintainer's tree.
>
> Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
> ---
> To support dt structure, another patch file will be sent.
>
>
>>   drivers/video/backlight/Kconfig         |    7 +
>>   drivers/video/backlight/Makefile        |    1 +
>>   drivers/video/backlight/lp8860_bl.c     |  528 +++++++++++++++++++++++++++++++
>>   include/linux/platform_data/lp8860_bl.h |   54 ++++
>>   4 files changed, 590 insertions(+)
>>   create mode 100644 drivers/video/backlight/lp8860_bl.c
>>   create mode 100644 include/linux/platform_data/lp8860_bl.h
>>
>> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
>> index 5a3eb2e..908048f 100644
>> --- a/drivers/video/backlight/Kconfig
>> +++ b/drivers/video/backlight/Kconfig
>> @@ -397,6 +397,13 @@ config BACKLIGHT_LP8788
>>   	help
>>   	  This supports TI LP8788 backlight driver.
>>
>> +config BACKLIGHT_LP8860
>> +	tristate "Backlight Driver for LP8860"
>> +	depends on BACKLIGHT_CLASS_DEVICE && I2C
>> +	select REGMAP_I2C
>> +	help
>> +	  This supports TI LP8860 Backlight Driver
>> +
>>   config BACKLIGHT_OT200
>>   	tristate "Backlight driver for ot200 visualisation device"
>>   	depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
>> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
>> index bb82002..cbc5ac3 100644
>> --- a/drivers/video/backlight/Makefile
>> +++ b/drivers/video/backlight/Makefile
>> @@ -42,6 +42,7 @@ obj-$(CONFIG_BACKLIGHT_LM3639)		+= lm3639_bl.o
>>   obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
>>   obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
>>   obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
>> +obj-$(CONFIG_BACKLIGHT_LP8860)		+= lp8860_bl.o
>>   obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
>>   obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
>>   obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
>> diff --git a/drivers/video/backlight/lp8860_bl.c b/drivers/video/backlight/lp8860_bl.c
>> new file mode 100644
>> index 0000000..4712e84
>> --- /dev/null
>> +++ b/drivers/video/backlight/lp8860_bl.c
>> @@ -0,0 +1,528 @@
>> +/*
>> +* Simple driver for Texas Instruments lp8860 Backlight driver chip
>> +*
>> +* Copyright (C) 2014 Texas Instruments
>> +* Author: Daniel Jeong  <gshark.jeong@gmail.com>
>> +*		  Ldd Mlp <ldd-mlp@list.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.
>> +*
>> +*/
>> +#include <linux/module.h>
> Please move this header in alphabetical order.
>
>> +#include <linux/backlight.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/platform_data/lp8860_bl.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>> +#include <linux/uaccess.h>
>> +
>> +#define REG_CL0_BRT_H	0x00
>> +#define REG_CL0_BRT_L	0x01
>> +#define REG_CL0_I_H		0x02
>> +#define REG_CL0_I_L		0x03
>> +
>> +#define REG_CL1_BRT_H	0x04
>> +#define REG_CL1_BRT_L	0x05
>> +#define REG_CL1_I		0x06
>> +
>> +#define REG_CL2_BRT_H	0x07
>> +#define REG_CL2_BRT_L	0x08
>> +#define REG_CL2_I		0x09
>> +
>> +#define REG_CL3_BRT_H	0x0a
>> +#define REG_CL3_BRT_L	0x0b
>> +#define REG_CL3_I		0x0c
>> +
>> +#define REG_CONF	0x0d
>> +#define REG_STATUS	0x0e
>> +#define REG_ID		0x12
>> +
>> +#define REG_ROM_CTRL	0x19
>> +#define REG_ROM_UNLOCK	0x1a
>> +#define REG_ROM_START	0x60
>> +#define REG_ROM_END		0x78
>> +
>> +#define REG_EEPROM_START	0x60
>> +#define REG_EEPROM_END		0x78
>> +#define REG_MAX	0xFF
>> +
>> +struct lp8860_chip {
>> +	struct device *dev;
>> +	struct lp8860_platform_data *pdata;
>> +	struct backlight_device *bled[LP8860_LED_MAX];
>> +	struct regmap *regmap;
>> +};
>> +
>> +/* brightness control */
>> +static int lp8860_bled_update_status(struct backlight_device *bl,
>> +				     enum lp8860_leds nsr)
>> +{
>> +	int ret = -EINVAL;
>> +	struct lp8860_chip *pchip = bl_get_data(bl);
>> +
>> +	if (pchip->pdata->mode)
>> +		return 0;
>> +
>> +	if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
>> +		bl->props.brightness = 0;
>> +
>> +	switch (nsr) {
>> +	case LP8860_LED0:
>> +		ret = regmap_write(pchip->regmap,
>> +				   REG_CL0_BRT_H, bl->props.brightness >> 8);
>> +		ret |= regmap_write(pchip->regmap,
>> +				    REG_CL0_BRT_L, bl->props.brightness & 0xff);
>> +		break;
>> +	case LP8860_LED1:
>> +		ret = regmap_write(pchip->regmap,
>> +				   REG_CL1_BRT_H,
>> +				   (bl->props.brightness >> 8) & 0x1f);
>> +		ret |>> +		    regmap_write(pchip->regmap, REG_CL1_BRT_L,
>> +				 bl->props.brightness & 0xff);
>> +		break;
>> +	case LP8860_LED2:
>> +		ret = regmap_write(pchip->regmap,
>> +				   REG_CL2_BRT_H,
>> +				   (bl->props.brightness >> 8) & 0x1f);
>> +		ret |>> +		    regmap_write(pchip->regmap, REG_CL2_BRT_L,
>> +				 bl->props.brightness & 0xff);
>> +		break;
>> +	case LP8860_LED3:
>> +		ret = regmap_write(pchip->regmap,
>> +				   REG_CL3_BRT_H,
>> +				   (bl->props.brightness >> 8) & 0x1f);
>> +		ret |>> +		    regmap_write(pchip->regmap, REG_CL3_BRT_L,
>> +				 bl->props.brightness & 0xff);
>> +		break;
>> +	default:
>> +		BUG();
>> +	}
>> +	if (ret < 0)
>> +		dev_err(pchip->dev, "fail : i2c access to register.\n");
>> +	else
>> +		ret = bl->props.brightness;
>> +
>> +	return ret;
>> +}
>> +
>> +static int lp8860_bled_get_brightness(struct backlight_device *bl,
>> +				      enum lp8860_leds nsr)
>> +{
>> +	struct lp8860_chip *pchip = bl_get_data(bl);
>> +	unsigned int rval_h, rval_l;
>> +	int ret = -EINVAL;
>> +
>> +	switch (nsr) {
>> +	case LP8860_LED0:
>> +		ret = regmap_read(pchip->regmap, REG_CL0_BRT_H, &rval_h);
>> +		ret |= regmap_read(pchip->regmap, REG_CL0_BRT_L, &rval_l);
>> +		break;
>> +	case LP8860_LED1:
>> +		ret = regmap_read(pchip->regmap, REG_CL1_BRT_H, &rval_h);
>> +		ret |= regmap_read(pchip->regmap, REG_CL1_BRT_L, &rval_l);
>> +		break;
>> +	case LP8860_LED2:
>> +		ret = regmap_read(pchip->regmap, REG_CL2_BRT_H, &rval_h);
>> +		ret |= regmap_read(pchip->regmap, REG_CL2_BRT_L, &rval_l);
>> +		break;
>> +	case LP8860_LED3:
>> +		ret = regmap_read(pchip->regmap, REG_CL3_BRT_H, &rval_h);
>> +		ret |= regmap_read(pchip->regmap, REG_CL3_BRT_L, &rval_l);
>> +		break;
>> +	default:
>> +		BUG();
>> +	}
>> +	if (ret < 0) {
>> +		dev_err(pchip->dev, "fail : i2c access to register.\n");
>> +		return ret;
>> +	}
>> +	bl->props.brightness = (rval_h << 8) | rval_l;
>> +	return bl->props.brightness;
>> +}
>> +
>> +static int lp8860_update_status_bled0(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_update_status(bl, LP8860_LED0);
>> +}
>> +
>> +static int lp8860_get_brightness_bled0(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_get_brightness(bl, LP8860_LED0);
>> +}
>> +
>> +static int lp8860_update_status_bled1(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_update_status(bl, LP8860_LED1);
>> +}
>> +
>> +static int lp8860_get_brightness_bled1(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_get_brightness(bl, LP8860_LED1);
>> +}
>> +
>> +static int lp8860_update_status_bled2(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_update_status(bl, LP8860_LED2);
>> +}
>> +
>> +static int lp8860_get_brightness_bled2(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_get_brightness(bl, LP8860_LED2);
>> +}
>> +
>> +static int lp8860_update_status_bled3(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_update_status(bl, LP8860_LED3);
>> +}
>> +
>> +static int lp8860_get_brightness_bled3(struct backlight_device *bl)
>> +{
>> +	return lp8860_bled_get_brightness(bl, LP8860_LED3);
>> +}
>> +
>> +#define lp8860_bled_ops(_id)\
>> +{\
>> +	.options = BL_CORE_SUSPENDRESUME,\
>> +	.update_status = lp8860_update_status_bled##_id,\
>> +	.get_brightness = lp8860_get_brightness_bled##_id,\
>> +}
>> +
>> +static const struct backlight_ops lp8860_bled_ops[LP8860_LED_MAX] = {
>> +	[LP8860_LED0] = lp8860_bled_ops(0),
>> +	[LP8860_LED1] = lp8860_bled_ops(1),
>> +	[LP8860_LED2] = lp8860_bled_ops(2),
>> +	[LP8860_LED3] = lp8860_bled_ops(3),
>> +};
>> +
>> +/* current control */
>> +static int lp8860_set_current(struct device *dev,
>> +			      const char *buf, enum lp8860_leds nsr)
>> +{
>> +	struct lp8860_chip *pchip = dev_get_drvdata(dev);
>> +	unsigned int ival;
>> +	ssize_t ret;
>> +
>> +	ret = kstrtouint(buf, 10, &ival);
>> +	if (ret)
>> +		return ret;
>> +
>> +	switch (nsr) {
>> +	case LP8860_LED0:
>> +		ival = min_t(unsigned int, ival, LP8860_LED0_BR_MAX);
>> +		ret = regmap_write(pchip->regmap, REG_CL0_I_H, ival >> 8);
>> +		ret |= regmap_write(pchip->regmap, REG_CL0_I_L, ival & 0xff);
>> +		break;
>> +	case LP8860_LED1:
>> +		ival = min_t(unsigned int, ival, LP8860_LED1_BR_MAX);
>> +		ret = regmap_write(pchip->regmap, REG_CL1_I, ival & 0xff);
>> +		break;
>> +	case LP8860_LED2:
>> +		ival = min_t(unsigned int, ival, LP8860_LED2_BR_MAX);
>> +		ret = regmap_write(pchip->regmap, REG_CL2_I, ival & 0xff);
>> +		break;
>> +	case LP8860_LED3:
>> +		ival = min_t(unsigned int, ival, LP8860_LED3_BR_MAX);
>> +		ret = regmap_write(pchip->regmap, REG_CL3_I, ival & 0xff);
>> +		break;
>> +	default:
>> +		BUG();
>> +	}
>> +	if (ret < 0)
>> +		dev_err(pchip->dev, "fail : i2c access error.\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static ssize_t lp8860_current_store_bled0(struct device *dev,
>> +					  struct device_attribute *devAttr,
>> +					  const char *buf, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = lp8860_set_current(dev, buf, LP8860_LED0);
>> +	if (ret < 0)
>> +		return ret;
>> +	return size;
>> +}
>> +
>> +static ssize_t lp8860_current_store_bled1(struct device *dev,
>> +					  struct device_attribute *devAttr,
>> +					  const char *buf, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = lp8860_set_current(dev, buf, LP8860_LED1);
>> +	if (ret < 0)
>> +		return ret;
>> +	return size;
>> +}
>> +
>> +static ssize_t lp8860_current_store_bled2(struct device *dev,
>> +					  struct device_attribute *devAttr,
>> +					  const char *buf, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = lp8860_set_current(dev, buf, LP8860_LED2);
>> +	if (ret < 0)
>> +		return ret;
>> +	return size;
>> +}
>> +
>> +static ssize_t lp8860_current_store_bled3(struct device *dev,
>> +					  struct device_attribute *devAttr,
>> +					  const char *buf, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = lp8860_set_current(dev, buf, LP8860_LED3);
>> +	if (ret < 0)
>> +		return ret;
>> +	return size;
>> +}
>> +
>> +#define lp8860_attr(_name, _show, _store)\
>> +{\
>> +	.attr = {\
>> +		.name = _name,\
>> +		.mode = S_IWUSR,\
>> +	},\
>> +	.show = _show,\
>> +	.store = _store,\
>> +}
>> +
>> +static struct device_attribute lp8860_dev_attr[LP8860_LED_MAX] = {
>> +	[LP8860_LED0] = lp8860_attr("current", NULL,
>> +				    lp8860_current_store_bled0),
>> +	[LP8860_LED1] = lp8860_attr("current", NULL,
>> +				    lp8860_current_store_bled1),
>> +	[LP8860_LED2] = lp8860_attr("current", NULL,
>> +				    lp8860_current_store_bled2),
>> +	[LP8860_LED3] = lp8860_attr("current", NULL,
>> +				    lp8860_current_store_bled3),
>> +};
>> +
>> +/*
>> + * eeprom write and readback to check.
>> + * eeprom register range is from 60h to 78h
>> + * buffer value to write data [reg] [data]
>> + * e.g) to change the register 0x60 value to 0xff
>> + *      buffer value should be 60 ff
>> + */
>> +static ssize_t lp8860_eeprom_store(struct device *dev,
>> +				   struct device_attribute *devAttr,
>> +				   const char *buf, size_t size)
>> +{
>> +	struct lp8860_chip *pchip = dev_get_drvdata(dev);
>> +	unsigned int reg, data, rval;
>> +	char *tok;
>> +	int ret;
>> +
>> +	/* register no. */
>> +	tok = strsep((char **)&buf, " ,\n");
>> +	if (tok = NULL)
>> +		goto err_input;
>> +	ret = kstrtouint(tok, 16, &reg);
>> +	if (ret)
>> +		goto err_input;
>> +
>> +	/* register value */
>> +	tok = strsep((char **)&buf, " ,\n");
>> +	if (tok = NULL)
>> +		goto err_input;
>> +	ret = kstrtouint(tok, 16, &data);
>> +	if (ret)
>> +		goto err_input;
>> +	/*
>> +	 * EEPROM Programming sequence
>> +	 *    (program data permanently from registers to NVM)
>> +	 * 1. Unlock EEPROM by writing
>> +	 *    the unlock codes to register 1Ah(08, BA, EF)
>> +	 * 2. Write data to EEPROM registers (address 60h...78h)
>> +	 * 3. Write EE_PROG to 1 in address 19h. (02h to address 19h)
>> +	 * 4. Wait 100ms
> If possible, please add the reason why 100ms is necessary.
> 100ms is very huge delay.

These sequences are based on the datasheet.

>
>> +	 * 5. Write EE_PROG to 0 in address 19h. (00h to address 19h)
>> +	 */
>> +	if (reg < REG_EEPROM_START || reg > REG_EEPROM_END || data > 0xff)
>> +		goto err_input;
>> +	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
>> +	ret |= regmap_write(pchip->regmap, reg, data);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x02);
>> +	msleep(100);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
>> +	if (ret < 0)
>> +		goto err_i2c;
>> +
>> +	/* read back */
>> +	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x01);
>> +	msleep(100);
>> +	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
>> +	ret |= regmap_read(pchip->regmap, reg, &rval);
>> +	if (ret < 0)
>> +		goto err_i2c;
>> +	if (rval != data)
>> +		dev_err(pchip->dev, "fail : eeprom did not change.\n");
>> +
>> +	return size;
>> +
>> +err_i2c:
>> +	dev_err(pchip->dev, "fail : i2c access error.\n");
>> +	return ret;
>> +
>> +err_input:
>> +	dev_err(pchip->dev, "fail : input fail.\n");
>> +	return -EINVAL;
>> +}
>> +
>> +static DEVICE_ATTR(eeprom, S_IWUSR, NULL, lp8860_eeprom_store);
>> +
>> +/* backlight register and remove */
>> +static char *lp8860_bled_name[LP8860_LED_MAX] = {
>> +	[LP8860_LED0] = "bled0",
>> +	[LP8860_LED1] = "bled1",
>> +	[LP8860_LED2] = "bled2",
>> +	[LP8860_LED3] = "bled3",
>> +};
>> +
>> +static int lp8860_backlight_remove(struct lp8860_chip *pchip)
>> +{
>> +	int icnt;
>> +
>> +	device_remove_file(&(pchip->bled[0]->dev), &dev_attr_eeprom);
>> +	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
>> +		if (pchip->bled[icnt]) {
>> +			backlight_device_unregister(pchip->bled[icnt]);
>> +			device_remove_file(&(pchip->bled[icnt]->dev),
>> +					   &lp8860_dev_attr[icnt]);
>> +		}
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int lp8860_backlight_registers(struct lp8860_chip *pchip)
>> +{
>> +	struct backlight_properties props;
>> +	struct lp8860_platform_data *pdata = pchip->pdata;
>> +	int icnt, ret;
>> +
>> +	props.type = BACKLIGHT_RAW;
>> +	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
>> +		props.max_brightness = pdata->max_brt[icnt];
>> +		pchip->bled[icnt] >> +		    backlight_device_register(lp8860_bled_name[icnt],
> devm_* functions will make the code simpler.
> Thus, please use devm_backlight_device_register(), instead of
> backlight_device_register().
>
>> +					      pchip->dev, pchip,
>> +					      &lp8860_bled_ops[icnt], &props);
>> +		if (IS_ERR(pchip->bled[icnt])) {
>> +			dev_err(pchip->dev, "fail : backlight register.\n");
>> +			ret = PTR_ERR(pchip->bled[icnt]);
>> +			goto err_out;
>> +		}
>> +
>> +		ret = device_create_file(&(pchip->bled[icnt]->dev),
>> +					 &lp8860_dev_attr[icnt]);
>> +		if (ret < 0) {
>> +			dev_err(pchip->dev, "fail : to add sysfs entries.\n");
>> +			goto err_out;
>> +		}
>> +	}
>> +	/* access eeprom */
>> +	ret = device_create_file(&(pchip->bled[LP8860_LED0]->dev),
>> +				 &dev_attr_eeprom);
>> +	if (ret < 0) {
>> +		dev_err(pchip->dev, "fail : to add sysfs entries.\n");
>> +		goto err_out;
>> +	}
>> +	return 0;
>> +
>> +err_out:
>> +	lp8860_backlight_remove(pchip);
>> +	return ret;
>> +}
>> +
>> +static const struct regmap_config lp8860_regmap = {
>> +	.reg_bits = 8,
>> +	.val_bits = 8,
>> +	.max_register = REG_MAX,
>> +};
>> +
>> +static int lp8860_probe(struct i2c_client *client,
>> +			const struct i2c_device_id *id)
>> +{
>> +	struct lp8860_chip *pchip;
>> +	struct lp8860_platform_data *pdata = dev_get_platdata(&client->dev);
>> +	int ret, icnt;
>> +
>> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>> +		dev_err(&client->dev, "fail : i2c functionality check.\n");
>> +		return -EOPNOTSUPP;
>> +	}
>> +
>> +	pchip = devm_kzalloc(&client->dev,
>> +			     sizeof(struct lp8860_chip), GFP_KERNEL);
>> +	if (!pchip)
>> +		return -ENOMEM;
>> +	pchip->dev = &client->dev;
>> +
>> +	pchip->regmap = devm_regmap_init_i2c(client, &lp8860_regmap);
>> +	if (IS_ERR(pchip->regmap)) {
>> +		ret = PTR_ERR(pchip->regmap);
>> +		dev_err(pchip->dev, "fail : allocate i2c register map.\n");
>> +		return ret;
>> +	}
>> +
>> +	if (pdata = NULL) {
>> +		pdata = devm_kzalloc(pchip->dev,
>> +				     sizeof(struct lp8860_platform_data),
>> +				     GFP_KERNEL);
>> +		if (pdata = NULL)
>> +			return -ENOMEM;
>> +		pdata->max_brt[LP8860_LED0] = 65535;
>> +		for (icnt = LP8860_LED1; icnt < LP8860_LED_MAX; icnt++)
>> +			pdata->max_brt[icnt] = 8191;
>> +		pchip->pdata = pdata;
>> +	} else {
>> +		pchip->pdata = pdata;
>> +	}
>> +	i2c_set_clientdata(client, pchip);
>> +	ret = lp8860_backlight_registers(pchip);
>> +	return ret;
>> +}
>> +
>> +static int lp8860_remove(struct i2c_client *client)
>> +{
>> +	return lp8860_backlight_remove(i2c_get_clientdata(client));
>> +}
>> +
>> +static const struct i2c_device_id lp8860_id[] = {
>> +	{LP8860_NAME, 0},
>> +	{}
>> +};
>> +
>> +MODULE_DEVICE_TABLE(i2c, lp8860_id);
>> +static struct i2c_driver lp8860_i2c_driver = {
>> +	.driver = {
>> +		   .name = LP8860_NAME,
>> +		   },
> Fix the indent style as below.
>
>   +	   },
>
>> +	.probe = lp8860_probe,
>> +	.remove = lp8860_remove,
>> +	.id_table = lp8860_id,
>> +};
>> +
>> +module_i2c_driver(lp8860_i2c_driver);
>> +
>> +MODULE_DESCRIPTION("Texas Instruments LP8860 Backlight Driver");
>> +MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
>> +MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/platform_data/lp8860_bl.h b/include/linux/platform_data/lp8860_bl.h
>> new file mode 100644
>> index 0000000..61bd0f5
>> --- /dev/null
>> +++ b/include/linux/platform_data/lp8860_bl.h
>> @@ -0,0 +1,54 @@
>> +/*
>> + * Simple driver for Texas Instruments LM3642 LED Flash driver chip
>> + * Copyright (C) 2014 Texas Instruments
>> + *
>> + * 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 __LINUX_LP8860_H
>> +#define __LINUX_LP8860_H
> Prefix 'LINUX' looks redundant.
> Please replace '__LINUX_LP8860_H' with '__LP8860_H'.
>
> If the datasheet of 'lp8860' is not closed, please let us
> know where the datasheet is. It would be helpful for reviewing
> your patch.

Officially the datasheet will be opened next month but as of now I can't open it.

> Best regards,
> Jingoo Han
>
>> +
>> +#define LP8860_NAME "lp8860"
>> +#define LP8860_ADDR 0x2d
>> +
>> +#define LP8860_LED0_BR_MAX 65535
>> +#define LP8860_LED1_BR_MAX 8191
>> +#define LP8860_LED2_BR_MAX 8191
>> +#define LP8860_LED3_BR_MAX 8191
>> +
>> +#define LP8860_LED0_I_MAX 4095
>> +#define LP8860_LED1_I_MAX 255
>> +#define LP8860_LED2_I_MAX 255
>> +#define LP8860_LED3_I_MAX 255
>> +
>> +enum lp8860_leds {
>> +	LP8860_LED0 = 0,
>> +	LP8860_LED1,
>> +	LP8860_LED2,
>> +	LP8860_LED3,
>> +	LP8860_LED_MAX
>> +};
>> +
>> +enum lp8860_ctrl_mode {
>> +	LP8860_CTRL_I2C = 0,
>> +	LP8860_CTRL_I2C_PWM,
>> +};
>> +
>> +/* struct lp8860 platform data
>> + * @mode : control mode
>> + * @max_brt : maximum brightness.
>> + *		LED0 0 ~ 65535
>> + *		LED1 0 ~ 8191
>> + *		LED2 0 ~ 8191
>> + *		LED3 0 ~ 8191
>> + */
>> +struct lp8860_platform_data {
>> +
>> +	enum lp8860_ctrl_mode mode;
>> +	int max_brt[LP8860_LED_MAX];
>> +};
>> +
>> +#endif /* __LINUX_LP8860_H */
>> --
>> 1.7.9.5


^ permalink raw reply

* [PATCH v2] backlight: add new LP8860 backlight driver
From: Daniel Jeong @ 2014-03-13  5:03 UTC (permalink / raw)
  To: Jingoo Han
  Cc: Daniel Jeong, linux-fbdev, linux-kernel,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Bryan Wu,
	Lee Jones

 This patch adds LP8860 backlight device driver.
LP8860 is a low EMI and High performance 4 channel LED Driver of TI.
This device driver provides the way to control brightness and current
of each channel and provides the way to change values in the eeprom.

Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
---
 drivers/video/backlight/Kconfig         |    7 +
 drivers/video/backlight/Makefile        |    1 +
 drivers/video/backlight/lp8860_bl.c     |  525 +++++++++++++++++++++++++++++++
 include/linux/platform_data/lp8860_bl.h |   54 ++++
 4 files changed, 587 insertions(+)
 create mode 100644 drivers/video/backlight/lp8860_bl.c
 create mode 100644 include/linux/platform_data/lp8860_bl.h

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 5a3eb2e..908048f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -397,6 +397,13 @@ config BACKLIGHT_LP8788
 	help
 	  This supports TI LP8788 backlight driver.
 
+config BACKLIGHT_LP8860
+	tristate "Backlight Driver for LP8860"
+	depends on BACKLIGHT_CLASS_DEVICE && I2C
+	select REGMAP_I2C
+	help
+	  This supports TI LP8860 Backlight Driver
+
 config BACKLIGHT_OT200
 	tristate "Backlight driver for ot200 visualisation device"
 	depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index bb82002..cbc5ac3 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_BACKLIGHT_LM3639)		+= lm3639_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
 obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
+obj-$(CONFIG_BACKLIGHT_LP8860)		+= lp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
diff --git a/drivers/video/backlight/lp8860_bl.c b/drivers/video/backlight/lp8860_bl.c
new file mode 100644
index 0000000..d2be950
--- /dev/null
+++ b/drivers/video/backlight/lp8860_bl.c
@@ -0,0 +1,525 @@
+/*
+* Simple driver for Texas Instruments lp8860 Backlight driver chip
+*
+* Copyright (C) 2014 Texas Instruments
+* Author: Daniel Jeong  <gshark.jeong@gmail.com>
+*		  Ldd Mlp <ldd-mlp@list.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.
+*
+*/
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/platform_data/lp8860_bl.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#define REG_CL0_BRT_H	0x00
+#define REG_CL0_BRT_L	0x01
+#define REG_CL0_I_H		0x02
+#define REG_CL0_I_L		0x03
+
+#define REG_CL1_BRT_H	0x04
+#define REG_CL1_BRT_L	0x05
+#define REG_CL1_I		0x06
+
+#define REG_CL2_BRT_H	0x07
+#define REG_CL2_BRT_L	0x08
+#define REG_CL2_I		0x09
+
+#define REG_CL3_BRT_H	0x0a
+#define REG_CL3_BRT_L	0x0b
+#define REG_CL3_I		0x0c
+
+#define REG_CONF	0x0d
+#define REG_STATUS	0x0e
+#define REG_ID		0x12
+
+#define REG_ROM_CTRL	0x19
+#define REG_ROM_UNLOCK	0x1a
+#define REG_ROM_START	0x60
+#define REG_ROM_END		0x78
+
+#define REG_EEPROM_START	0x60
+#define REG_EEPROM_END		0x78
+#define REG_MAX	0xFF
+
+struct lp8860_chip {
+	struct device *dev;
+	struct lp8860_platform_data *pdata;
+	struct backlight_device *bled[LP8860_LED_MAX];
+	struct regmap *regmap;
+};
+
+/* brightness control */
+static int lp8860_bled_update_status(struct backlight_device *bl,
+				     enum lp8860_leds nsr)
+{
+	int ret = -EINVAL;
+	struct lp8860_chip *pchip = bl_get_data(bl);
+
+	if (pchip->pdata->mode)
+		return 0;
+
+	if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+		bl->props.brightness = 0;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL0_BRT_H, bl->props.brightness >> 8);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL0_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED1:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL1_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL1_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED2:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL2_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL2_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED3:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL3_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL3_BRT_L, bl->props.brightness & 0xff);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0)
+		dev_err(pchip->dev, "fail : i2c access to register.\n");
+	else
+		ret = bl->props.brightness;
+
+	return ret;
+}
+
+static int lp8860_bled_get_brightness(struct backlight_device *bl,
+				      enum lp8860_leds nsr)
+{
+	struct lp8860_chip *pchip = bl_get_data(bl);
+	unsigned int rval_h, rval_l;
+	int ret = -EINVAL;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ret = regmap_read(pchip->regmap, REG_CL0_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL0_BRT_L, &rval_l);
+		break;
+	case LP8860_LED1:
+		ret = regmap_read(pchip->regmap, REG_CL1_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL1_BRT_L, &rval_l);
+		break;
+	case LP8860_LED2:
+		ret = regmap_read(pchip->regmap, REG_CL2_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL2_BRT_L, &rval_l);
+		break;
+	case LP8860_LED3:
+		ret = regmap_read(pchip->regmap, REG_CL3_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL3_BRT_L, &rval_l);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0) {
+		dev_err(pchip->dev, "fail : i2c access to register.\n");
+		return ret;
+	}
+	bl->props.brightness = (rval_h << 8) | rval_l;
+	return bl->props.brightness;
+}
+
+static int lp8860_update_status_bled0(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED0);
+}
+
+static int lp8860_get_brightness_bled0(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED0);
+}
+
+static int lp8860_update_status_bled1(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED1);
+}
+
+static int lp8860_get_brightness_bled1(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED1);
+}
+
+static int lp8860_update_status_bled2(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED2);
+}
+
+static int lp8860_get_brightness_bled2(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED2);
+}
+
+static int lp8860_update_status_bled3(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED3);
+}
+
+static int lp8860_get_brightness_bled3(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED3);
+}
+
+#define lp8860_bled_ops(_id)\
+{\
+	.options = BL_CORE_SUSPENDRESUME,\
+	.update_status = lp8860_update_status_bled##_id,\
+	.get_brightness = lp8860_get_brightness_bled##_id,\
+}
+
+static const struct backlight_ops lp8860_bled_ops[LP8860_LED_MAX] = {
+	[LP8860_LED0] = lp8860_bled_ops(0),
+	[LP8860_LED1] = lp8860_bled_ops(1),
+	[LP8860_LED2] = lp8860_bled_ops(2),
+	[LP8860_LED3] = lp8860_bled_ops(3),
+};
+
+/* current control */
+static int lp8860_set_current(struct device *dev,
+			      const char *buf, enum lp8860_leds nsr)
+{
+	struct lp8860_chip *pchip = dev_get_drvdata(dev);
+	unsigned int ival;
+	ssize_t ret;
+
+	ret = kstrtouint(buf, 10, &ival);
+	if (ret)
+		return ret;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ival = min_t(unsigned int, ival, LP8860_LED0_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL0_I_H, ival >> 8);
+		ret |= regmap_write(pchip->regmap, REG_CL0_I_L, ival & 0xff);
+		break;
+	case LP8860_LED1:
+		ival = min_t(unsigned int, ival, LP8860_LED1_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL1_I, ival & 0xff);
+		break;
+	case LP8860_LED2:
+		ival = min_t(unsigned int, ival, LP8860_LED2_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL2_I, ival & 0xff);
+		break;
+	case LP8860_LED3:
+		ival = min_t(unsigned int, ival, LP8860_LED3_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL3_I, ival & 0xff);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0)
+		dev_err(pchip->dev, "fail : i2c access error.\n");
+
+	return ret;
+}
+
+static ssize_t lp8860_current_store_bled0(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED0);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled1(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED1);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled2(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED2);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled3(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED3);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+#define lp8860_attr(_name, _show, _store)\
+{\
+	.attr = {\
+		.name = _name,\
+		.mode = S_IWUSR,\
+	},\
+	.show = _show,\
+	.store = _store,\
+}
+
+static struct device_attribute lp8860_dev_attr[LP8860_LED_MAX] = {
+	[LP8860_LED0] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled0),
+	[LP8860_LED1] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled1),
+	[LP8860_LED2] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled2),
+	[LP8860_LED3] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled3),
+};
+
+/*
+ * eeprom write and readback to check.
+ * eeprom register range is from 60h to 78h
+ * buffer value to write data [reg] [data]
+ * e.g) to change the register 0x60 value to 0xff
+ *      buffer value should be 60 ff
+ */
+static ssize_t lp8860_eeprom_store(struct device *dev,
+				   struct device_attribute *devAttr,
+				   const char *buf, size_t size)
+{
+	struct lp8860_chip *pchip = dev_get_drvdata(dev);
+	unsigned int reg, data, rval;
+	char *tok;
+	int ret;
+
+	/* register no. */
+	tok = strsep((char **)&buf, " ,\n");
+	if (tok = NULL)
+		goto err_input;
+	ret = kstrtouint(tok, 16, &reg);
+	if (ret)
+		goto err_input;
+
+	/* register value */
+	tok = strsep((char **)&buf, " ,\n");
+	if (tok = NULL)
+		goto err_input;
+	ret = kstrtouint(tok, 16, &data);
+	if (ret)
+		goto err_input;
+	/*
+	 * EEPROM Programming sequence
+	 *    (program data permanently from registers to NVM)
+	 * 1. Unlock EEPROM by writing
+	 *    the unlock codes to register 1Ah(08, BA, EF)
+	 * 2. Write data to EEPROM registers (address 60h...78h)
+	 * 3. Write EE_PROG to 1 in address 19h. (02h to address 19h)
+	 * 4. Wait 100ms for chip interanl dealy to access the eeprom
+	 * 5. Write EE_PROG to 0 in address 19h. (00h to address 19h)
+	 */
+	if (reg < REG_EEPROM_START || reg > REG_EEPROM_END || data > 0xff)
+		goto err_input;
+	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
+	ret |= regmap_write(pchip->regmap, reg, data);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x02);
+	msleep(100);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* read back */
+	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x01);
+	msleep(100);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
+	ret |= regmap_read(pchip->regmap, reg, &rval);
+	if (ret < 0)
+		goto err_i2c;
+	if (rval != data)
+		dev_err(pchip->dev, "fail : eeprom did not change.\n");
+
+	return size;
+
+err_i2c:
+	dev_err(pchip->dev, "fail : i2c access error.\n");
+	return ret;
+
+err_input:
+	dev_err(pchip->dev, "fail : input fail.\n");
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(eeprom, S_IWUSR, NULL, lp8860_eeprom_store);
+
+/* backlight register and remove */
+static char *lp8860_bled_name[LP8860_LED_MAX] = {
+	[LP8860_LED0] = "bled0",
+	[LP8860_LED1] = "bled1",
+	[LP8860_LED2] = "bled2",
+	[LP8860_LED3] = "bled3",
+};
+
+static int lp8860_backlight_remove(struct lp8860_chip *pchip)
+{
+	int icnt;
+
+	device_remove_file(&(pchip->bled[0]->dev), &dev_attr_eeprom);
+	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
+		if (pchip->bled[icnt])
+			device_remove_file(&(pchip->bled[icnt]->dev),
+					   &lp8860_dev_attr[icnt]);
+	}
+	return 0;
+}
+
+static int lp8860_backlight_registers(struct lp8860_chip *pchip)
+{
+	struct backlight_properties props;
+	struct lp8860_platform_data *pdata = pchip->pdata;
+	int icnt, ret;
+
+	props.type = BACKLIGHT_RAW;
+	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
+		props.max_brightness = pdata->max_brt[icnt];
+		pchip->bled[icnt] +		    devm_backlight_device_register(pchip->dev,
+						   lp8860_bled_name[icnt],
+						   pchip->dev, pchip,
+						   &lp8860_bled_ops[icnt],
+						   &props);
+		if (IS_ERR(pchip->bled[icnt])) {
+			dev_err(pchip->dev, "fail : backlight register.\n");
+			ret = PTR_ERR(pchip->bled[icnt]);
+			goto err_out;
+		}
+		/* to control current */
+		ret = device_create_file(&(pchip->bled[icnt]->dev),
+					 &lp8860_dev_attr[icnt]);
+		if (ret < 0) {
+			dev_err(pchip->dev, "fail : to add sysfs entries.\n");
+			goto err_out;
+		}
+	}
+	/* to access eeprom */
+	ret = device_create_file(&(pchip->bled[LP8860_LED0]->dev),
+				 &dev_attr_eeprom);
+	if (ret < 0) {
+		dev_err(pchip->dev, "fail : to add sysfs entries.\n");
+		goto err_out;
+	}
+	return 0;
+
+err_out:
+	lp8860_backlight_remove(pchip);
+	return ret;
+}
+
+static const struct regmap_config lp8860_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG_MAX,
+};
+
+static int lp8860_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct lp8860_chip *pchip;
+	struct lp8860_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret, icnt;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "fail : i2c functionality check.\n");
+		return -EOPNOTSUPP;
+	}
+
+	pchip = devm_kzalloc(&client->dev,
+			     sizeof(struct lp8860_chip), GFP_KERNEL);
+	if (!pchip)
+		return -ENOMEM;
+	pchip->dev = &client->dev;
+
+	pchip->regmap = devm_regmap_init_i2c(client, &lp8860_regmap);
+	if (IS_ERR(pchip->regmap)) {
+		ret = PTR_ERR(pchip->regmap);
+		dev_err(pchip->dev, "fail : allocate i2c register map.\n");
+		return ret;
+	}
+
+	if (pdata = NULL) {
+		pdata = devm_kzalloc(pchip->dev,
+				     sizeof(struct lp8860_platform_data),
+				     GFP_KERNEL);
+		if (pdata = NULL)
+			return -ENOMEM;
+		pdata->max_brt[LP8860_LED0] = 65535;
+		for (icnt = LP8860_LED1; icnt < LP8860_LED_MAX; icnt++)
+			pdata->max_brt[icnt] = 8191;
+		pchip->pdata = pdata;
+	} else {
+		pchip->pdata = pdata;
+	}
+	i2c_set_clientdata(client, pchip);
+	ret = lp8860_backlight_registers(pchip);
+	return ret;
+}
+
+static int lp8860_remove(struct i2c_client *client)
+{
+	return lp8860_backlight_remove(i2c_get_clientdata(client));
+}
+
+static const struct i2c_device_id lp8860_id[] = {
+	{LP8860_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp8860_id);
+static struct i2c_driver lp8860_i2c_driver = {
+	.driver = {
+		.name = LP8860_NAME,
+	},
+	.probe = lp8860_probe,
+	.remove = lp8860_remove,
+	.id_table = lp8860_id,
+};
+
+module_i2c_driver(lp8860_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8860 Backlight Driver");
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/lp8860_bl.h b/include/linux/platform_data/lp8860_bl.h
new file mode 100644
index 0000000..9edd7cf
--- /dev/null
+++ b/include/linux/platform_data/lp8860_bl.h
@@ -0,0 +1,54 @@
+/*
+ * Simple driver for Texas Instruments LP8860 Backlight driver chip
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * 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 __LP8860_H
+#define __LP8860_H
+
+#define LP8860_NAME "lp8860"
+#define LP8860_ADDR 0x2d
+
+#define LP8860_LED0_BR_MAX 65535
+#define LP8860_LED1_BR_MAX 8191
+#define LP8860_LED2_BR_MAX 8191
+#define LP8860_LED3_BR_MAX 8191
+
+#define LP8860_LED0_I_MAX 4095
+#define LP8860_LED1_I_MAX 255
+#define LP8860_LED2_I_MAX 255
+#define LP8860_LED3_I_MAX 255
+
+enum lp8860_leds {
+	LP8860_LED0 = 0,
+	LP8860_LED1,
+	LP8860_LED2,
+	LP8860_LED3,
+	LP8860_LED_MAX
+};
+
+enum lp8860_ctrl_mode {
+	LP8860_CTRL_I2C = 0,
+	LP8860_CTRL_I2C_PWM,
+};
+
+/* struct lp8860 platform data
+ * @mode : control mode
+ * @max_brt : maximum brightness.
+ *		LED0 0 ~ 65535
+ *		LED1 0 ~ 8191
+ *		LED2 0 ~ 8191
+ *		LED3 0 ~ 8191
+ */
+struct lp8860_platform_data {
+
+	enum lp8860_ctrl_mode mode;
+	int max_brt[LP8860_LED_MAX];
+};
+
+#endif /* __LP8860_H */
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] lcd: Provide dummy functions if CONFIG_LCD_CLASS_DEVICE is not set
From: Alexander Shiyan @ 2014-03-13  7:31 UTC (permalink / raw)
  To: linux-fbdev

Provide dummy functions for LCD register()/unregister() if
CONFIG_LCD_CLASS_DEVICE is not set.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
 include/linux/lcd.h | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/include/linux/lcd.h b/include/linux/lcd.h
index 504f624..f1c94fd 100644
--- a/include/linux/lcd.h
+++ b/include/linux/lcd.h
@@ -110,14 +110,37 @@ static inline void lcd_set_power(struct lcd_device *ld, int power)
 	mutex_unlock(&ld->update_lock);
 }
 
-extern struct lcd_device *lcd_device_register(const char *name,
-	struct device *parent, void *devdata, struct lcd_ops *ops);
-extern struct lcd_device *devm_lcd_device_register(struct device *dev,
-	const char *name, struct device *parent,
+#if defined(CONFIG_LCD_CLASS_DEVICE) || defined(CONFIG_LCD_CLASS_DEVICE_MODULE)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
 	void *devdata, struct lcd_ops *ops);
-extern void lcd_device_unregister(struct lcd_device *ld);
-extern void devm_lcd_device_unregister(struct device *dev,
-	struct lcd_device *ld);
+struct lcd_device *devm_lcd_device_register(struct device *dev,
+	const char *name, struct device *parent, void *devdata,
+	struct lcd_ops *ops);
+void lcd_device_unregister(struct lcd_device *ld);
+void devm_lcd_device_unregister(struct device *dev, struct lcd_device *ld);
+#else
+static inline struct lcd_device *lcd_device_register(const char *name,
+	struct device *parent, void *devdata, struct lcd_ops *ops)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline struct lcd_device *devm_lcd_device_register(struct device *dev,
+	const char *name, struct device *parent, void *devdata,
+	struct lcd_ops *ops)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void lcd_device_unregister(struct lcd_device *ld)
+{
+}
+
+static inline void devm_lcd_device_unregister(struct device *dev,
+	struct lcd_device *ld)
+{
+}
+#endif
 
 #define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
 
-- 
1.8.3.2


^ permalink raw reply related

* Re: [PATCH] lcd: Provide dummy functions if CONFIG_LCD_CLASS_DEVICE is not set
From: Tomi Valkeinen @ 2014-03-13  8:23 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1394695879-22845-1-git-send-email-shc_work@mail.ru>

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]

On 13/03/14 09:31, Alexander Shiyan wrote:
> Provide dummy functions for LCD register()/unregister() if
> CONFIG_LCD_CLASS_DEVICE is not set.

Hmm, why do you want to do that? If a driver needs the LCD class, it
should depend on or select it.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCH] lcd: Provide dummy functions if C =?UTF-8?B?T05GSUdfTENEX0NMQ
From: Alexander Shiyan @ 2014-03-13  8:48 UTC (permalink / raw)
  To: linux-fbdev

0KfQtdGC0LLQtdGA0LMsIDEzINC80LDRgNGC0LAgMjAxNCwgMTA6MjMgKzAyOjAwINC+0YIgVG9t
aSBWYWxrZWluZW4gPHRvbWkudmFsa2VpbmVuQHRpLmNvbT46Cj4gT24gMTMvMDMvMTQgMDk6MzEs
IEFsZXhhbmRlciBTaGl5YW4gd3JvdGU6Cj4gPiBQcm92aWRlIGR1bW15IGZ1bmN0aW9ucyBmb3Ig
TENEIHJlZ2lzdGVyKCkvdW5yZWdpc3RlcigpIGlmCj4gPiBDT05GSUdfTENEX0NMQVNTX0RFVklD
RSBpcyBub3Qgc2V0Lgo+IAo+IEhtbSwgd2h5IGRvIHlvdSB3YW50IHRvIGRvIHRoYXQ/IElmIGEg
ZHJpdmVyIG5lZWRzIHRoZSBMQ0QgY2xhc3MsIGl0Cj4gc2hvdWxkIGRlcGVuZCBvbiBvciBzZWxl
Y3QgaXQuCgpJIGluc3BlY3QgbXkgcmVjZW50IGNoYW5nZXMgZm9yIHRoZSBpbXhmYiBkcml2ZXIu
CkkgdXNlIHRoZSBMQ0QgY2xhc3MgZm9yIHBvd2VyIG1hbmFnZW1lbnQgYW5kIGNvbnRyYXN0LCBu
ZXZlcnRoZWxlc3MsCmlmIGl0IGxhY2sgaW4gdGhlIGtlcm5lbCB0aGlzIGxlYWRzIHRvIGFuIGVy
cm9yLgpZZXMsIHdlIGNhbiBjaG9vc2UgdGhlIExDRF9DTEFTU19ERVZJQ0Ugc3ltYm9sIGZvciB0
aGUgaW14ZmIgZHJpdmVyLApidXQgYXQgdGhlIHNhbWUgdGltZSB3ZSBtdXN0IGNob29zZSBCQUNL
TElHSFRfTENEX1NVUFBPUlQuCkkgZG8gbm90IHRoaW5rIGl0J3MgYSBnb29kIHdheS4KSW4gYW55
IGNhc2UsIEkgd291bGQgbGlrZSB0byByZXZpc2UgdGhlIHBhdGNoIHRvIHVzZSBOVUxMIGFzIGEg
cmVzdWx0CmlmIHRoZXJlIGlzIG5vIHN1cHBvcnQgTENEX0NMQVNTX0RFVklDRSBpbiB0aGUga2Vy
bmVsLgpBZGRpdGlvbmFsbHksIEkgaGF2ZSBhIHBsYW4gdG8gY29udmVydCAibWVudWNvbmZpZyIg
ZW50cnkgZm9yCkJBQ0tMSUdIVF9MQ0RfU1VQUE9SVCB0byB0aGUgIm1lbnUiLgpPSz8KCi0tLQo

^ permalink raw reply

* Re: [PATCH] lcd: Provide dummy functions if CONFIG_LCD_CLASS_DEVICE is not set
From: Tomi Valkeinen @ 2014-03-13  9:04 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1394695879-22845-1-git-send-email-shc_work@mail.ru>

[-- Attachment #1: Type: text/plain, Size: 1975 bytes --]

On 13/03/14 10:48, Alexander Shiyan wrote:
> Четверг, 13 марта 2014, 10:23 +02:00 от Tomi Valkeinen <tomi.valkeinen@ti.com>:
>> On 13/03/14 09:31, Alexander Shiyan wrote:
>>> Provide dummy functions for LCD register()/unregister() if
>>> CONFIG_LCD_CLASS_DEVICE is not set.
>>
>> Hmm, why do you want to do that? If a driver needs the LCD class, it
>> should depend on or select it.
> 
> I inspect my recent changes for the imxfb driver.
> I use the LCD class for power management and contrast, nevertheless,
> if it lack in the kernel this leads to an error.

So is the CONFIG_LCD_CLASS_DEVICE optional for imxfb? It works fine with
or without the LCD class support? Is there some reason to run it without
LCD class support?

> Yes, we can choose the LCD_CLASS_DEVICE symbol for the imxfb driver,
> but at the same time we must choose BACKLIGHT_LCD_SUPPORT.
> I do not think it's a good way.

Why not?

> In any case, I would like to revise the patch to use NULL as a result
> if there is no support LCD_CLASS_DEVICE in the kernel.

Why do you want to run imxfb without LCD_CLASS_DEVICE? Isn't it simpler
to just depend on it?

> Additionally, I have a plan to convert "menuconfig" entry for
> BACKLIGHT_LCD_SUPPORT to the "menu".

Hmm. That does make sense, as I don't see BACKLIGHT_LCD_SUPPORT
affecting anything, except enabling the BL & LCD Kconfig menu.

However, many of the items in BL & LCD menu have, for some reason,
"default y" or "default m". So if you make BACKLIGHT_LCD_SUPPORT a menu,
it means all those subitems are always enabled. So there definitely will
be a side effect to that change.

I guess there's legacy reasons why many of the items are enabled by
default. It would make sense to me to have BACKLIGHT_LCD_SUPPORT as a
menu, as you suggest, and having all the subitems disabled by default.
But again, that would change the current behavior, which may or may not
cause issues.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

^ permalink raw reply

* Re: [PATCH] lcd: Provide dummy functions if C =?UTF-8?B?T05GSUdfTENEX0NMQ
From: Alexander Shiyan @ 2014-03-13  9:26 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1394700536.448009775@f174.i.mail.ru>

0KfQtdGC0LLQtdGA0LMsIDEzINC80LDRgNGC0LAgMjAxNCwgMTE6MDQgKzAyOjAwINC+0YIgVG9t
aSBWYWxrZWluZW4gPHRvbWkudmFsa2VpbmVuQHRpLmNvbT46Cj4gT24gMTMvMDMvMTQgMTA6NDgs
IEFsZXhhbmRlciBTaGl5YW4gd3JvdGU6Cj4gPiDQp9C10YLQstC10YDQsywgMTMg0LzQsNGA0YLQ
sCAyMDE0LCAxMDoyMyArMDI6MDAg0L7RgiBUb21pIFZhbGtlaW5lbiA8dG9taS52YWxrZWluZW5A
dGkuY29tPjoKPiA+PiBPbiAxMy8wMy8xNCAwOTozMSwgQWxleGFuZGVyIFNoaXlhbiB3cm90ZToK
PiA+Pj4gUHJvdmlkZSBkdW1teSBmdW5jdGlvbnMgZm9yIExDRCByZWdpc3RlcigpL3VucmVnaXN0
ZXIoKSBpZgo+ID4+PiBDT05GSUdfTENEX0NMQVNTX0RFVklDRSBpcyBub3Qgc2V0Lgo+ID4+Cj4g
Pj4gSG1tLCB3aHkgZG8geW91IHdhbnQgdG8gZG8gdGhhdD8gSWYgYSBkcml2ZXIgbmVlZHMgdGhl
IExDRCBjbGFzcywgaXQKPiA+PiBzaG91bGQgZGVwZW5kIG9uIG9yIHNlbGVjdCBpdC4KPiA+IAo+
ID4gSSBpbnNwZWN0IG15IHJlY2VudCBjaGFuZ2VzIGZvciB0aGUgaW14ZmIgZHJpdmVyLgo+ID4g
SSB1c2UgdGhlIExDRCBjbGFzcyBmb3IgcG93ZXIgbWFuYWdlbWVudCBhbmQgY29udHJhc3QsIG5l
dmVydGhlbGVzcywKPiA+IGlmIGl0IGxhY2sgaW4gdGhlIGtlcm5lbCB0aGlzIGxlYWRzIHRvIGFu
IGVycm9yLgo+IAo+IFNvIGlzIHRoZSBDT05GSUdfTENEX0NMQVNTX0RFVklDRSBvcHRpb25hbCBm
b3IgaW14ZmI/IEl0IHdvcmtzIGZpbmUgd2l0aAo+IG9yIHdpdGhvdXQgdGhlIExDRCBjbGFzcyBz
dXBwb3J0PyBJcyB0aGVyZSBzb21lIHJlYXNvbiB0byBydW4gaXQgd2l0aG91dAo+IExDRCBjbGFz
cyBzdXBwb3J0PwoKU29tZSB1c2VycyBvZiBpbXhmYiByZXF1aXJlIGNvbnRyYXN0IGNvbnRyb2wg
KGl0IGlzIG1hbmRhdG9yeSBmb3IgU0hBUlAgZGlzcGxheXMsCmZvciBleGFtcGxlKSwgc29tZSB1
c2VycyByZXF1aXJlIHBvd2VyIGNvbnRyb2wsIHNvbWUgcmVxdWlyZSBib3RoIGNvbnRyb2xzLApz
b21lIHJlcXVpcmUgbm90aGluZyBvZiBkZXNjcmliZWQgYWJvdmUuClNvLCB0aGlzIHNlZW1zIGFz
IGFuIG9wdGlvbmFsIGNvbnRyb2wsIHdoaWNoIChpbiB0aGVvcnkpIG1heSBiZSBpbmNsdWRlZCBp
biB0aGUKY29uZmlndXJhdGlvbiBvciBub3QsIHNhbWUgYXMgcmVndWxhdG9yIGNsYXNzLgoKPiA+
IFllcywgd2UgY2FuIGNob29zZSB0aGUgTENEX0NMQVNTX0RFVklDRSBzeW1ib2wgZm9yIHRoZSBp
bXhmYiBkcml2ZXIsCj4gPiBidXQgYXQgdGhlIHNhbWUgdGltZSB3ZSBtdXN0IGNob29zZSBCQUNL
TElHSFRfTENEX1NVUFBPUlQuCj4gPiBJIGRvIG5vdCB0aGluayBpdCdzIGEgZ29vZCB3YXkuCj4g
Cj4gV2h5IG5vdD8KPiAKPiA+IEluIGFueSBjYXNlLCBJIHdvdWxkIGxpa2UgdG8gcmV2aXNlIHRo
ZSBwYXRjaCB0byB1c2UgTlVMTCBhcyBhIHJlc3VsdAo+ID4gaWYgdGhlcmUgaXMgbm8gc3VwcG9y
dCBMQ0RfQ0xBU1NfREVWSUNFIGluIHRoZSBrZXJuZWwuCj4gCj4gV2h5IGRvIHlvdSB3YW50IHRv
IHJ1biBpbXhmYiB3aXRob3V0IExDRF9DTEFTU19ERVZJQ0U/IElzbid0IGl0IHNpbXBsZXIKPiB0
byBqdXN0IGRlcGVuZCBvbiBpdD8KCkp1c3QgYW4gZXhjZWVkIGRlcGVuZGVuY3kuCk1ha2luZyB0
aGlzIG9wdGlvbiBhcyBvcHRpb25hbCBhbGxvdyB1cyB0byBpbmNyZWFzZSBjb21waWxlIGNvdmVy
YWdlIGFuZAptYWtlcyBjb25maWd1cmF0aW9uIG1vcmUgZmxleGlibGUuCgo+IAo+ID4gQWRkaXRp
b25hbGx5LCBJIGhhdmUgYSBwbGFuIHRvIGNvbnZlcnQgIm1lbnVjb25maWciIGVudHJ5IGZvcgo+
ID4gQkFDS0xJR0hUX0xDRF9TVVBQT1JUIHRvIHRoZSAibWVudSIuCj4gCj4gSG1tLiBUaGF0IGRv
ZXMgbWFrZSBzZW5zZSwgYXMgSSBkb24ndCBzZWUgQkFDS0xJR0hUX0xDRF9TVVBQT1JUCj4gYWZm
ZWN0aW5nIGFueXRoaW5nLCBleGNlcHQgZW5hYmxpbmcgdGhlIEJMICYgTENEIEtjb25maWcgbWVu
dS4KPiAKPiBIb3dldmVyLCBtYW55IG9mIHRoZSBpdGVtcyBpbiBCTCAmIExDRCBtZW51IGhhdmUs
IGZvciBzb21lIHJlYXNvbiwKPiAiZGVmYXVsdCB5IiBvciAiZGVmYXVsdCBtIi4gU28gaWYgeW91
IG1ha2UgQkFDS0xJR0hUX0xDRF9TVVBQT1JUIGEgbWVudSwKPiBpdCBtZWFucyBhbGwgdGhvc2Ug
c3ViaXRlbXMgYXJlIGFsd2F5cyBlbmFibGVkLiBTbyB0aGVyZSBkZWZpbml0ZWx5IHdpbGwKPiBi
ZSBhIHNpZGUgZWZmZWN0IHRvIHRoYXQgY2hhbmdlLgo+IAo+IEkgZ3Vlc3MgdGhlcmUncyBsZWdh
Y3kgcmVhc29ucyB3aHkgbWFueSBvZiB0aGUgaXRlbXMgYXJlIGVuYWJsZWQgYnkKPiBkZWZhdWx0
LiBJdCB3b3VsZCBtYWtlIHNlbnNlIHRvIG1lIHRvIGhhdmUgQkFDS0xJR0hUX0xDRF9TVVBQT1JU
IGFzIGEKPiBtZW51LCBhcyB5b3Ugc3VnZ2VzdCwgYW5kIGhhdmluZyBhbGwgdGhlIHN1Yml0ZW1z
IGRpc2FibGVkIGJ5IGRlZmF1bHQuCj4gQnV0IGFnYWluLCB0aGF0IHdvdWxkIGNoYW5nZSB0aGUg
Y3VycmVudCBiZWhhdmlvciwgd2hpY2ggbWF5IG9yIG1heSBub3QKPiBjYXVzZSBpc3N1ZXMuCgpJ
IHRoaW5rIGl0IHNob3VsZCBub3QgY2F1c2UgYW55IGluc3RhYmlsaXR5IGFuZCBwb3NzaWJsZSBk
aXNjcmVwYW5jaWVzIHdpbGwKcmVzb2x2ZWQgZHVyaW5nIHRoZSBsaWZlIG9mIHRoZXNlIGNoYW5n
ZXMgaW4gdGhlIGxpbnV4LW5leHQuCgotLS0K

^ permalink raw reply

* Re: [PATCH v5 1/2] video: ARM CLCD: Add DT support
From: Linus Walleij @ 2014-03-13  9:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <53184C2E.3000807@ti.com>

On Thu, Mar 6, 2014 at 11:21 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> Hi Pawel,
>
> On 05/03/14 18:23, Pawel Moll wrote:
>> This patch adds basic DT bindings for the PL11x CLCD cells
>> and make their fbdev driver use them.
>
> Is this an old HW, and presumably there won't be new users for it?

AFAICT ARM really like to re-synthesize this piece of HW in every
new reference design they make. Plus a number of manufacturers
have used it in elder systems.

> If
> yes, this is probably fine. If not, you might want to look at the video
> ports and endpoints, which is used by at least three not-yet-merged series:
>
> [PATCHv3 00/41] OMAPDSS: DT support v3
> [PATCH v5 00/11] imx-drm dt bindings
> [RFC PATCH v2 00/21] Add DSI display support for Exynos based boards
>
> Using bindings like that would be more future proof, even if the current
> driver doesn't use them.

I take it that it shouldn't matter if the driver is for framebuffer or
DRM (as was implied by some answer here) the hardware
description should be the same no matter what, so the more
furture-proof the better.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v3] backlight: add new LP8860 backlight driver
From: Daniel Jeong @ 2014-03-13 10:28 UTC (permalink / raw)
  To: Jingoo Han
  Cc: Daniel Jeong, linux-fbdev, linux-kernel,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Bryan Wu,
	Lee Jones

 This patch adds LP8860 backlight device driver.
LP8860 is a low EMI and High performance 4 channel LED Driver of TI.
This device driver provides the way to control brightness and current
of each channel and provides the way to change values in the eeprom.

Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
---
To support dt structure, another patch file will be sent.
changes since v2
 - removed some magic number. 
 - fixed the possibility to refer null when backlight is removed.

---
 drivers/video/backlight/Kconfig         |    7 +
 drivers/video/backlight/Makefile        |    1 +
 drivers/video/backlight/lp8860_bl.c     |  526 +++++++++++++++++++++++++++++++
 include/linux/platform_data/lp8860_bl.h |   54 ++++
 4 files changed, 588 insertions(+)
 create mode 100644 drivers/video/backlight/lp8860_bl.c
 create mode 100644 include/linux/platform_data/lp8860_bl.h

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 5a3eb2e..908048f 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -397,6 +397,13 @@ config BACKLIGHT_LP8788
 	help
 	  This supports TI LP8788 backlight driver.
 
+config BACKLIGHT_LP8860
+	tristate "Backlight Driver for LP8860"
+	depends on BACKLIGHT_CLASS_DEVICE && I2C
+	select REGMAP_I2C
+	help
+	  This supports TI LP8860 Backlight Driver
+
 config BACKLIGHT_OT200
 	tristate "Backlight driver for ot200 visualisation device"
 	depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index bb82002..cbc5ac3 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_BACKLIGHT_LM3639)		+= lm3639_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
 obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
+obj-$(CONFIG_BACKLIGHT_LP8860)		+= lp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
diff --git a/drivers/video/backlight/lp8860_bl.c b/drivers/video/backlight/lp8860_bl.c
new file mode 100644
index 0000000..e17e94f
--- /dev/null
+++ b/drivers/video/backlight/lp8860_bl.c
@@ -0,0 +1,526 @@
+/*
+* Simple driver for Texas Instruments lp8860 Backlight driver chip
+*
+* Copyright (C) 2014 Texas Instruments
+* Author: Daniel Jeong  <gshark.jeong@gmail.com>
+*		  Ldd Mlp <ldd-mlp@list.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.
+*
+*/
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/platform_data/lp8860_bl.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#define REG_CL0_BRT_H	0x00
+#define REG_CL0_BRT_L	0x01
+#define REG_CL0_I_H		0x02
+#define REG_CL0_I_L		0x03
+
+#define REG_CL1_BRT_H	0x04
+#define REG_CL1_BRT_L	0x05
+#define REG_CL1_I		0x06
+
+#define REG_CL2_BRT_H	0x07
+#define REG_CL2_BRT_L	0x08
+#define REG_CL2_I		0x09
+
+#define REG_CL3_BRT_H	0x0a
+#define REG_CL3_BRT_L	0x0b
+#define REG_CL3_I		0x0c
+
+#define REG_CONF	0x0d
+#define REG_STATUS	0x0e
+#define REG_ID		0x12
+
+#define REG_ROM_CTRL	0x19
+#define REG_ROM_UNLOCK	0x1a
+#define REG_ROM_START	0x60
+#define REG_ROM_END		0x78
+
+#define REG_EEPROM_START	0x60
+#define REG_EEPROM_END		0x78
+#define REG_MAX	0xFF
+
+struct lp8860_chip {
+	struct device *dev;
+	struct lp8860_platform_data *pdata;
+	struct backlight_device *bled[LP8860_LED_MAX];
+	struct regmap *regmap;
+};
+
+/* brightness control */
+static int lp8860_bled_update_status(struct backlight_device *bl,
+				     enum lp8860_leds nsr)
+{
+	int ret = -EINVAL;
+	struct lp8860_chip *pchip = bl_get_data(bl);
+
+	if (pchip->pdata->mode)
+		return 0;
+
+	if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+		bl->props.brightness = 0;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL0_BRT_H, bl->props.brightness >> 8);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL0_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED1:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL1_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL1_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED2:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL2_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL2_BRT_L, bl->props.brightness & 0xff);
+		break;
+	case LP8860_LED3:
+		ret = regmap_write(pchip->regmap,
+				   REG_CL3_BRT_H,
+				   (bl->props.brightness >> 8) & 0x1f);
+		ret |= regmap_write(pchip->regmap,
+				    REG_CL3_BRT_L, bl->props.brightness & 0xff);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0)
+		dev_err(pchip->dev, "fail : i2c access to register.\n");
+	else
+		ret = bl->props.brightness;
+
+	return ret;
+}
+
+static int lp8860_bled_get_brightness(struct backlight_device *bl,
+				      enum lp8860_leds nsr)
+{
+	struct lp8860_chip *pchip = bl_get_data(bl);
+	unsigned int rval_h, rval_l;
+	int ret = -EINVAL;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ret = regmap_read(pchip->regmap, REG_CL0_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL0_BRT_L, &rval_l);
+		break;
+	case LP8860_LED1:
+		ret = regmap_read(pchip->regmap, REG_CL1_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL1_BRT_L, &rval_l);
+		break;
+	case LP8860_LED2:
+		ret = regmap_read(pchip->regmap, REG_CL2_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL2_BRT_L, &rval_l);
+		break;
+	case LP8860_LED3:
+		ret = regmap_read(pchip->regmap, REG_CL3_BRT_H, &rval_h);
+		ret |= regmap_read(pchip->regmap, REG_CL3_BRT_L, &rval_l);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0) {
+		dev_err(pchip->dev, "fail : i2c access to register.\n");
+		return ret;
+	}
+	bl->props.brightness = (rval_h << 8) | rval_l;
+	return bl->props.brightness;
+}
+
+static int lp8860_update_status_bled0(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED0);
+}
+
+static int lp8860_get_brightness_bled0(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED0);
+}
+
+static int lp8860_update_status_bled1(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED1);
+}
+
+static int lp8860_get_brightness_bled1(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED1);
+}
+
+static int lp8860_update_status_bled2(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED2);
+}
+
+static int lp8860_get_brightness_bled2(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED2);
+}
+
+static int lp8860_update_status_bled3(struct backlight_device *bl)
+{
+	return lp8860_bled_update_status(bl, LP8860_LED3);
+}
+
+static int lp8860_get_brightness_bled3(struct backlight_device *bl)
+{
+	return lp8860_bled_get_brightness(bl, LP8860_LED3);
+}
+
+#define lp8860_bled_ops(_id)\
+{\
+	.options = BL_CORE_SUSPENDRESUME,\
+	.update_status = lp8860_update_status_bled##_id,\
+	.get_brightness = lp8860_get_brightness_bled##_id,\
+}
+
+static const struct backlight_ops lp8860_bled_ops[LP8860_LED_MAX] = {
+	[LP8860_LED0] = lp8860_bled_ops(0),
+	[LP8860_LED1] = lp8860_bled_ops(1),
+	[LP8860_LED2] = lp8860_bled_ops(2),
+	[LP8860_LED3] = lp8860_bled_ops(3),
+};
+
+/* current control */
+static int lp8860_set_current(struct device *dev,
+			      const char *buf, enum lp8860_leds nsr)
+{
+	struct lp8860_chip *pchip = dev_get_drvdata(dev);
+	unsigned int ival;
+	ssize_t ret;
+
+	ret = kstrtouint(buf, 10, &ival);
+	if (ret)
+		return ret;
+
+	switch (nsr) {
+	case LP8860_LED0:
+		ival = min_t(unsigned int, ival, LP8860_LED0_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL0_I_H, ival >> 8);
+		ret |= regmap_write(pchip->regmap, REG_CL0_I_L, ival & 0xff);
+		break;
+	case LP8860_LED1:
+		ival = min_t(unsigned int, ival, LP8860_LED1_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL1_I, ival & 0xff);
+		break;
+	case LP8860_LED2:
+		ival = min_t(unsigned int, ival, LP8860_LED2_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL2_I, ival & 0xff);
+		break;
+	case LP8860_LED3:
+		ival = min_t(unsigned int, ival, LP8860_LED3_BR_MAX);
+		ret = regmap_write(pchip->regmap, REG_CL3_I, ival & 0xff);
+		break;
+	default:
+		BUG();
+	}
+	if (ret < 0)
+		dev_err(pchip->dev, "fail : i2c access error.\n");
+
+	return ret;
+}
+
+static ssize_t lp8860_current_store_bled0(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED0);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled1(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED1);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled2(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED2);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+static ssize_t lp8860_current_store_bled3(struct device *dev,
+					  struct device_attribute *devAttr,
+					  const char *buf, size_t size)
+{
+	int ret;
+
+	ret = lp8860_set_current(dev, buf, LP8860_LED3);
+	if (ret < 0)
+		return ret;
+	return size;
+}
+
+#define lp8860_attr(_name, _show, _store)\
+{\
+	.attr = {\
+		.name = _name,\
+		.mode = S_IWUSR,\
+	},\
+	.show = _show,\
+	.store = _store,\
+}
+
+static struct device_attribute lp8860_dev_attr[LP8860_LED_MAX] = {
+	[LP8860_LED0] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled0),
+	[LP8860_LED1] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled1),
+	[LP8860_LED2] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled2),
+	[LP8860_LED3] = lp8860_attr("current", NULL,
+				    lp8860_current_store_bled3),
+};
+
+/*
+ * eeprom write and readback to check.
+ * eeprom register range is from 60h to 78h
+ * buffer value to write data [reg] [data]
+ * e.g) to change the register 0x60 value to 0xff
+ *      buffer value should be 60 ff
+ */
+static ssize_t lp8860_eeprom_store(struct device *dev,
+				   struct device_attribute *devAttr,
+				   const char *buf, size_t size)
+{
+	struct lp8860_chip *pchip = dev_get_drvdata(dev);
+	unsigned int reg, data, rval;
+	char *tok;
+	int ret;
+
+	/* register no. */
+	tok = strsep((char **)&buf, " ,\n");
+	if (tok = NULL)
+		goto err_input;
+	ret = kstrtouint(tok, 16, &reg);
+	if (ret)
+		goto err_input;
+
+	/* register value */
+	tok = strsep((char **)&buf, " ,\n");
+	if (tok = NULL)
+		goto err_input;
+	ret = kstrtouint(tok, 16, &data);
+	if (ret)
+		goto err_input;
+	/*
+	 * EEPROM Programming sequence
+	 *    (program data permanently from registers to NVM)
+	 * 1. Unlock EEPROM by writing
+	 *    the unlock codes to register 1Ah(08, BA, EF)
+	 * 2. Write data to EEPROM registers (address 60h...78h)
+	 * 3. Write EE_PROG to 1 in address 19h. (02h to address 19h)
+	 * 4. Wait 100ms for chip interanl dealy to access the eeprom
+	 * 5. Write EE_PROG to 0 in address 19h. (00h to address 19h)
+	 */
+	if (reg < REG_EEPROM_START || reg > REG_EEPROM_END || data > 0xff)
+		goto err_input;
+	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
+	ret |= regmap_write(pchip->regmap, reg, data);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x02);
+	msleep(100);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
+	if (ret < 0)
+		goto err_i2c;
+
+	/* read back */
+	ret = regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0x08);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xba);
+	ret |= regmap_write(pchip->regmap, REG_ROM_UNLOCK, 0xef);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x01);
+	msleep(100);
+	ret |= regmap_write(pchip->regmap, REG_ROM_CTRL, 0x00);
+	ret |= regmap_read(pchip->regmap, reg, &rval);
+	if (ret < 0)
+		goto err_i2c;
+	if (rval != data)
+		dev_err(pchip->dev, "fail : eeprom did not change.\n");
+
+	return size;
+
+err_i2c:
+	dev_err(pchip->dev, "fail : i2c access error.\n");
+	return ret;
+
+err_input:
+	dev_err(pchip->dev, "fail : input fail.\n");
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(eeprom, S_IWUSR, NULL, lp8860_eeprom_store);
+
+/* backlight register and remove */
+static char *lp8860_bled_name[LP8860_LED_MAX] = {
+	[LP8860_LED0] = "bled0",
+	[LP8860_LED1] = "bled1",
+	[LP8860_LED2] = "bled2",
+	[LP8860_LED3] = "bled3",
+};
+
+static int lp8860_backlight_remove(struct lp8860_chip *pchip)
+{
+	int icnt;
+
+	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
+		if (pchip->bled[icnt])
+			device_remove_file(&(pchip->bled[icnt]->dev),
+					   &lp8860_dev_attr[icnt]);
+	}
+	return 0;
+}
+
+static int lp8860_backlight_registers(struct lp8860_chip *pchip)
+{
+	struct backlight_properties props;
+	struct lp8860_platform_data *pdata = pchip->pdata;
+	int icnt, ret;
+
+	props.type = BACKLIGHT_RAW;
+	for (icnt = LP8860_LED0; icnt < LP8860_LED_MAX; icnt++) {
+		props.max_brightness = pdata->max_brt[icnt];
+		pchip->bled[icnt] +		    devm_backlight_device_register(pchip->dev,
+						   lp8860_bled_name[icnt],
+						   pchip->dev, pchip,
+						   &lp8860_bled_ops[icnt],
+						   &props);
+		if (IS_ERR(pchip->bled[icnt])) {
+			dev_err(pchip->dev, "fail : backlight register.\n");
+			ret = PTR_ERR(pchip->bled[icnt]);
+			goto err_out;
+		}
+		/* to control current */
+		ret = device_create_file(&(pchip->bled[icnt]->dev),
+					 &lp8860_dev_attr[icnt]);
+		if (ret < 0) {
+			dev_err(pchip->dev, "fail : to add sysfs entries.\n");
+			goto err_out;
+		}
+	}
+	/* to access eeprom */
+	ret = device_create_file(&(pchip->bled[LP8860_LED0]->dev),
+				 &dev_attr_eeprom);
+	if (ret < 0) {
+		dev_err(pchip->dev, "fail : to add sysfs entries.\n");
+		goto err_out;
+	}
+	return 0;
+
+err_out:
+	lp8860_backlight_remove(pchip);
+	return ret;
+}
+
+static const struct regmap_config lp8860_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG_MAX,
+};
+
+static int lp8860_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct lp8860_chip *pchip;
+	struct lp8860_platform_data *pdata = dev_get_platdata(&client->dev);
+	int ret, icnt;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "fail : i2c functionality check.\n");
+		return -EOPNOTSUPP;
+	}
+
+	pchip = devm_kzalloc(&client->dev,
+			     sizeof(struct lp8860_chip), GFP_KERNEL);
+	if (!pchip)
+		return -ENOMEM;
+	pchip->dev = &client->dev;
+
+	pchip->regmap = devm_regmap_init_i2c(client, &lp8860_regmap);
+	if (IS_ERR(pchip->regmap)) {
+		ret = PTR_ERR(pchip->regmap);
+		dev_err(pchip->dev, "fail : allocate i2c register map.\n");
+		return ret;
+	}
+
+	if (pdata = NULL) {
+		pdata = devm_kzalloc(pchip->dev,
+				     sizeof(struct lp8860_platform_data),
+				     GFP_KERNEL);
+		if (pdata = NULL)
+			return -ENOMEM;
+		pdata->max_brt[LP8860_LED0] = LP8860_LED0_BR_MAX;
+		for (icnt = LP8860_LED1; icnt < LP8860_LED_MAX; icnt++)
+			pdata->max_brt[icnt] = LP8860_LED1_BR_MAX;
+	}
+	pchip->pdata = pdata;
+
+	i2c_set_clientdata(client, pchip);
+	ret = lp8860_backlight_registers(pchip);
+	return ret;
+}
+
+static int lp8860_remove(struct i2c_client *client)
+{
+	struct lp8860_chip *pchip = i2c_get_clientdata(client);
+
+	device_remove_file(&(pchip->bled[LP8860_LED0]->dev), &dev_attr_eeprom);
+	return lp8860_backlight_remove(i2c_get_clientdata(client));
+}
+
+static const struct i2c_device_id lp8860_id[] = {
+	{LP8860_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp8860_id);
+static struct i2c_driver lp8860_i2c_driver = {
+	.driver = {
+		.name = LP8860_NAME,
+	},
+	.probe = lp8860_probe,
+	.remove = lp8860_remove,
+	.id_table = lp8860_id,
+};
+
+module_i2c_driver(lp8860_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8860 Backlight Driver");
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/lp8860_bl.h b/include/linux/platform_data/lp8860_bl.h
new file mode 100644
index 0000000..9edd7cf
--- /dev/null
+++ b/include/linux/platform_data/lp8860_bl.h
@@ -0,0 +1,54 @@
+/*
+ * Simple driver for Texas Instruments LP8860 Backlight driver chip
+ * Copyright (C) 2014 Texas Instruments
+ *
+ * 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 __LP8860_H
+#define __LP8860_H
+
+#define LP8860_NAME "lp8860"
+#define LP8860_ADDR 0x2d
+
+#define LP8860_LED0_BR_MAX 65535
+#define LP8860_LED1_BR_MAX 8191
+#define LP8860_LED2_BR_MAX 8191
+#define LP8860_LED3_BR_MAX 8191
+
+#define LP8860_LED0_I_MAX 4095
+#define LP8860_LED1_I_MAX 255
+#define LP8860_LED2_I_MAX 255
+#define LP8860_LED3_I_MAX 255
+
+enum lp8860_leds {
+	LP8860_LED0 = 0,
+	LP8860_LED1,
+	LP8860_LED2,
+	LP8860_LED3,
+	LP8860_LED_MAX
+};
+
+enum lp8860_ctrl_mode {
+	LP8860_CTRL_I2C = 0,
+	LP8860_CTRL_I2C_PWM,
+};
+
+/* struct lp8860 platform data
+ * @mode : control mode
+ * @max_brt : maximum brightness.
+ *		LED0 0 ~ 65535
+ *		LED1 0 ~ 8191
+ *		LED2 0 ~ 8191
+ *		LED3 0 ~ 8191
+ */
+struct lp8860_platform_data {
+
+	enum lp8860_ctrl_mode mode;
+	int max_brt[LP8860_LED_MAX];
+};
+
+#endif /* __LP8860_H */
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH v5 1/2] video: ARM CLCD: Add DT support
From: Pawel Moll @ 2014-03-13 11:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdYBuxYko5JD5ZCfoQq+PeXtkKP9eprk9HM=ghW2YMoMuA@mail.gmail.com>

On Thu, 2014-03-13 at 09:30 +0000, Linus Walleij wrote:
> On Thu, Mar 6, 2014 at 11:21 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> > On 05/03/14 18:23, Pawel Moll wrote:
> >> This patch adds basic DT bindings for the PL11x CLCD cells
> >> and make their fbdev driver use them.
> >
> > Is this an old HW, and presumably there won't be new users for it?
> 
> AFAICT ARM really like to re-synthesize this piece of HW in every
> new reference design they make. 

Not for long now, hopefully...

> > If
> > yes, this is probably fine. If not, you might want to look at the video
> > ports and endpoints, which is used by at least three not-yet-merged series:
> >
> > [PATCHv3 00/41] OMAPDSS: DT support v3
> > [PATCH v5 00/11] imx-drm dt bindings
> > [RFC PATCH v2 00/21] Add DSI display support for Exynos based boards
> >
> > Using bindings like that would be more future proof, even if the current
> > driver doesn't use them.
> 
> I take it that it shouldn't matter if the driver is for framebuffer or
> DRM (as was implied by some answer here) the hardware
> description should be the same no matter what, so the more
> furture-proof the better.

Again, no argument here - the clcd-specific properties will be of use
whatever happens in the future (the "immediate" display timing subnode
is optional and is cloned from other existing bindings, so no new
problem is introduced here). I'm just shying away from the discussions
on generic display (or CDF or video or whatever) bindings. Call me
coward if you wish (maybe just tired to death with this subject ;-)

Pawel


^ permalink raw reply

* Re: [PATCH v5 1/2] video: ARM CLCD: Add DT support
From: Russell King - ARM Linux @ 2014-03-13 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <531DAEB9.3020502@ti.com>

On Mon, Mar 10, 2014 at 02:23:21PM +0200, Tomi Valkeinen wrote:
> On 10/03/14 14:09, Pawel Moll wrote:
> 
> >> Note that the same DT bindings you add here should also work for the DRM
> >> driver in the future. So, in fact, the question is extended to: will the
> >> fbdev 
> > 
> > No, I don't think so. It's a end of line for it, I believe. From my
> > personal point of view the main goal is to fill the last gap between DT
> > and non-DT support on one of the Versatile Express boards - CLCD works
> > fine when booted with ATAGs, doesn't work when booted with DT. It looks
> > bad.
> 
> The DT describes the hardware, and there should be only one description
> of it, no matter what the used SW is. I see compatible = "arm,pl111" in
> the dts. PL111 is the LCD controller, right? What will the DRM driver
> use, then, if the "arm,pl111" DT data is designed to work only for the
> fbdev?

If we could move forward with things like DT bindings for DRM (which
seems impossible) then we might be able to move forward with a proper
DT implementation for componentised video systems which would solve
this as you'd have the pl111 as just a CRTC component in a larger
subsystem representation which included things like encoders and
connectors - even for something as simple as the Versatile Express
boards.

These boards have a DVI connector which offers analogue (and probably
digital) output.  Previous boards like Versatile and Integrator have
offered VGA output and a connector for various LCD panels (sometimes
the connected LCD panel is identified via a set of GPIOs.)

So, going ahead with some bindings which include stuff like timing
information in a pl111 node seems wrong and boxes us in if we're going
to start representing connectors as well - as the timing should be part
of the panel node or similar.

So basically all movement on display subsystem DT representations is
now blocked because no one can agree how they should be represented in
a decent way.

Maybe board files were much better than this frigging DT crap.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply

* Re: [PATCH v5 1/2] video: ARM CLCD: Add DT support
From: Pawel Moll @ 2014-03-13 13:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <531DAEB9.3020502@ti.com>

On Mon, 2014-03-10 at 12:23 +0000, Tomi Valkeinen wrote:
> The DT describes the hardware, and there should be only one description
> of it, no matter what the used SW is. I see compatible = "arm,pl111" in
> the dts. PL111 is the LCD controller, right? 

Correct.

> What will the DRM driver
> use, then, 

Exactly the same properties, plus (hopefully) the generic display data,
when (if) ready.

> if the "arm,pl111" DT data is designed to work only for the
> fbdev?

The binding I proposed is *not* designed to work only with the fbdev
driver, no. That's what I was trying to say all way long, if I failed -
apologies.

So let me say it again: with the exception display timings subnode, all
other properties will be important for the DRM scan out driver as well.
As to the display timings, being optional can be easily marked as
deprecated and replaced with the proper solution.

Now, if you find any other property I proposed being non generic enough
(ie. fbdev-specific), I will happily discuss it. Once you get generic
display bindings in place, I will gladly do all that will be required to
make CLCD driver(s) use them. But I will rather drop and forget this
patch completely that get dragged into another
"display/video/CDF/DRM/whatever" discussion. Hope I made myself clear.

Pawel


^ permalink raw reply

* [PATCH] backlight: lm3639: use devm_backlight_device_register()
From: Daniel Jeong @ 2014-03-14  2:14 UTC (permalink / raw)
  To: Jingoo Han
  Cc: Daniel Jeong, linux-fbdev, linux-kernel,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Bryan Wu,
	Lee Jones

 change to use devm_backlight_device_register() for simple cleanup.

Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>
---
 drivers/video/backlight/lm3639_bl.c |   17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c
index 6fd60ad..5f36808 100644
--- a/drivers/video/backlight/lm3639_bl.c
+++ b/drivers/video/backlight/lm3639_bl.c
@@ -349,8 +349,9 @@ static int lm3639_probe(struct i2c_client *client,
 	props.brightness = pdata->init_brt_led;
 	props.max_brightness = pdata->max_brt_led;
 	pchip->bled -	    backlight_device_register("lm3639_bled", pchip->dev, pchip,
-				      &lm3639_bled_ops, &props);
+	    devm_backlight_device_register(pchip->dev, "lm3639_bled",
+					   pchip->dev, pchip, &lm3639_bled_ops,
+					   &props);
 	if (IS_ERR(pchip->bled)) {
 		dev_err(&client->dev, "fail : backlight register\n");
 		ret = PTR_ERR(pchip->bled);
@@ -360,7 +361,7 @@ static int lm3639_probe(struct i2c_client *client,
 	ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
 	if (ret < 0) {
 		dev_err(&client->dev, "failed : add sysfs entries\n");
-		goto err_bled_mode;
+		goto err_out;
 	}
 
 	/* flash */
@@ -391,8 +392,6 @@ err_torch:
 	led_classdev_unregister(&pchip->cdev_flash);
 err_flash:
 	device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
-err_bled_mode:
-	backlight_device_unregister(pchip->bled);
 err_out:
 	return ret;
 }
@@ -407,10 +406,8 @@ static int lm3639_remove(struct i2c_client *client)
 		led_classdev_unregister(&pchip->cdev_torch);
 	if (&pchip->cdev_flash)
 		led_classdev_unregister(&pchip->cdev_flash);
-	if (pchip->bled) {
+	if (pchip->bled)
 		device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
-		backlight_device_unregister(pchip->bled);
-	}
 	return 0;
 }
 
@@ -432,6 +429,6 @@ static struct i2c_driver lm3639_i2c_driver = {
 module_i2c_driver(lm3639_i2c_driver);
 
 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
-MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
-MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
 MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH] backlight: lm3639: use devm_backlight_device_register()
From: Jingoo Han @ 2014-03-14  2:22 UTC (permalink / raw)
  To: 'Lee Jones', 'Bryan Wu'
  Cc: 'Daniel Jeong', linux-fbdev, linux-kernel,
	'Jean-Christophe Plagniol-Villard',
	'Tomi Valkeinen', 'Jingoo Han'
In-Reply-To: <1394763240-10176-1-git-send-email-gshark.jeong@gmail.com>

On Friday, March 14, 2014 11:14 AM, Daniel Jeong wrote:
> 
>  change to use devm_backlight_device_register() for simple cleanup.
> 
> Signed-off-by: Daniel Jeong <gshark.jeong@gmail.com>

Acked-by: Jingoo Han <jg1.han@samsung.com>

Lee Jones,
Would you merge this patch into your backlight tree?

Best regards,
Jingoo Han

> ---
>  drivers/video/backlight/lm3639_bl.c |   17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c
> index 6fd60ad..5f36808 100644
> --- a/drivers/video/backlight/lm3639_bl.c
> +++ b/drivers/video/backlight/lm3639_bl.c
> @@ -349,8 +349,9 @@ static int lm3639_probe(struct i2c_client *client,
>  	props.brightness = pdata->init_brt_led;
>  	props.max_brightness = pdata->max_brt_led;
>  	pchip->bled > -	    backlight_device_register("lm3639_bled", pchip->dev, pchip,
> -				      &lm3639_bled_ops, &props);
> +	    devm_backlight_device_register(pchip->dev, "lm3639_bled",
> +					   pchip->dev, pchip, &lm3639_bled_ops,
> +					   &props);
>  	if (IS_ERR(pchip->bled)) {
>  		dev_err(&client->dev, "fail : backlight register\n");
>  		ret = PTR_ERR(pchip->bled);
> @@ -360,7 +361,7 @@ static int lm3639_probe(struct i2c_client *client,
>  	ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
>  	if (ret < 0) {
>  		dev_err(&client->dev, "failed : add sysfs entries\n");
> -		goto err_bled_mode;
> +		goto err_out;
>  	}
> 
>  	/* flash */
> @@ -391,8 +392,6 @@ err_torch:
>  	led_classdev_unregister(&pchip->cdev_flash);
>  err_flash:
>  	device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
> -err_bled_mode:
> -	backlight_device_unregister(pchip->bled);
>  err_out:
>  	return ret;
>  }
> @@ -407,10 +406,8 @@ static int lm3639_remove(struct i2c_client *client)
>  		led_classdev_unregister(&pchip->cdev_torch);
>  	if (&pchip->cdev_flash)
>  		led_classdev_unregister(&pchip->cdev_flash);
> -	if (pchip->bled) {
> +	if (pchip->bled)
>  		device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
> -		backlight_device_unregister(pchip->bled);
> -	}
>  	return 0;
>  }
> 
> @@ -432,6 +429,6 @@ static struct i2c_driver lm3639_i2c_driver = {
>  module_i2c_driver(lm3639_i2c_driver);
> 
>  MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
> -MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
> -MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
> +MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
> +MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
>  MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5


^ permalink raw reply

* [PATCH v7][ 1/5] video: mx3fb: Use devm_kzalloc
From: Denis Carikli @ 2014-03-14  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Replace kzalloc by devm_kzalloc and remove the kfree() calls.

Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v6->v7:
- Removed the Cc from the patch, they went into 
  git send-email instead.
ChangeLog v5->v6:
 - New patch need
---
 drivers/video/fbdev/mx3fb.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 142e860..ee95de8 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -1496,7 +1496,7 @@ static int mx3fb_probe(struct platform_device *pdev)
 	if (!sdc_reg)
 		return -EINVAL;
 
-	mx3fb = kzalloc(sizeof(*mx3fb), GFP_KERNEL);
+	mx3fb = devm_kzalloc(&pdev->dev, sizeof(*mx3fb), GFP_KERNEL);
 	if (!mx3fb)
 		return -ENOMEM;
 
@@ -1542,7 +1542,6 @@ ersdc0:
 	dmaengine_put();
 	iounmap(mx3fb->reg_base);
 eremap:
-	kfree(mx3fb);
 	dev_err(dev, "mx3fb: failed to register fb\n");
 	return ret;
 }
@@ -1561,7 +1560,6 @@ static int mx3fb_remove(struct platform_device *dev)
 	dmaengine_put();
 
 	iounmap(mx3fb->reg_base);
-	kfree(mx3fb);
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH v7][ 2/5] video: mx3fb: Add device tree suport.
From: Denis Carikli @ 2014-03-14  9:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1394788369-5096-1-git-send-email-denis@eukrea.com>

This patch is based on:
  838bdf7 video: mxsfb: fix broken videomode selection

Signed-off-by: Denis Carikli <denis@eukrea.com>
---
ChangeLog v6->v7:
- Removed the Cc from the patch, they went into 
  git send-email instead.

ChangeLog v5->v6:
- Shrinked the Cc list.
- de-active and pixelclk-active dt properties are
  now handled in this patch to get rid of the
  "fbdev: Add the lacking FB_SYNC_* for matching the DISPLAY_FLAGS_*" patch

ChangeLog v4->v5:
- Added some people in the Cc list.
- The full ipu register range is now passed to the driver,
  the code and the documentation were adapted to it.
- Updated the documentation not to mention the lcd controller, the ipu was
  mentioned instead.
- The ipu patch was removed from this patchset, as a consequence the mx3fb code
  has been adapted not to expect the dma ipu driver to be probed trough the device tree.

ChangeLog v3->v4:
- Updated bindings.
- Updated documentation accordinly.
- Updated code accordinly.
- Fixed the lack of "ret =" in
  of_property_read_string(display_np, "model", &name);
- Supressed some compilation warnings.

ChangeLog v2->v3:
- The device tree bindings were reworked in order to make it look more like the
  IPUv3 bindings.
- The interface_pix_fmt property now looks like the IPUv3 one.
---
 .../devicetree/bindings/video/fsl,mx3-fb.txt       |   44 +++++
 drivers/video/fbdev/Kconfig                        |    2 +
 drivers/video/fbdev/mx3fb.c                        |  185 +++++++++++++++++---
 3 files changed, 208 insertions(+), 23 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/fsl,mx3-fb.txt

diff --git a/Documentation/devicetree/bindings/video/fsl,mx3-fb.txt b/Documentation/devicetree/bindings/video/fsl,mx3-fb.txt
new file mode 100644
index 0000000..c0409a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,mx3-fb.txt
@@ -0,0 +1,44 @@
+Freescale MX3 IPU.
+=========
+
+Required properties:
+- compatible: Should be "fsl,<chip>-ipu". compatible chips include the imx31 and the
+  imx35.
+- reg: should be register base and length as documented in the datasheet.
+- clocks: Handle to the ipu_gate clock.
+- display: Phandle to a "fsl,mx3-parallel-display" compatible display node
+  which is described below.
+
+Example:
+
+ipu: ipu@53fc0000 {
+	compatible = "fsl,imx35-ipu";
+	reg = <0x53fc0000 0x4000>;
+	clocks = <&clks 55>;
+};
+
+Parallel display support
+============
+
+Required properties:
+- compatible: Should be "fsl,mx3-parallel-display".
+- model : The user-visible name of the display.
+
+Optional properties:
+- interface_pix_fmt: How this display is connected to the
+  crtc. Currently supported types: "rgb24", "rgb565", "rgb666".
+
+It can also have an optional timing subnode as described in
+  Documentation/devicetree/bindings/video/display-timing.txt.
+
+Example:
+
+display0: display@di0 {
+	compatible = "fsl,mx3-parallel-display";
+	interface-pix-fmt = "rgb666";
+	model = "CMO-QVGA";
+};
+
+&ipu {
+	display = <&display0>;
+}
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 67409e0..c996b96 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2330,6 +2330,8 @@ config FB_MX3
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select VIDEOMODE_HELPERS
+	select FB_MODE_HELPERS
 	default y
 	help
 	  This is a framebuffer device for the i.MX31 LCD Controller. So
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index ee95de8..952d2b5 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -31,6 +31,10 @@
 #include <linux/platform_data/dma-imx.h>
 #include <linux/platform_data/video-mx3fb.h>
 
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -237,6 +241,8 @@ static const struct fb_videomode mx3fb_modedb[] = {
 
 struct mx3fb_data {
 	struct fb_info		*fbi;
+	struct videomode	*vm;
+	struct fb_videomode	*fb_vm;
 	int			backlight_level;
 	void __iomem		*reg_base;
 	spinlock_t		lock;
@@ -269,6 +275,7 @@ struct mx3fb_info {
 	struct scatterlist		sg[2];
 
 	struct fb_var_screeninfo	cur_var; /* current var info */
+	uint32_t			flags;
 };
 
 static void mx3fb_dma_done(void *);
@@ -753,16 +760,32 @@ static int __set_par(struct fb_info *fbi, bool lock)
 
 	if (mx3_fbi->ipu_ch = IDMAC_SDC_0) {
 		memset(&sig_cfg, 0, sizeof(sig_cfg));
+
 		if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
 			sig_cfg.Hsync_pol = true;
+
 		if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
 			sig_cfg.Vsync_pol = true;
-		if (fbi->var.sync & FB_SYNC_CLK_INVERT)
-			sig_cfg.clk_pol = true;
+
+		if (fbi->device->of_node) {
+			if (mx3_fbi->flags & FB_SYNC_CLK_INVERT)
+				sig_cfg.clk_pol = true;
+		} else {
+			if (fbi->var.sync & FB_SYNC_CLK_INVERT)
+				sig_cfg.clk_pol = true;
+		}
+
 		if (fbi->var.sync & FB_SYNC_DATA_INVERT)
 			sig_cfg.data_pol = true;
-		if (fbi->var.sync & FB_SYNC_OE_ACT_HIGH)
-			sig_cfg.enable_pol = true;
+
+		if (fbi->device->of_node) {
+			if (mx3_fbi->flags & FB_SYNC_OE_ACT_HIGH)
+				sig_cfg.enable_pol = true;
+		} else {
+			if (fbi->var.sync & FB_SYNC_OE_ACT_HIGH)
+				sig_cfg.enable_pol = true;
+		}
+
 		if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
 			sig_cfg.clkidle_en = true;
 		if (fbi->var.sync & FB_SYNC_CLK_SEL_EN)
@@ -1266,7 +1289,8 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
 						  &addr, GFP_DMA | GFP_KERNEL);
 
 	if (!fbi->screen_base) {
-		dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
+		dev_err(fbi->device,
+			"Cannot allocate %u bytes framebuffer memory\n",
 			mem_len);
 		retval = -EBUSY;
 		goto err0;
@@ -1280,7 +1304,8 @@ static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
 		mutex_unlock(&fbi->mm_lock);
 
 	dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
-		(uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
+		(uint32_t) fbi->fix.smem_start,
+		fbi->screen_base, fbi->fix.smem_len);
 
 	fbi->screen_size = fbi->fix.smem_len;
 
@@ -1351,21 +1376,68 @@ static struct fb_info *mx3fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
 	return fbi;
 }
 
+static int match_dt_disp_data(const char *property)
+{
+	if (!strcmp("rgb666", property))
+		return IPU_DISP_DATA_MAPPING_RGB666;
+	else if (!strcmp("rgb565", property))
+		return IPU_DISP_DATA_MAPPING_RGB565;
+	else if (!strcmp("rgb24", property))
+		return IPU_DISP_DATA_MAPPING_RGB888;
+	else
+		return -EINVAL;
+}
+
 static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
 {
 	struct device *dev = mx3fb->dev;
 	struct mx3fb_platform_data *mx3fb_pdata = dev_get_platdata(dev);
-	const char *name = mx3fb_pdata->name;
+	struct device_node *np = dev->of_node;
+	const char *name;
+	const char *ipu_disp_format;
 	unsigned int irq;
 	struct fb_info *fbi;
 	struct mx3fb_info *mx3fbi;
 	const struct fb_videomode *mode;
 	int ret, num_modes;
+	struct device_node *display_np = NULL;
+
+	if (np) {
+		display_np = of_parse_phandle(np, "display", 0);
+		if (!display_np) {
+			dev_err(dev, "Can't get the display device node.\n");
+			return -EINVAL;
+		}
+
+		of_property_read_string(display_np, "interface-pix-fmt",
+					&ipu_disp_format);
+		if (!ipu_disp_format) {
+			mx3fb->disp_data_fmt = IPU_DISP_DATA_MAPPING_RGB666;
+			dev_warn(dev,
+				"ipu display data mapping was not defined, using the default rgb666.\n");
+		} else {
+			mx3fb->disp_data_fmt +				match_dt_disp_data(ipu_disp_format);
+		}
 
-	if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) {
-		dev_err(dev, "Illegal display data format %d\n",
+		if (mx3fb->disp_data_fmt = -EINVAL) {
+			dev_err(dev, "Illegal display data format \"%s\"\n",
+				ipu_disp_format);
+			return -EINVAL;
+		}
+
+		ret = of_property_read_string(display_np, "model", &name);
+		if (ret) {
+			dev_err(dev, "Missing display model name\n");
+			return -EINVAL;
+		}
+	} else {
+		name = mx3fb_pdata->name;
+		if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) {
+			dev_err(dev, "Illegal display data format %d\n",
 				mx3fb_pdata->disp_data_fmt);
-		return -EINVAL;
+			return -EINVAL;
+		}
 	}
 
 	ichan->client = mx3fb;
@@ -1386,12 +1458,36 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
 		goto emode;
 	}
 
-	if (mx3fb_pdata->mode && mx3fb_pdata->num_modes) {
-		mode = mx3fb_pdata->mode;
-		num_modes = mx3fb_pdata->num_modes;
+	mx3fbi = fbi->par;
+
+	if (np) {
+		ret = of_get_videomode(display_np, mx3fb->vm,
+				       OF_USE_NATIVE_MODE);
+		if (ret) {
+			dev_err(dev, "failed to get videomode from DT\n");
+			goto put_display_node;
+		}
+
+		ret = fb_videomode_from_videomode(mx3fb->vm, mx3fb->fb_vm);
+		if (ret < 0)
+			goto put_display_node;
+
+		if (mx3fb->vm->flags & DISPLAY_FLAGS_DE_HIGH)
+			mx3fbi->flags |= FB_SYNC_OE_ACT_HIGH;
+
+		if (mx3fb->vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+			mx3fbi->flags |= FB_SYNC_CLK_INVERT;
+
+		mode = mx3fb->fb_vm;
+		num_modes = 1;
 	} else {
-		mode = mx3fb_modedb;
-		num_modes = ARRAY_SIZE(mx3fb_modedb);
+		if (mx3fb_pdata->mode && mx3fb_pdata->num_modes) {
+			mode = mx3fb_pdata->mode;
+			num_modes = mx3fb_pdata->num_modes;
+		} else {
+			mode = mx3fb_modedb;
+			num_modes = ARRAY_SIZE(mx3fb_modedb);
+		}
 	}
 
 	if (!fb_find_mode(&fbi->var, fbi, fb_mode, mode,
@@ -1415,13 +1511,13 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
 	sdc_set_global_alpha(mx3fb, true, 0xFF);
 	sdc_set_color_key(mx3fb, IDMAC_SDC_0, false, 0);
 
-	mx3fbi			= fbi->par;
 	mx3fbi->idmac_channel	= ichan;
 	mx3fbi->ipu_ch		= ichan->dma_chan.chan_id;
 	mx3fbi->mx3fb		= mx3fb;
 	mx3fbi->blank		= FB_BLANK_NORMAL;
 
-	mx3fb->disp_data_fmt	= mx3fb_pdata->disp_data_fmt;
+	if (!np)
+		mx3fb->disp_data_fmt = mx3fb_pdata->disp_data_fmt;
 
 	init_completion(&mx3fbi->flip_cmpl);
 	disable_irq(ichan->eof_irq);
@@ -1440,6 +1536,8 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
 
 	return 0;
 
+put_display_node:
+	of_node_put(display_np);
 erfb:
 esetpar:
 emode:
@@ -1455,17 +1553,21 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
 	struct device *dev;
 	struct mx3fb_platform_data *mx3fb_pdata;
 
-	if (!imx_dma_is_ipu(chan))
-		return false;
-
 	if (!rq)
 		return false;
 
 	dev = rq->mx3fb->dev;
 	mx3fb_pdata = dev_get_platdata(dev);
 
-	return rq->id = chan->chan_id &&
-		mx3fb_pdata->dma_dev = chan->device->dev;
+	if (!imx_dma_is_ipu(chan) && mx3fb_pdata)
+		return false;
+
+	/* When using the devicetree, mx3fb_pdata is NULL */
+	if (mx3fb_pdata)
+		return rq->id = chan->chan_id &&
+			mx3fb_pdata->dma_dev = chan->device->dev;
+	else
+		return rq->id = chan->chan_id;
 }
 
 static void release_fbi(struct fb_info *fbi)
@@ -1487,6 +1589,9 @@ static int mx3fb_probe(struct platform_device *pdev)
 	dma_cap_mask_t mask;
 	struct dma_chan *chan;
 	struct dma_chan_request rq;
+	struct device_node *np = dev->of_node;
+	struct videomode *vm;
+	struct fb_videomode *fb_vm;
 
 	/*
 	 * Display Interface (DI) and Synchronous Display Controller (SDC)
@@ -1508,7 +1613,33 @@ static int mx3fb_probe(struct platform_device *pdev)
 		goto eremap;
 	}
 
-	pr_debug("Remapped %pR at %p\n", sdc_reg, mx3fb->reg_base);
+	/* The full IPU registers range is passed by the device tree,
+	 * whereas the platform data only passes the SDC registers range.
+	 */
+	if (np) {
+		vm = devm_kzalloc(&pdev->dev, sizeof(struct videomode),
+				  GFP_KERNEL);
+		if (!vm) {
+			ret = -ENOMEM;
+			goto eremap;
+		}
+
+		fb_vm = devm_kzalloc(&pdev->dev, sizeof(struct fb_videomode),
+				     GFP_KERNEL);
+		if (!fb_vm) {
+			ret = -ENOMEM;
+			goto eremap;
+		}
+
+		mx3fb->vm = vm;
+		mx3fb->fb_vm = fb_vm;
+
+		mx3fb->reg_base += MX3FB_REG_OFFSET;
+		pr_debug("Remapped %pR at %p\n", sdc_reg + MX3FB_REG_OFFSET,
+			 mx3fb->reg_base);
+	} else {
+		pr_debug("Remapped %pR at %p\n", sdc_reg, mx3fb->reg_base);
+	}
 
 	/* IDMAC interface */
 	dmaengine_get();
@@ -1563,9 +1694,17 @@ static int mx3fb_remove(struct platform_device *dev)
 	return 0;
 }
 
+static struct of_device_id mx3fb_of_dev_id[] = {
+	{ .compatible = "fsl,imx31-ipu", },
+	{ .compatible = "fsl,imx35-ipu", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mx3fb_of_dev_id);
+
 static struct platform_driver mx3fb_driver = {
 	.driver = {
 		.name = MX3FB_NAME,
+		.of_match_table = mx3fb_of_dev_id,
 		.owner = THIS_MODULE,
 	},
 	.probe = mx3fb_probe,
-- 
1.7.9.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox