* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Dr. H. Nikolaus Schaller @ 2013-10-10 13:42 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Tomi Valkeinen, Marek Belisko, plagnioj, linux-kernel, linux-omap,
linux-fbdev
In-Reply-To: <52569CE8.5070201@metafoo.de>
Am 10.10.2013 um 14:26 schrieb Lars-Peter Clausen:
> On 10/10/2013 02:13 PM, Tomi Valkeinen wrote:
>> On 10/10/13 14:52, Dr. H. Nikolaus Schaller wrote:
>>
>>> Yes, I agree and I am willing to help if someone comes up with such a SoC.
>>> At the moment we have connected it to the OMAP3 only.
>>
>> True, but even without that kind of SoC, SPI bitbanging should be
>> handled by an SPI driver, not by the drivers that use the bus.
>>
>>> I.e. I want not to do a lot of work for others who we just guess about that they
>>> might exist...
>>
>> Yep. It's fine for me, it's not that much extra code in the panel driver.
>>
>>>> The panel hardware has three wires, so the panel driver (if it does
>>>> handle the bus by bitbanging) can only refer to three gpios.
>>>
>>> Hm. The panle hardware has 3 but the SoC (OMAP3) the driver
>>> is running on has 4.
>>
>> Right, but this panel driver is a driver for the panel hardware. Not for
>> the SoC, or the SoC+panel combination. So the panel driver must only use
>> resources as seen by the panel hardware.
>>
>>>> So either
>>>> the bus details should be hidden by using the normal spi framework, or
>>>> if the driver does the bitbanging, use the gpios as specified in the
>>>> panel spec. The panel driver cannot contain any board specific stuff.
>>>
>>> The bitbang driver shown below can handle either 3 or 4 gpios (except
>>> for initialization).
>>
>> It's not a bitbang driver, it's a panel driver. And anyway, if I
>> understood right, your use of 4 gpios was just a hack to try to make it
>> look like a normal 4-wire SPI bus. What you really have is 3 wires, 3
>> gpios. I don't see any reason to use 4 gpios, as two of them are the same.
There is a protection resistor in the one defined as "output" so that
protocol errors don't have two outputs work against each other.
>>
>> Hmm, how does it work anyway. Did I understand it right, the panel's
>> 'DIN' pin is connected to two gpios on the SoC, and one of those gpios
>> is set as output, and the other as input?
Yes.
>> So the SoC is always pulling
>> that line up or down, and the panel is also pulling it up or down when
>> it's sending data. I'm no HW guy but that sounds quite bad =).
Yes, that is the strange thing with this protocol. It does a direction reversal
after some time. I.e. the panel switches its input to output and the SoC has
to be fast enough to do the same. Therefore, we have one output GPIO
(protected by a resistor) and a separate input GPIO.
Sometimes interfacing hardware is indeed strange.
>>
>> I've never written or studied a bitbanging driver, but shouldn't there
>> be just one gpio used on the SoC for DIN, and it would be set to either
>> output or input mode, depending on if we are reading or writing?
>
> Back in the OpenMoko days we used the panel in normal 4-wire SPI mode with
> the GPIO bitbang SPI master. The bitbang code in this driver also looks like
> normal 4 wire.
Thanks for this hint!
Maybe using a standard 4-wire SPI simply works if we only write data and
make sure the panel is not sending anything...
I still hesitate to break working code because it needs quite some time to debug
and we don't even know if it ever works, i.e. sends us to swampy ground...
BR,
Nikolaus
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Lars-Peter Clausen @ 2013-10-10 12:26 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Dr. H. Nikolaus Schaller, Marek Belisko, plagnioj, linux-kernel,
linux-omap, linux-fbdev
In-Reply-To: <525699EF.6090803@ti.com>
On 10/10/2013 02:13 PM, Tomi Valkeinen wrote:
> On 10/10/13 14:52, Dr. H. Nikolaus Schaller wrote:
>
>> Yes, I agree and I am willing to help if someone comes up with such a SoC.
>> At the moment we have connected it to the OMAP3 only.
>
> True, but even without that kind of SoC, SPI bitbanging should be
> handled by an SPI driver, not by the drivers that use the bus.
>
>> I.e. I want not to do a lot of work for others who we just guess about that they
>> might exist...
>
> Yep. It's fine for me, it's not that much extra code in the panel driver.
>
>>> The panel hardware has three wires, so the panel driver (if it does
>>> handle the bus by bitbanging) can only refer to three gpios.
>>
>> Hm. The panle hardware has 3 but the SoC (OMAP3) the driver
>> is running on has 4.
>
> Right, but this panel driver is a driver for the panel hardware. Not for
> the SoC, or the SoC+panel combination. So the panel driver must only use
> resources as seen by the panel hardware.
>
>>> So either
>>> the bus details should be hidden by using the normal spi framework, or
>>> if the driver does the bitbanging, use the gpios as specified in the
>>> panel spec. The panel driver cannot contain any board specific stuff.
>>
>> The bitbang driver shown below can handle either 3 or 4 gpios (except
>> for initialization).
>
> It's not a bitbang driver, it's a panel driver. And anyway, if I
> understood right, your use of 4 gpios was just a hack to try to make it
> look like a normal 4-wire SPI bus. What you really have is 3 wires, 3
> gpios. I don't see any reason to use 4 gpios, as two of them are the same.
>
> Hmm, how does it work anyway. Did I understand it right, the panel's
> 'DIN' pin is connected to two gpios on the SoC, and one of those gpios
> is set as output, and the other as input? So the SoC is always pulling
> that line up or down, and the panel is also pulling it up or down when
> it's sending data. I'm no HW guy but that sounds quite bad =).
>
> I've never written or studied a bitbanging driver, but shouldn't there
> be just one gpio used on the SoC for DIN, and it would be set to either
> output or input mode, depending on if we are reading or writing?
Back in the OpenMoko days we used the panel in normal 4-wire SPI mode with
the GPIO bitbang SPI master. The bitbang code in this driver also looks like
normal 4 wire.
- Lars
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Tomi Valkeinen @ 2013-10-10 12:13 UTC (permalink / raw)
To: Dr. H. Nikolaus Schaller
Cc: Marek Belisko, plagnioj, linux-kernel, linux-omap, linux-fbdev
In-Reply-To: <04AC7291-38E4-421B-979C-BF03D52E94BD@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 2130 bytes --]
On 10/10/13 14:52, Dr. H. Nikolaus Schaller wrote:
> Yes, I agree and I am willing to help if someone comes up with such a SoC.
> At the moment we have connected it to the OMAP3 only.
True, but even without that kind of SoC, SPI bitbanging should be
handled by an SPI driver, not by the drivers that use the bus.
> I.e. I want not to do a lot of work for others who we just guess about that they
> might exist...
Yep. It's fine for me, it's not that much extra code in the panel driver.
>> The panel hardware has three wires, so the panel driver (if it does
>> handle the bus by bitbanging) can only refer to three gpios.
>
> Hm. The panle hardware has 3 but the SoC (OMAP3) the driver
> is running on has 4.
Right, but this panel driver is a driver for the panel hardware. Not for
the SoC, or the SoC+panel combination. So the panel driver must only use
resources as seen by the panel hardware.
>> So either
>> the bus details should be hidden by using the normal spi framework, or
>> if the driver does the bitbanging, use the gpios as specified in the
>> panel spec. The panel driver cannot contain any board specific stuff.
>
> The bitbang driver shown below can handle either 3 or 4 gpios (except
> for initialization).
It's not a bitbang driver, it's a panel driver. And anyway, if I
understood right, your use of 4 gpios was just a hack to try to make it
look like a normal 4-wire SPI bus. What you really have is 3 wires, 3
gpios. I don't see any reason to use 4 gpios, as two of them are the same.
Hmm, how does it work anyway. Did I understand it right, the panel's
'DIN' pin is connected to two gpios on the SoC, and one of those gpios
is set as output, and the other as input? So the SoC is always pulling
that line up or down, and the panel is also pulling it up or down when
it's sending data. I'm no HW guy but that sounds quite bad =).
I've never written or studied a bitbanging driver, but shouldn't there
be just one gpio used on the SoC for DIN, and it would be set to either
output or input mode, depending on if we are reading or writing?
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Dr. H. Nikolaus Schaller @ 2013-10-10 11:52 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Marek Belisko, plagnioj, linux-kernel, linux-omap, linux-fbdev
In-Reply-To: <52568B40.4040802@ti.com>
Hi Tomi,
Am 10.10.2013 um 13:10 schrieb Tomi Valkeinen:
> On 10/10/13 12:34, Dr. H. Nikolaus Schaller wrote:
>> Hi Tomi,
>>
>> Am 10.10.2013 um 10:19 schrieb Tomi Valkeinen:
>>
>>> Hi,
>>>
>>> On 10/10/13 00:08, Marek Belisko wrote:
>>>> For communicating with driver is used gpio bitbanging because TD028 does
>>>> not have a standard compliant SPI interface. It is a 3-wire thing with
>>>> direction reversal.
>>>
>>> Isn't that SPI_3WIRE?
>>
>> Maybe - but we have no complete datasheet and I don't know an official spec of
>> a 3-wire SPI protocol to compare how 3-wire should work.
>
> Yep, and I know only what I read on wikipedia a few hours ago =).
>
>> And I think (but I may be wrong) that SPI_3WIRE is an optional feature of the SoC
>> specific SPI drivers and in my understanding the OMAP has no such driver:
>>
>> http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L874
>>
>> And spi-bitbang.c hasn't either.
>>
>> So I would prefer to leave this as an area for optimizations for future work.
>> Maybe we can add some more comments on this.
>
> Ok. Well, I guess it's not too bad. But it's really not something that
> should be in the panel driver (assuming it's "standard" 3-wire SPI).
> Some SoC could support 3-wire SPI, and then it'd be good to use the SoCs
> hardware for SPI communication. Having bitbanging hardcoded into the
> driver will prevent that.
Yes, I agree and I am willing to help if someone comes up with such a SoC.
At the moment we have connected it to the OMAP3 only.
I.e. I want not to do a lot of work for others who we just guess about that they
might exist...
>
>>>> + int cs_gpio;
>>>> + int scl_gpio;
>>>> + int din_gpio;
>>>> + int dout_gpio;
>>>
>>> Three wires, but four gpios? What am I missing here...
>>
>> We have wired up the 3-wire SPI interface of the display
>> to 4 wires of the McSPI interface because we initially thought
>> that it could work in 4 wire mode as well.
>>
>> The next step we did was to port the driver code from the
>> Openmoko Neo1973 U-Boot which used the gpio-bitbang
>> mechanism.
>>
>> Since it worked and is used only for enabling/disabling the
>> display and for no other purpose we never felt it important
>> to check or modify the code to use SPI.
>>
>> But you are right - we don't use the din_gpio really since
>> we never read registers from the chip. So 3 gpios could be
>> sufficient.
>>
>> Or we must handle the case that din_gpio = dout_gpio
>> in panel_probe to avoid duplicate use of the same gpio.
>
> The panel hardware has three wires, so the panel driver (if it does
> handle the bus by bitbanging) can only refer to three gpios.
Hm. The panle hardware has 3 but the SoC (OMAP3) the driver
is running on has 4.
> So either
> the bus details should be hidden by using the normal spi framework, or
> if the driver does the bitbanging, use the gpios as specified in the
> panel spec. The panel driver cannot contain any board specific stuff.
The bitbang driver shown below can handle either 3 or 4 gpios (except
for initialization).
>
>>>> +static int jbt_spi_xfer(struct panel_drv_data *data, int wordnum, int bitlen)
>>>
>>> Hmm, if it's not SPI, maybe it shouldn't be called SPI?
>>
>> Yes, we can remove the _spi_ in this name.
>
> Or maybe use "spi3w" or such, just to make it clear it's not plain
> standard spi. Again, presuming it's really 3-wire spi =).
>
>>>> +static int td028ttec1_panel_probe(struct platform_device *pdev)
>>>> +{
>>>> + struct panel_drv_data *ddata;
>>>> + struct omap_dss_device *dssdev;
>>>> + int r;
>>>> +
>>>> + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
>>>> + if (ddata = NULL)
>>>> + return -ENOMEM;
>>>> +
>>>> + platform_set_drvdata(pdev, ddata);
>>>> +
>>>> + if (dev_get_platdata(&pdev->dev)) {
>>>> + r = td028ttec1_panel_probe_pdata(pdev);
>>>> + if (r)
>>>> + return r;
>>>> + } else {
>>>> + return -ENODEV;
>>>> + }
>>>> +
>>>> + if (gpio_is_valid(ddata->cs_gpio)) {
>>>> + r = devm_gpio_request_one(&pdev->dev, ddata->cs_gpio,
>>>> + GPIOF_OUT_INIT_HIGH, "lcd cs");
>>>> + if (r)
>>>> + goto err_gpio;
>>>> + }
>>>> +
>>>> + if (gpio_is_valid(ddata->scl_gpio)) {
>>>> + r = devm_gpio_request_one(&pdev->dev, ddata->scl_gpio,
>>>> + GPIOF_OUT_INIT_HIGH, "lcd scl");
>>>> + if (r)
>>>> + goto err_gpio;
>>>> + }
>>>> +
>>>> + if (gpio_is_valid(ddata->dout_gpio)) {
>>>> + r = devm_gpio_request_one(&pdev->dev, ddata->dout_gpio,
>>>> + GPIOF_OUT_INIT_LOW, "lcd dout");
>>>> + if (r)
>>>> + goto err_gpio;
>>>> + }
>>>> +
>>>> + if (gpio_is_valid(ddata->din_gpio)) {
>>>> + r = devm_gpio_request_one(&pdev->dev, ddata->din_gpio,
>>>> + GPIOF_IN, "lcd din");
>>>> + if (r)
>>>> + goto err_gpio;
>>>> + }
>>>> +
>>>> + /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
>>>> + * seems unreliable with later LCM batches, increasing to 90ms */
>>>> + mdelay(90);
>>>
>>> What is this delay for? Usually sleeps/delays should be between two "HW
>>> actions". Here there's nothing below this line that would count as such
>>> an action.
>>
>> I guess that this delay is intended to power on the display first, then wait some
>
> I'm not very comfortable with merging a driver, when the driver author
> guesses what parts of the driver do =).
Well, that is the problem with some badly documented chips. We have "inherited"
that from the Openmoko project and I think those guys did have access to some
more precise data sheets but we don't. You can't even find google results for this
strange jbt chip.
It works on all our GTA04 devices for quite a long time (using the old display API).
We just recently upgraded to display-new.
>
>> time and after that delay enable the DSS clocks and signals and make the
>> controller chip in the panel initialize.
>
> I don't see the code before the delay doing any power up, it just sets
> the data bus gpios to certain state. Do those gpio initializations power
> up the panel?
No, and they don't need to. The enable_power code is not implemented because
we have no dedicated regulator (but one shared and enabled early in the kernel).
It should be quite straightforward to add it to enable/disable if we need it.
We may want to change this in the next hardware revision, but on the other hand
do not want to postpone upstreaming until we have that, because an upstreamed
driver will help GTA04 users of today.
>
>> But this of course depends on the order the DSS components are probed
>> and enabled and how power is controlled (we don't interrupt power at all).
>>
>> I think we can move this delay (sleep) to the beginning of
>>
>> td028ttec1_panel_enable() before /* three times command zero */
>>
>> to make sure that a freshly powered display has enough time to do its
>> internal reset and initializations before registers are programmed.
>
> The probe function should not enable the panel (well, it can enable the
> panel, but only to read an ID or such and then disable it before exiting
> probe).
>
> So after probe, the panel should be as dead as possible, power disabled
> etc. All the powering up should happen in enable().
Yes, I agree. And threrefore the safety-delay should indeed be in enable().
BR, Nikolaus
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Tomi Valkeinen @ 2013-10-10 11:10 UTC (permalink / raw)
To: Dr. H. Nikolaus Schaller
Cc: Marek Belisko, plagnioj, linux-kernel, linux-omap, linux-fbdev
In-Reply-To: <7FAC77D4-5E1E-4B11-B067-3A8233C69240@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 5821 bytes --]
On 10/10/13 12:34, Dr. H. Nikolaus Schaller wrote:
> Hi Tomi,
>
> Am 10.10.2013 um 10:19 schrieb Tomi Valkeinen:
>
>> Hi,
>>
>> On 10/10/13 00:08, Marek Belisko wrote:
>>> For communicating with driver is used gpio bitbanging because TD028 does
>>> not have a standard compliant SPI interface. It is a 3-wire thing with
>>> direction reversal.
>>
>> Isn't that SPI_3WIRE?
>
> Maybe - but we have no complete datasheet and I don't know an official spec of
> a 3-wire SPI protocol to compare how 3-wire should work.
Yep, and I know only what I read on wikipedia a few hours ago =).
> And I think (but I may be wrong) that SPI_3WIRE is an optional feature of the SoC
> specific SPI drivers and in my understanding the OMAP has no such driver:
>
> http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L874
>
> And spi-bitbang.c hasn't either.
>
> So I would prefer to leave this as an area for optimizations for future work.
> Maybe we can add some more comments on this.
Ok. Well, I guess it's not too bad. But it's really not something that
should be in the panel driver (assuming it's "standard" 3-wire SPI).
Some SoC could support 3-wire SPI, and then it'd be good to use the SoCs
hardware for SPI communication. Having bitbanging hardcoded into the
driver will prevent that.
>>> + int cs_gpio;
>>> + int scl_gpio;
>>> + int din_gpio;
>>> + int dout_gpio;
>>
>> Three wires, but four gpios? What am I missing here...
>
> We have wired up the 3-wire SPI interface of the display
> to 4 wires of the McSPI interface because we initially thought
> that it could work in 4 wire mode as well.
>
> The next step we did was to port the driver code from the
> Openmoko Neo1973 U-Boot which used the gpio-bitbang
> mechanism.
>
> Since it worked and is used only for enabling/disabling the
> display and for no other purpose we never felt it important
> to check or modify the code to use SPI.
>
> But you are right - we don't use the din_gpio really since
> we never read registers from the chip. So 3 gpios could be
> sufficient.
>
> Or we must handle the case that din_gpio == dout_gpio
> in panel_probe to avoid duplicate use of the same gpio.
The panel hardware has three wires, so the panel driver (if it does
handle the bus by bitbanging) can only refer to three gpios. So either
the bus details should be hidden by using the normal spi framework, or
if the driver does the bitbanging, use the gpios as specified in the
panel spec. The panel driver cannot contain any board specific stuff.
>>> +static int jbt_spi_xfer(struct panel_drv_data *data, int wordnum, int bitlen)
>>
>> Hmm, if it's not SPI, maybe it shouldn't be called SPI?
>
> Yes, we can remove the _spi_ in this name.
Or maybe use "spi3w" or such, just to make it clear it's not plain
standard spi. Again, presuming it's really 3-wire spi =).
>>> +static int td028ttec1_panel_probe(struct platform_device *pdev)
>>> +{
>>> + struct panel_drv_data *ddata;
>>> + struct omap_dss_device *dssdev;
>>> + int r;
>>> +
>>> + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
>>> + if (ddata == NULL)
>>> + return -ENOMEM;
>>> +
>>> + platform_set_drvdata(pdev, ddata);
>>> +
>>> + if (dev_get_platdata(&pdev->dev)) {
>>> + r = td028ttec1_panel_probe_pdata(pdev);
>>> + if (r)
>>> + return r;
>>> + } else {
>>> + return -ENODEV;
>>> + }
>>> +
>>> + if (gpio_is_valid(ddata->cs_gpio)) {
>>> + r = devm_gpio_request_one(&pdev->dev, ddata->cs_gpio,
>>> + GPIOF_OUT_INIT_HIGH, "lcd cs");
>>> + if (r)
>>> + goto err_gpio;
>>> + }
>>> +
>>> + if (gpio_is_valid(ddata->scl_gpio)) {
>>> + r = devm_gpio_request_one(&pdev->dev, ddata->scl_gpio,
>>> + GPIOF_OUT_INIT_HIGH, "lcd scl");
>>> + if (r)
>>> + goto err_gpio;
>>> + }
>>> +
>>> + if (gpio_is_valid(ddata->dout_gpio)) {
>>> + r = devm_gpio_request_one(&pdev->dev, ddata->dout_gpio,
>>> + GPIOF_OUT_INIT_LOW, "lcd dout");
>>> + if (r)
>>> + goto err_gpio;
>>> + }
>>> +
>>> + if (gpio_is_valid(ddata->din_gpio)) {
>>> + r = devm_gpio_request_one(&pdev->dev, ddata->din_gpio,
>>> + GPIOF_IN, "lcd din");
>>> + if (r)
>>> + goto err_gpio;
>>> + }
>>> +
>>> + /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
>>> + * seems unreliable with later LCM batches, increasing to 90ms */
>>> + mdelay(90);
>>
>> What is this delay for? Usually sleeps/delays should be between two "HW
>> actions". Here there's nothing below this line that would count as such
>> an action.
>
> I guess that this delay is intended to power on the display first, then wait some
I'm not very comfortable with merging a driver, when the driver author
guesses what parts of the driver do =).
> time and after that delay enable the DSS clocks and signals and make the
> controller chip in the panel initialize.
I don't see the code before the delay doing any power up, it just sets
the data bus gpios to certain state. Do those gpio initializations power
up the panel?
> But this of course depends on the order the DSS components are probed
> and enabled and how power is controlled (we don't interrupt power at all).
>
> I think we can move this delay (sleep) to the beginning of
>
> td028ttec1_panel_enable() before /* three times command zero */
>
> to make sure that a freshly powered display has enough time to do its
> internal reset and initializations before registers are programmed.
The probe function should not enable the panel (well, it can enable the
panel, but only to read an ID or such and then disable it before exiting
probe).
So after probe, the panel should be as dead as possible, power disabled
etc. All the powering up should happen in enable().
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* Re: [RFC PATCH 1/4] mipi-dsi-bus: add MIPI DSI bus support
From: Andrzej Hajda @ 2013-10-10 9:57 UTC (permalink / raw)
To: Bert Kenward, Laurent Pinchart
Cc: linux-fbdev@vger.kernel.org, Kyungmin Park,
dri-devel@lists.freedesktop.org, linux-media@vger.kernel.org
In-Reply-To: <F5FE6E5E9429DA44B1C6B8A1A883D135041E001F@SJEXCHMB13.corp.ad.broadcom.com>
On 10/07/2013 12:47 PM, Bert Kenward wrote:
> On Tuesday September 24 2013 at 15:23, Andrzej Hajda wrote:
>> MIPI DSI is a high-speed serial interface to transmit
>> data from/to host to display module.
>>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>> drivers/video/display/Kconfig | 4 +
>> drivers/video/display/Makefile | 1 +
>> drivers/video/display/mipi-dsi-bus.c | 332
>> +++++++++++++++++++++++++++++++++++
>> include/video/display.h | 3 +
>> include/video/mipi-dsi-bus.h | 144 +++++++++++++++
>> 5 files changed, 484 insertions(+)
> <snipped as far as mipi-dsi-bus.h
>
>> diff --git a/include/video/mipi-dsi-bus.h b/include/video/mipi-dsi-bus.h
>> new file mode 100644
>> index 0000000..a78792d
>> --- /dev/null
>> +++ b/include/video/mipi-dsi-bus.h
>> @@ -0,0 +1,144 @@
>> +/*
>> + * MIPI DSI Bus
>> + *
>> + * Copyright (C) 2013, Samsung Electronics, Co., Ltd.
>> + * Andrzej Hajda <a.hajda@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef __MIPI_DSI_BUS_H__
>> +#define __MIPI_DSI_BUS_H__
>> +
>> +#include <linux/device.h>
>> +#include <video/videomode.h>
>> +
>> +struct mipi_dsi_bus;
>> +struct mipi_dsi_device;
>> +
>> +struct mipi_dsi_bus_ops {
>> + int (*set_power)(struct mipi_dsi_bus *bus, struct mipi_dsi_device
>> *dev,
>> + bool on);
>> + int (*set_stream)(struct mipi_dsi_bus *bus, struct mipi_dsi_device
>> *dev,
>> + bool on);
>> + int (*transfer)(struct mipi_dsi_bus *bus, struct mipi_dsi_device
>> *dev,
>> + u8 type, const u8 *tx_buf, size_t tx_len, u8 *rx_buf,
>> + size_t rx_len);
>> +};
>> +
>> +#define DSI_MODE_VIDEO (1 << 0)
>> +#define DSI_MODE_VIDEO_BURST (1 << 1)
>> +#define DSI_MODE_VIDEO_SYNC_PULSE (1 << 2)
>> +#define DSI_MODE_VIDEO_AUTO_VERT (1 << 3)
>> +#define DSI_MODE_VIDEO_HSE (1 << 4)
>> +#define DSI_MODE_VIDEO_HFP (1 << 5)
>> +#define DSI_MODE_VIDEO_HBP (1 << 6)
>> +#define DSI_MODE_VIDEO_HSA (1 << 7)
>> +#define DSI_MODE_VSYNC_FLUSH (1 << 8)
>> +#define DSI_MODE_EOT_PACKET (1 << 9)
>> +
>> +enum mipi_dsi_pixel_format {
>> + DSI_FMT_RGB888,
>> + DSI_FMT_RGB666,
>> + DSI_FMT_RGB666_PACKED,
>> + DSI_FMT_RGB565,
>> +};
>> +
>> +struct mipi_dsi_interface_params {
>> + enum mipi_dsi_pixel_format format;
>> + unsigned long mode;
>> + unsigned long hs_clk_freq;
>> + unsigned long esc_clk_freq;
>> + unsigned char data_lanes;
>> + unsigned char cmd_allow;
>> +};
>> +
>> +struct mipi_dsi_bus {
>> + struct device *dev;
>> + const struct mipi_dsi_bus_ops *ops;
>> +};
>> +
>> +#define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
>> +#define MIPI_DSI_NAME_SIZE 32
>> +
>> +struct mipi_dsi_device_id {
>> + char name[MIPI_DSI_NAME_SIZE];
>> + __kernel_ulong_t driver_data /* Data private to the driver */
>> + __aligned(sizeof(__kernel_ulong_t));
>> +};
>> +
>> +struct mipi_dsi_device {
>> + char name[MIPI_DSI_NAME_SIZE];
>> + int id;
>> + struct device dev;
>> +
>> + const struct mipi_dsi_device_id *id_entry;
>> + struct mipi_dsi_bus *bus;
>> + struct videomode vm;
>> + struct mipi_dsi_interface_params params;
>> +};
>> +
>> +#define to_mipi_dsi_device(d) container_of(d, struct
>> mipi_dsi_device, dev)
>> +
>> +int mipi_dsi_device_register(struct mipi_dsi_device *dev,
>> + struct mipi_dsi_bus *bus);
>> +void mipi_dsi_device_unregister(struct mipi_dsi_device *dev);
>> +
>> +struct mipi_dsi_driver {
>> + int(*probe)(struct mipi_dsi_device *);
>> + int(*remove)(struct mipi_dsi_device *);
>> + struct device_driver driver;
>> + const struct mipi_dsi_device_id *id_table;
>> +};
>> +
>> +#define to_mipi_dsi_driver(d) container_of(d, struct
>> mipi_dsi_driver, driver)
>> +
>> +int mipi_dsi_driver_register(struct mipi_dsi_driver *drv);
>> +void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv);
>> +
>> +static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device
>> *dev)
>> +{
>> + return dev_get_drvdata(&dev->dev);
>> +}
>> +
>> +static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dev,
>> + void *data)
>> +{
>> + dev_set_drvdata(&dev->dev, data);
>> +}
>> +
>> +int of_mipi_dsi_register_devices(struct mipi_dsi_bus *bus);
>> +void mipi_dsi_unregister_devices(struct mipi_dsi_bus *bus);
>> +
>> +/* module_mipi_dsi_driver() - Helper macro for drivers that don't do
>> + * anything special in module init/exit. This eliminates a lot of
>> + * boilerplate. Each module may only use this macro once, and
>> + * calling it replaces module_init() and module_exit()
>> + */
>> +#define module_mipi_dsi_driver(__mipi_dsi_driver) \
>> + module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
>> + mipi_dsi_driver_unregister)
>> +
>> +int mipi_dsi_set_power(struct mipi_dsi_device *dev, bool on);
>> +int mipi_dsi_set_stream(struct mipi_dsi_device *dev, bool on);
>> +int mipi_dsi_dcs_write(struct mipi_dsi_device *dev, int channel, const u8
>> *data,
>> + size_t len);
>> +int mipi_dsi_dcs_read(struct mipi_dsi_device *dev, int channel, u8 cmd,
>> + u8 *data, size_t len);
>> +
>> +#define mipi_dsi_dcs_write_seq(dev, channel, seq...) \
>> +({\
>> + const u8 d[] = { seq };\
>> + BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too long for
>> stack");\
>> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\
>> +})
>> +
>> +#define mipi_dsi_dcs_write_static_seq(dev, channel, seq...) \
>> +({\
>> + static const u8 d[] = { seq };\
>> + mipi_dsi_dcs_write(dev, channel, d, ARRAY_SIZE(d));\
>> +})
>> +
>> +#endif /* __MIPI_DSI_BUS__ */
> I may well have missed something,
> but I can't see exactly how a command mode
> update would be done with this interface. Would this require repeated calls to
> .transfer? Such transfers would need to be flagged as requiring
> synchronisation with a tearing effect control signal - either the inband
> method or a dedicated line. I suspect many hardware implementations will have
> a specific method for transferring pixel data in a DSI command mode transfer.
>
> The command sending period during video mode should probably be configurable
> on a per-transfer basis. Some commands have to be synchronised with vertical
> blanking, others do not. This could perhaps be combined with a wider
> configuration option for a given panel or interface. Similarly, selection of
> low power (LP) and high speed (HS) mode on a per-transfer basis can be needed
> for some panels.
>
> Is there a mechanism for controlling ultra-low power state (ULPS) entry? Also,
> is there a method for sending arbitrary trigger messages (eg the reset
> trigger)?
Thanks for the feedback.
The current dsi bus implementation was just made to work with the
hw I have. It should be extended to be more generic, but I hope
now it is just matter of adding good opses and parameters.
Feel free to propose new opses.
Andrzej
>
> Thanks,
>
> Bert.
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Dr. H. Nikolaus Schaller @ 2013-10-10 9:34 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Marek Belisko, plagnioj, linux-kernel, linux-omap, linux-fbdev
In-Reply-To: <525662F5.3090600@ti.com>
Hi Tomi,
Am 10.10.2013 um 10:19 schrieb Tomi Valkeinen:
> Hi,
>
> On 10/10/13 00:08, Marek Belisko wrote:
>> For communicating with driver is used gpio bitbanging because TD028 does
>> not have a standard compliant SPI interface. It is a 3-wire thing with
>> direction reversal.
>
> Isn't that SPI_3WIRE?
Maybe - but we have no complete datasheet and I don't know an official spec of
a 3-wire SPI protocol to compare how 3-wire should work.
And I think (but I may be wrong) that SPI_3WIRE is an optional feature of the SoC
specific SPI drivers and in my understanding the OMAP has no such driver:
http://lxr.free-electrons.com/source/drivers/spi/spi-omap2-mcspi.c#L874
And spi-bitbang.c hasn't either.
So I would prefer to leave this as an area for optimizations for future work.
Maybe we can add some more comments on this.
>
>> Communication with display is used only during panel enable/disable so it's
>> not performance issue.
>>
>> Signed-off-by: Marek Belisko <marek@goldelico.com>
>> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
>> ---
>> drivers/video/omap2/displays-new/Kconfig | 6 +
>> drivers/video/omap2/displays-new/Makefile | 1 +
>> .../omap2/displays-new/panel-tpo-td028ttec1.c | 537 +++++++++++++++++++++
>> include/video/omap-panel-data.h | 22 +
>> 4 files changed, 566 insertions(+)
>> create mode 100644 drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
>>
>> diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
>> index 6c90885..3f86432 100644
>> --- a/drivers/video/omap2/displays-new/Kconfig
>> +++ b/drivers/video/omap2/displays-new/Kconfig
>> @@ -56,6 +56,11 @@ config DISPLAY_PANEL_SHARP_LS037V7DW01
>> help
>> LCD Panel used in TI's SDP3430 and EVM boards
>>
>> +config DISPLAY_PANEL_TPO_TD028TTEC1
>> + tristate "TPO TD028TTEC1 LCD Panel"
>> + help
>> + LCD panel used by Openmoko.
>> +
>> config DISPLAY_PANEL_TPO_TD043MTEA1
>> tristate "TPO TD043MTEA1 LCD Panel"
>> depends on SPI
>> @@ -70,4 +75,5 @@ config DISPLAY_PANEL_NEC_NL8048HL11
>> This NEC NL8048HL11 panel is TFT LCD used in the
>> Zoom2/3/3630 sdp boards.
>>
>> +
>
> Extra change.
>
>> endmenu
>> diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
>> index 5aeb11b..0323a8a 100644
>> --- a/drivers/video/omap2/displays-new/Makefile
>> +++ b/drivers/video/omap2/displays-new/Makefile
>> @@ -8,5 +8,6 @@ obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
>> obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
>> obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
>> obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
>> +obj-$(CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
>> obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
>> obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
>> diff --git a/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
>> new file mode 100644
>> index 0000000..b63586e
>> --- /dev/null
>> +++ b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
>> @@ -0,0 +1,537 @@
>> +/*
>> + * Toppoly TD028TTEC1 panel support
>> + *
>> + * Copyright (C) 2008 Nokia Corporation
>> + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
>> + *
>> + * Neo 1973 code (jbt6k74.c):
>> + * Copyright (C) 2006-2007 by OpenMoko, Inc.
>> + * Author: Harald Welte <laforge@openmoko.org>
>> + *
>> + * Ported and adapted from Neo 1973 U-Boot by:
>> + * H. Nikolaus Schaller <hns@goldelico.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.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/delay.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/gpio.h>
>> +#include <video/omapdss.h>
>> +#include <video/omap-panel-data.h>
>> +
>> +struct panel_drv_data {
>> + struct omap_dss_device dssdev;
>> + struct omap_dss_device *in;
>> +
>> + int data_lines;
>> +
>> + struct omap_video_timings videomode;
>> +
>> + int cs_gpio;
>> + int scl_gpio;
>> + int din_gpio;
>> + int dout_gpio;
>
> Three wires, but four gpios? What am I missing here...
We have wired up the 3-wire SPI interface of the display
to 4 wires of the McSPI interface because we initially thought
that it could work in 4 wire mode as well.
The next step we did was to port the driver code from the
Openmoko Neo1973 U-Boot which used the gpio-bitbang
mechanism.
Since it worked and is used only for enabling/disabling the
display and for no other purpose we never felt it important
to check or modify the code to use SPI.
But you are right - we don't use the din_gpio really since
we never read registers from the chip. So 3 gpios could be
sufficient.
Or we must handle the case that din_gpio = dout_gpio
in panel_probe to avoid duplicate use of the same gpio.
>
>> + u_int16_t tx_buf[4];
>
> Hmm, what's wrong with "u16"?
Nothing. Maybe a relict from taking years old u-boot code and not
recognising because the compiler did not complain...
>
>> +};
>> +
>> +static struct omap_video_timings td028ttec1_panel_timings = {
>> + .x_res = 480,
>> + .y_res = 640,
>> + .pixel_clock = 22153,
>> + .hfp = 24,
>> + .hsw = 8,
>> + .hbp = 8,
>> + .vfp = 4,
>> + .vsw = 2,
>> + .vbp = 2,
>> +
>> + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
>> + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
>> +
>> + .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
>> + .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
>> + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
>> +};
>> +
>> +#define JBT_COMMAND 0x000
>> +#define JBT_DATA 0x100
>> +
>> +/* 150uS minimum clock cycle, we have two of this plus our other
>> + * instructions */
>> +
>> +#define SPI_DELAY() udelay(200)
>
> Would usleep_range work here?
Yes, I think that works as well.
The 150uS is a minimum and I think it would also work
much slower.
>
> See Documentation/timers/timers-howto.txt
>
>> +static int jbt_spi_xfer(struct panel_drv_data *data, int wordnum, int bitlen)
>
> Hmm, if it's not SPI, maybe it shouldn't be called SPI?
Yes, we can remove the _spi_ in this name.
>
>> +{
>> + u_int16_t tmpdout = 0;
>> + int i, j;
>> +
>> + gpio_set_value(data->cs_gpio, 0);
>> +
>> + for (i = 0; i < wordnum; i++) {
>> + tmpdout = data->tx_buf[i];
>> +
>> + for (j = 0; j < bitlen; j++) {
>> + gpio_set_value(data->scl_gpio, 0);
>> + if (tmpdout & (1 << (bitlen-1))) {
>> + gpio_set_value(data->dout_gpio, 1);
>> + if (gpio_get_value(data->din_gpio) = 0)
>> + return 1;
>> + } else {
>> + gpio_set_value(data->dout_gpio, 0);
>> + if (gpio_get_value(data->din_gpio) != 0)
>> + return 1;
>> + }
>> + SPI_DELAY();
>> + gpio_set_value(data->scl_gpio, 1);
>> + SPI_DELAY();
>> + tmpdout <<= 1;
>> + }
>> + }
>> +
>> + gpio_set_value(data->cs_gpio, 1);
>> +
>> + return 0;
>> +}
>> +
>> +#define JBT_COMMAND 0x000
>> +#define JBT_DATA 0x100
>> +
>> +int jbt_reg_write_nodata(struct panel_drv_data *ddata, u_int8_t reg)
>
> What's wrong with "u8"? Have I missed a memo? =)
>
>> +{
>> + int rc;
>> +
>> + ddata->tx_buf[0] = JBT_COMMAND | reg;
>> +
>> + rc = jbt_spi_xfer(ddata, 1, 9);
>> + if (rc)
>> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
>> +
>> + return rc;
>> +}
>> +
>> +int jbt_reg_write(struct panel_drv_data *ddata, u_int8_t reg, u_int8_t data)
>> +{
>> + int rc;
>> +
>> + ddata->tx_buf[0] = JBT_COMMAND | reg;
>> + ddata->tx_buf[1] = JBT_DATA | data;
>> +
>> + rc = jbt_spi_xfer(ddata, 2, 9);
>> + if (rc)
>> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
>> +
>> + return rc;
>> +}
>> +
>> +int jbt_reg_write16(struct panel_drv_data *ddata, u_int8_t reg, u_int16_t data)
>> +{
>> + int rc;
>> +
>> + ddata->tx_buf[0] = JBT_COMMAND | reg;
>> + ddata->tx_buf[1] = JBT_DATA | (data >> 8);
>> + ddata->tx_buf[2] = JBT_DATA | (data & 0xff);
>> +
>> + rc = jbt_spi_xfer(ddata, 3, 9);
>> + if (rc)
>> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
>> +
>> + return rc;
>> +}
>> +
>> +enum jbt_register {
>> + JBT_REG_SLEEP_IN = 0x10,
>> + JBT_REG_SLEEP_OUT = 0x11,
>> +
>> + JBT_REG_DISPLAY_OFF = 0x28,
>> + JBT_REG_DISPLAY_ON = 0x29,
>> +
>> + JBT_REG_RGB_FORMAT = 0x3a,
>> + JBT_REG_QUAD_RATE = 0x3b,
>> +
>> + JBT_REG_POWER_ON_OFF = 0xb0,
>> + JBT_REG_BOOSTER_OP = 0xb1,
>> + JBT_REG_BOOSTER_MODE = 0xb2,
>> + JBT_REG_BOOSTER_FREQ = 0xb3,
>> + JBT_REG_OPAMP_SYSCLK = 0xb4,
>> + JBT_REG_VSC_VOLTAGE = 0xb5,
>> + JBT_REG_VCOM_VOLTAGE = 0xb6,
>> + JBT_REG_EXT_DISPL = 0xb7,
>> + JBT_REG_OUTPUT_CONTROL = 0xb8,
>> + JBT_REG_DCCLK_DCEV = 0xb9,
>> + JBT_REG_DISPLAY_MODE1 = 0xba,
>> + JBT_REG_DISPLAY_MODE2 = 0xbb,
>> + JBT_REG_DISPLAY_MODE = 0xbc,
>> + JBT_REG_ASW_SLEW = 0xbd,
>> + JBT_REG_DUMMY_DISPLAY = 0xbe,
>> + JBT_REG_DRIVE_SYSTEM = 0xbf,
>> +
>> + JBT_REG_SLEEP_OUT_FR_A = 0xc0,
>> + JBT_REG_SLEEP_OUT_FR_B = 0xc1,
>> + JBT_REG_SLEEP_OUT_FR_C = 0xc2,
>> + JBT_REG_SLEEP_IN_LCCNT_D = 0xc3,
>> + JBT_REG_SLEEP_IN_LCCNT_E = 0xc4,
>> + JBT_REG_SLEEP_IN_LCCNT_F = 0xc5,
>> + JBT_REG_SLEEP_IN_LCCNT_G = 0xc6,
>> +
>> + JBT_REG_GAMMA1_FINE_1 = 0xc7,
>> + JBT_REG_GAMMA1_FINE_2 = 0xc8,
>> + JBT_REG_GAMMA1_INCLINATION = 0xc9,
>> + JBT_REG_GAMMA1_BLUE_OFFSET = 0xca,
>> +
>> + JBT_REG_BLANK_CONTROL = 0xcf,
>> + JBT_REG_BLANK_TH_TV = 0xd0,
>> + JBT_REG_CKV_ON_OFF = 0xd1,
>> + JBT_REG_CKV_1_2 = 0xd2,
>> + JBT_REG_OEV_TIMING = 0xd3,
>> + JBT_REG_ASW_TIMING_1 = 0xd4,
>> + JBT_REG_ASW_TIMING_2 = 0xd5,
>> +
>> + JBT_REG_HCLOCK_VGA = 0xec,
>> + JBT_REG_HCLOCK_QVGA = 0xed,
>> +};
>> +
>> +#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
>> +
>> +static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> + int r;
>> +
>> + if (omapdss_device_is_connected(dssdev))
>> + return 0;
>> +
>> + r = in->ops.dpi->connect(in, dssdev);
>> + if (r)
>> + return r;
>> +
>> + return 0;
>> +}
>> +
>> +static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> +
>> + if (!omapdss_device_is_connected(dssdev))
>> + return;
>> +
>> + in->ops.dpi->disconnect(in, dssdev);
>> +}
>> +
>> +static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> + int r;
>> +
>> + if (!omapdss_device_is_connected(dssdev))
>> + return -ENODEV;
>> +
>> + if (omapdss_device_is_enabled(dssdev))
>> + return 0;
>> +
>> + in->ops.dpi->set_data_lines(in, ddata->data_lines);
>> + in->ops.dpi->set_timings(in, &ddata->videomode);
>> +
>> + r = in->ops.dpi->enable(in);
>> + if (r)
>> + return r;
>> +
>> + dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
>> + dssdev->state);
>> +
>> + /* three times command zero */
>> + r |= jbt_reg_write_nodata(ddata, 0x00);
>> + udelay(1000);
>
> These are big delays, and I guess the timing is not strict here, so
> maybe some sleep variant would be better.
Yes, good hint! We will look at it. And add some locks so that enabling
and disabling can't interfere.
>
>> + r |= jbt_reg_write_nodata(ddata, 0x00);
>> + udelay(1000);
>> + r |= jbt_reg_write_nodata(ddata, 0x00);
>> + udelay(1000);
>> +
>> + /* deep standby out */
>> + r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x17);
>> +
>> + /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
>> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE, 0x80);
>> +
>> + /* Quad mode off */
>> + r |= jbt_reg_write(ddata, JBT_REG_QUAD_RATE, 0x00);
>> +
>> + /* AVDD on, XVDD on */
>> + r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x16);
>> +
>> + /* Output control */
>> + r |= jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
>> +
>> + /* Sleep mode off */
>> + r |= jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_OUT);
>> +
>> + /* at this point we have like 50% grey */
>> +
>> + /* initialize register set */
>> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
>> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
>> + r |= jbt_reg_write(ddata, JBT_REG_RGB_FORMAT, 0x60);
>> + r |= jbt_reg_write(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
>> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_OP, 0x56);
>> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_MODE, 0x33);
>> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
>> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
>> + r |= jbt_reg_write(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
>> + r |= jbt_reg_write(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
>> + r |= jbt_reg_write(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
>> + r |= jbt_reg_write(ddata, JBT_REG_EXT_DISPL, 0x03);
>> + r |= jbt_reg_write(ddata, JBT_REG_DCCLK_DCEV, 0x04);
>> + /*
>> + * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
>> + * to avoid red / blue flicker
>> + */
>> + r |= jbt_reg_write(ddata, JBT_REG_ASW_SLEW, 0x04);
>> + r |= jbt_reg_write(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
>> +
>> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
>> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
>> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
>> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
>> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
>> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
>> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
>> +
>> + r |= jbt_reg_write16(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
>> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
>> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
>> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
>> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
>> +
>> + r |= jbt_reg_write16(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
>> + r |= jbt_reg_write(ddata, JBT_REG_BLANK_CONTROL, 0x02);
>> + r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
>> + r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
>> +
>> + r |= jbt_reg_write(ddata, JBT_REG_CKV_ON_OFF, 0x01);
>> + r |= jbt_reg_write16(ddata, JBT_REG_CKV_1_2, 0x0000);
>> +
>> + r |= jbt_reg_write16(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
>> + r |= jbt_reg_write16(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
>> + r |= jbt_reg_write(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
>> +
>> + r |= jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_ON);
>> +
>> + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
>> +
>> + return r;
>> +}
>> +
>> +static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> +
>> + if (!omapdss_device_is_enabled(dssdev))
>> + return;
>> +
>> + dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
>> +
>> + in->ops.dpi->disable(in);
>> +
>> + jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_OFF);
>> + jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
>> + jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_IN);
>> + jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x00);
>> +
>> + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
>> +}
>> +
>> +static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
>> + struct omap_video_timings *timings)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> +
>> + ddata->videomode = *timings;
>> + dssdev->panel.timings = *timings;
>> +
>> + in->ops.dpi->set_timings(in, timings);
>> +}
>> +
>> +static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
>> + struct omap_video_timings *timings)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> +
>> + *timings = ddata->videomode;
>> +}
>> +
>> +static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
>> + struct omap_video_timings *timings)
>> +{
>> + struct panel_drv_data *ddata = to_panel_data(dssdev);
>> + struct omap_dss_device *in = ddata->in;
>> +
>> + return in->ops.dpi->check_timings(in, timings);
>> +}
>> +
>> +static struct omap_dss_driver td028ttec1_ops = {
>> + .connect = td028ttec1_panel_connect,
>> + .disconnect = td028ttec1_panel_disconnect,
>> +
>> + .enable = td028ttec1_panel_enable,
>> + .disable = td028ttec1_panel_disable,
>> +
>> + .set_timings = td028ttec1_panel_set_timings,
>> + .get_timings = td028ttec1_panel_get_timings,
>> + .check_timings = td028ttec1_panel_check_timings,
>> +};
>> +
>> +static int td028ttec1_panel_probe_pdata(struct platform_device *pdev)
>> +{
>> + const struct panel_tpo_td028tec1_platform_data *pdata;
>> + struct panel_drv_data *ddata = platform_get_drvdata(pdev);
>> + struct omap_dss_device *dssdev, *in;
>> +
>> + pdata = dev_get_platdata(&pdev->dev);
>> +
>> + in = omap_dss_find_output(pdata->source);
>> + if (in = NULL) {
>> + dev_err(&pdev->dev, "failed to find video source '%s'\n",
>> + pdata->source);
>> + return -EPROBE_DEFER;
>> + }
>> +
>> + ddata->in = in;
>> +
>> + ddata->data_lines = pdata->data_lines;
>> +
>> + dssdev = &ddata->dssdev;
>> + dssdev->name = pdata->name;
>> +
>> + ddata->cs_gpio = pdata->cs_gpio;
>> + ddata->scl_gpio = pdata->scl_gpio;
>> + ddata->din_gpio = pdata->din_gpio;
>> + ddata->dout_gpio = pdata->dout_gpio;
>> +
>> + return 0;
>> +}
>> +
>> +static int td028ttec1_panel_probe(struct platform_device *pdev)
>> +{
>> + struct panel_drv_data *ddata;
>> + struct omap_dss_device *dssdev;
>> + int r;
>> +
>> + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
>> + if (ddata = NULL)
>> + return -ENOMEM;
>> +
>> + platform_set_drvdata(pdev, ddata);
>> +
>> + if (dev_get_platdata(&pdev->dev)) {
>> + r = td028ttec1_panel_probe_pdata(pdev);
>> + if (r)
>> + return r;
>> + } else {
>> + return -ENODEV;
>> + }
>> +
>> + if (gpio_is_valid(ddata->cs_gpio)) {
>> + r = devm_gpio_request_one(&pdev->dev, ddata->cs_gpio,
>> + GPIOF_OUT_INIT_HIGH, "lcd cs");
>> + if (r)
>> + goto err_gpio;
>> + }
>> +
>> + if (gpio_is_valid(ddata->scl_gpio)) {
>> + r = devm_gpio_request_one(&pdev->dev, ddata->scl_gpio,
>> + GPIOF_OUT_INIT_HIGH, "lcd scl");
>> + if (r)
>> + goto err_gpio;
>> + }
>> +
>> + if (gpio_is_valid(ddata->dout_gpio)) {
>> + r = devm_gpio_request_one(&pdev->dev, ddata->dout_gpio,
>> + GPIOF_OUT_INIT_LOW, "lcd dout");
>> + if (r)
>> + goto err_gpio;
>> + }
>> +
>> + if (gpio_is_valid(ddata->din_gpio)) {
>> + r = devm_gpio_request_one(&pdev->dev, ddata->din_gpio,
>> + GPIOF_IN, "lcd din");
>> + if (r)
>> + goto err_gpio;
>> + }
>> +
>> + /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
>> + * seems unreliable with later LCM batches, increasing to 90ms */
>> + mdelay(90);
>
> What is this delay for? Usually sleeps/delays should be between two "HW
> actions". Here there's nothing below this line that would count as such
> an action.
I guess that this delay is intended to power on the display first, then wait some
time and after that delay enable the DSS clocks and signals and make the
controller chip in the panel initialize.
But this of course depends on the order the DSS components are probed
and enabled and how power is controlled (we don't interrupt power at all).
I think we can move this delay (sleep) to the beginning of
td028ttec1_panel_enable() before /* three times command zero */
to make sure that a freshly powered display has enough time to do its
internal reset and initializations before registers are programmed.
>
>> + ddata->videomode = td028ttec1_panel_timings;
>> +
>> + dssdev = &ddata->dssdev;
>> + dssdev->dev = &pdev->dev;
>> + dssdev->driver = &td028ttec1_ops;
>> + dssdev->type = OMAP_DISPLAY_TYPE_DPI;
>> + dssdev->owner = THIS_MODULE;
>> + dssdev->panel.timings = ddata->videomode;
>> + dssdev->phy.dpi.data_lines = ddata->data_lines;
>> +
>> + r = omapdss_register_display(dssdev);
>> + if (r) {
>> + dev_err(&pdev->dev, "Failed to register panel\n");
>> + goto err_reg;
>> + }
>> +
>> + return 0;
>> +
>> +err_reg:
>> +err_gpio:
>> + omap_dss_put_device(ddata->in);
>> + return r;
>> +}
>> +
>
> Tomi
BR,
Nikolaus
^ permalink raw reply
* Re: [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Tomi Valkeinen @ 2013-10-10 8:19 UTC (permalink / raw)
To: Marek Belisko
Cc: plagnioj, linux-kernel, linux-omap, linux-fbdev,
H. Nikolaus Schaller
In-Reply-To: <1381352915-17219-1-git-send-email-marek@goldelico.com>
[-- Attachment #1: Type: text/plain, Size: 18597 bytes --]
Hi,
On 10/10/13 00:08, Marek Belisko wrote:
> For communicating with driver is used gpio bitbanging because TD028 does
> not have a standard compliant SPI interface. It is a 3-wire thing with
> direction reversal.
Isn't that SPI_3WIRE?
> Communication with display is used only during panel enable/disable so it's
> not performance issue.
>
> Signed-off-by: Marek Belisko <marek@goldelico.com>
> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
> ---
> drivers/video/omap2/displays-new/Kconfig | 6 +
> drivers/video/omap2/displays-new/Makefile | 1 +
> .../omap2/displays-new/panel-tpo-td028ttec1.c | 537 +++++++++++++++++++++
> include/video/omap-panel-data.h | 22 +
> 4 files changed, 566 insertions(+)
> create mode 100644 drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
>
> diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
> index 6c90885..3f86432 100644
> --- a/drivers/video/omap2/displays-new/Kconfig
> +++ b/drivers/video/omap2/displays-new/Kconfig
> @@ -56,6 +56,11 @@ config DISPLAY_PANEL_SHARP_LS037V7DW01
> help
> LCD Panel used in TI's SDP3430 and EVM boards
>
> +config DISPLAY_PANEL_TPO_TD028TTEC1
> + tristate "TPO TD028TTEC1 LCD Panel"
> + help
> + LCD panel used by Openmoko.
> +
> config DISPLAY_PANEL_TPO_TD043MTEA1
> tristate "TPO TD043MTEA1 LCD Panel"
> depends on SPI
> @@ -70,4 +75,5 @@ config DISPLAY_PANEL_NEC_NL8048HL11
> This NEC NL8048HL11 panel is TFT LCD used in the
> Zoom2/3/3630 sdp boards.
>
> +
Extra change.
> endmenu
> diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
> index 5aeb11b..0323a8a 100644
> --- a/drivers/video/omap2/displays-new/Makefile
> +++ b/drivers/video/omap2/displays-new/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
> obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
> obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
> obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
> +obj-$(CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
> obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
> obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
> diff --git a/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
> new file mode 100644
> index 0000000..b63586e
> --- /dev/null
> +++ b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
> @@ -0,0 +1,537 @@
> +/*
> + * Toppoly TD028TTEC1 panel support
> + *
> + * Copyright (C) 2008 Nokia Corporation
> + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
> + *
> + * Neo 1973 code (jbt6k74.c):
> + * Copyright (C) 2006-2007 by OpenMoko, Inc.
> + * Author: Harald Welte <laforge@openmoko.org>
> + *
> + * Ported and adapted from Neo 1973 U-Boot by:
> + * H. Nikolaus Schaller <hns@goldelico.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.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/gpio.h>
> +#include <video/omapdss.h>
> +#include <video/omap-panel-data.h>
> +
> +struct panel_drv_data {
> + struct omap_dss_device dssdev;
> + struct omap_dss_device *in;
> +
> + int data_lines;
> +
> + struct omap_video_timings videomode;
> +
> + int cs_gpio;
> + int scl_gpio;
> + int din_gpio;
> + int dout_gpio;
Three wires, but four gpios? What am I missing here...
> + u_int16_t tx_buf[4];
Hmm, what's wrong with "u16"?
> +};
> +
> +static struct omap_video_timings td028ttec1_panel_timings = {
> + .x_res = 480,
> + .y_res = 640,
> + .pixel_clock = 22153,
> + .hfp = 24,
> + .hsw = 8,
> + .hbp = 8,
> + .vfp = 4,
> + .vsw = 2,
> + .vbp = 2,
> +
> + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
> + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
> +
> + .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
> + .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
> + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
> +};
> +
> +#define JBT_COMMAND 0x000
> +#define JBT_DATA 0x100
> +
> +/* 150uS minimum clock cycle, we have two of this plus our other
> + * instructions */
> +
> +#define SPI_DELAY() udelay(200)
Would usleep_range work here?
See Documentation/timers/timers-howto.txt
> +static int jbt_spi_xfer(struct panel_drv_data *data, int wordnum, int bitlen)
Hmm, if it's not SPI, maybe it shouldn't be called SPI?
> +{
> + u_int16_t tmpdout = 0;
> + int i, j;
> +
> + gpio_set_value(data->cs_gpio, 0);
> +
> + for (i = 0; i < wordnum; i++) {
> + tmpdout = data->tx_buf[i];
> +
> + for (j = 0; j < bitlen; j++) {
> + gpio_set_value(data->scl_gpio, 0);
> + if (tmpdout & (1 << (bitlen-1))) {
> + gpio_set_value(data->dout_gpio, 1);
> + if (gpio_get_value(data->din_gpio) == 0)
> + return 1;
> + } else {
> + gpio_set_value(data->dout_gpio, 0);
> + if (gpio_get_value(data->din_gpio) != 0)
> + return 1;
> + }
> + SPI_DELAY();
> + gpio_set_value(data->scl_gpio, 1);
> + SPI_DELAY();
> + tmpdout <<= 1;
> + }
> + }
> +
> + gpio_set_value(data->cs_gpio, 1);
> +
> + return 0;
> +}
> +
> +#define JBT_COMMAND 0x000
> +#define JBT_DATA 0x100
> +
> +int jbt_reg_write_nodata(struct panel_drv_data *ddata, u_int8_t reg)
What's wrong with "u8"? Have I missed a memo? =)
> +{
> + int rc;
> +
> + ddata->tx_buf[0] = JBT_COMMAND | reg;
> +
> + rc = jbt_spi_xfer(ddata, 1, 9);
> + if (rc)
> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
> +
> + return rc;
> +}
> +
> +int jbt_reg_write(struct panel_drv_data *ddata, u_int8_t reg, u_int8_t data)
> +{
> + int rc;
> +
> + ddata->tx_buf[0] = JBT_COMMAND | reg;
> + ddata->tx_buf[1] = JBT_DATA | data;
> +
> + rc = jbt_spi_xfer(ddata, 2, 9);
> + if (rc)
> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
> +
> + return rc;
> +}
> +
> +int jbt_reg_write16(struct panel_drv_data *ddata, u_int8_t reg, u_int16_t data)
> +{
> + int rc;
> +
> + ddata->tx_buf[0] = JBT_COMMAND | reg;
> + ddata->tx_buf[1] = JBT_DATA | (data >> 8);
> + ddata->tx_buf[2] = JBT_DATA | (data & 0xff);
> +
> + rc = jbt_spi_xfer(ddata, 3, 9);
> + if (rc)
> + dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
> +
> + return rc;
> +}
> +
> +enum jbt_register {
> + JBT_REG_SLEEP_IN = 0x10,
> + JBT_REG_SLEEP_OUT = 0x11,
> +
> + JBT_REG_DISPLAY_OFF = 0x28,
> + JBT_REG_DISPLAY_ON = 0x29,
> +
> + JBT_REG_RGB_FORMAT = 0x3a,
> + JBT_REG_QUAD_RATE = 0x3b,
> +
> + JBT_REG_POWER_ON_OFF = 0xb0,
> + JBT_REG_BOOSTER_OP = 0xb1,
> + JBT_REG_BOOSTER_MODE = 0xb2,
> + JBT_REG_BOOSTER_FREQ = 0xb3,
> + JBT_REG_OPAMP_SYSCLK = 0xb4,
> + JBT_REG_VSC_VOLTAGE = 0xb5,
> + JBT_REG_VCOM_VOLTAGE = 0xb6,
> + JBT_REG_EXT_DISPL = 0xb7,
> + JBT_REG_OUTPUT_CONTROL = 0xb8,
> + JBT_REG_DCCLK_DCEV = 0xb9,
> + JBT_REG_DISPLAY_MODE1 = 0xba,
> + JBT_REG_DISPLAY_MODE2 = 0xbb,
> + JBT_REG_DISPLAY_MODE = 0xbc,
> + JBT_REG_ASW_SLEW = 0xbd,
> + JBT_REG_DUMMY_DISPLAY = 0xbe,
> + JBT_REG_DRIVE_SYSTEM = 0xbf,
> +
> + JBT_REG_SLEEP_OUT_FR_A = 0xc0,
> + JBT_REG_SLEEP_OUT_FR_B = 0xc1,
> + JBT_REG_SLEEP_OUT_FR_C = 0xc2,
> + JBT_REG_SLEEP_IN_LCCNT_D = 0xc3,
> + JBT_REG_SLEEP_IN_LCCNT_E = 0xc4,
> + JBT_REG_SLEEP_IN_LCCNT_F = 0xc5,
> + JBT_REG_SLEEP_IN_LCCNT_G = 0xc6,
> +
> + JBT_REG_GAMMA1_FINE_1 = 0xc7,
> + JBT_REG_GAMMA1_FINE_2 = 0xc8,
> + JBT_REG_GAMMA1_INCLINATION = 0xc9,
> + JBT_REG_GAMMA1_BLUE_OFFSET = 0xca,
> +
> + JBT_REG_BLANK_CONTROL = 0xcf,
> + JBT_REG_BLANK_TH_TV = 0xd0,
> + JBT_REG_CKV_ON_OFF = 0xd1,
> + JBT_REG_CKV_1_2 = 0xd2,
> + JBT_REG_OEV_TIMING = 0xd3,
> + JBT_REG_ASW_TIMING_1 = 0xd4,
> + JBT_REG_ASW_TIMING_2 = 0xd5,
> +
> + JBT_REG_HCLOCK_VGA = 0xec,
> + JBT_REG_HCLOCK_QVGA = 0xed,
> +};
> +
> +#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
> +
> +static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> + int r;
> +
> + if (omapdss_device_is_connected(dssdev))
> + return 0;
> +
> + r = in->ops.dpi->connect(in, dssdev);
> + if (r)
> + return r;
> +
> + return 0;
> +}
> +
> +static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> +
> + if (!omapdss_device_is_connected(dssdev))
> + return;
> +
> + in->ops.dpi->disconnect(in, dssdev);
> +}
> +
> +static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> + int r;
> +
> + if (!omapdss_device_is_connected(dssdev))
> + return -ENODEV;
> +
> + if (omapdss_device_is_enabled(dssdev))
> + return 0;
> +
> + in->ops.dpi->set_data_lines(in, ddata->data_lines);
> + in->ops.dpi->set_timings(in, &ddata->videomode);
> +
> + r = in->ops.dpi->enable(in);
> + if (r)
> + return r;
> +
> + dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
> + dssdev->state);
> +
> + /* three times command zero */
> + r |= jbt_reg_write_nodata(ddata, 0x00);
> + udelay(1000);
These are big delays, and I guess the timing is not strict here, so
maybe some sleep variant would be better.
> + r |= jbt_reg_write_nodata(ddata, 0x00);
> + udelay(1000);
> + r |= jbt_reg_write_nodata(ddata, 0x00);
> + udelay(1000);
> +
> + /* deep standby out */
> + r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x17);
> +
> + /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE, 0x80);
> +
> + /* Quad mode off */
> + r |= jbt_reg_write(ddata, JBT_REG_QUAD_RATE, 0x00);
> +
> + /* AVDD on, XVDD on */
> + r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x16);
> +
> + /* Output control */
> + r |= jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
> +
> + /* Sleep mode off */
> + r |= jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_OUT);
> +
> + /* at this point we have like 50% grey */
> +
> + /* initialize register set */
> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
> + r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
> + r |= jbt_reg_write(ddata, JBT_REG_RGB_FORMAT, 0x60);
> + r |= jbt_reg_write(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_OP, 0x56);
> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_MODE, 0x33);
> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
> + r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
> + r |= jbt_reg_write(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
> + r |= jbt_reg_write(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
> + r |= jbt_reg_write(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
> + r |= jbt_reg_write(ddata, JBT_REG_EXT_DISPL, 0x03);
> + r |= jbt_reg_write(ddata, JBT_REG_DCCLK_DCEV, 0x04);
> + /*
> + * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
> + * to avoid red / blue flicker
> + */
> + r |= jbt_reg_write(ddata, JBT_REG_ASW_SLEW, 0x04);
> + r |= jbt_reg_write(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
> +
> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
> + r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
> + r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
> +
> + r |= jbt_reg_write16(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
> + r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
> +
> + r |= jbt_reg_write16(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
> + r |= jbt_reg_write(ddata, JBT_REG_BLANK_CONTROL, 0x02);
> + r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
> + r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
> +
> + r |= jbt_reg_write(ddata, JBT_REG_CKV_ON_OFF, 0x01);
> + r |= jbt_reg_write16(ddata, JBT_REG_CKV_1_2, 0x0000);
> +
> + r |= jbt_reg_write16(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
> + r |= jbt_reg_write16(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
> + r |= jbt_reg_write(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
> +
> + r |= jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_ON);
> +
> + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
> +
> + return r;
> +}
> +
> +static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> +
> + if (!omapdss_device_is_enabled(dssdev))
> + return;
> +
> + dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
> +
> + in->ops.dpi->disable(in);
> +
> + jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_OFF);
> + jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
> + jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_IN);
> + jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x00);
> +
> + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
> +}
> +
> +static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
> + struct omap_video_timings *timings)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> +
> + ddata->videomode = *timings;
> + dssdev->panel.timings = *timings;
> +
> + in->ops.dpi->set_timings(in, timings);
> +}
> +
> +static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
> + struct omap_video_timings *timings)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> +
> + *timings = ddata->videomode;
> +}
> +
> +static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
> + struct omap_video_timings *timings)
> +{
> + struct panel_drv_data *ddata = to_panel_data(dssdev);
> + struct omap_dss_device *in = ddata->in;
> +
> + return in->ops.dpi->check_timings(in, timings);
> +}
> +
> +static struct omap_dss_driver td028ttec1_ops = {
> + .connect = td028ttec1_panel_connect,
> + .disconnect = td028ttec1_panel_disconnect,
> +
> + .enable = td028ttec1_panel_enable,
> + .disable = td028ttec1_panel_disable,
> +
> + .set_timings = td028ttec1_panel_set_timings,
> + .get_timings = td028ttec1_panel_get_timings,
> + .check_timings = td028ttec1_panel_check_timings,
> +};
> +
> +static int td028ttec1_panel_probe_pdata(struct platform_device *pdev)
> +{
> + const struct panel_tpo_td028tec1_platform_data *pdata;
> + struct panel_drv_data *ddata = platform_get_drvdata(pdev);
> + struct omap_dss_device *dssdev, *in;
> +
> + pdata = dev_get_platdata(&pdev->dev);
> +
> + in = omap_dss_find_output(pdata->source);
> + if (in == NULL) {
> + dev_err(&pdev->dev, "failed to find video source '%s'\n",
> + pdata->source);
> + return -EPROBE_DEFER;
> + }
> +
> + ddata->in = in;
> +
> + ddata->data_lines = pdata->data_lines;
> +
> + dssdev = &ddata->dssdev;
> + dssdev->name = pdata->name;
> +
> + ddata->cs_gpio = pdata->cs_gpio;
> + ddata->scl_gpio = pdata->scl_gpio;
> + ddata->din_gpio = pdata->din_gpio;
> + ddata->dout_gpio = pdata->dout_gpio;
> +
> + return 0;
> +}
> +
> +static int td028ttec1_panel_probe(struct platform_device *pdev)
> +{
> + struct panel_drv_data *ddata;
> + struct omap_dss_device *dssdev;
> + int r;
> +
> + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
> + if (ddata == NULL)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, ddata);
> +
> + if (dev_get_platdata(&pdev->dev)) {
> + r = td028ttec1_panel_probe_pdata(pdev);
> + if (r)
> + return r;
> + } else {
> + return -ENODEV;
> + }
> +
> + if (gpio_is_valid(ddata->cs_gpio)) {
> + r = devm_gpio_request_one(&pdev->dev, ddata->cs_gpio,
> + GPIOF_OUT_INIT_HIGH, "lcd cs");
> + if (r)
> + goto err_gpio;
> + }
> +
> + if (gpio_is_valid(ddata->scl_gpio)) {
> + r = devm_gpio_request_one(&pdev->dev, ddata->scl_gpio,
> + GPIOF_OUT_INIT_HIGH, "lcd scl");
> + if (r)
> + goto err_gpio;
> + }
> +
> + if (gpio_is_valid(ddata->dout_gpio)) {
> + r = devm_gpio_request_one(&pdev->dev, ddata->dout_gpio,
> + GPIOF_OUT_INIT_LOW, "lcd dout");
> + if (r)
> + goto err_gpio;
> + }
> +
> + if (gpio_is_valid(ddata->din_gpio)) {
> + r = devm_gpio_request_one(&pdev->dev, ddata->din_gpio,
> + GPIOF_IN, "lcd din");
> + if (r)
> + goto err_gpio;
> + }
> +
> + /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
> + * seems unreliable with later LCM batches, increasing to 90ms */
> + mdelay(90);
What is this delay for? Usually sleeps/delays should be between two "HW
actions". Here there's nothing below this line that would count as such
an action.
> + ddata->videomode = td028ttec1_panel_timings;
> +
> + dssdev = &ddata->dssdev;
> + dssdev->dev = &pdev->dev;
> + dssdev->driver = &td028ttec1_ops;
> + dssdev->type = OMAP_DISPLAY_TYPE_DPI;
> + dssdev->owner = THIS_MODULE;
> + dssdev->panel.timings = ddata->videomode;
> + dssdev->phy.dpi.data_lines = ddata->data_lines;
> +
> + r = omapdss_register_display(dssdev);
> + if (r) {
> + dev_err(&pdev->dev, "Failed to register panel\n");
> + goto err_reg;
> + }
> +
> + return 0;
> +
> +err_reg:
> +err_gpio:
> + omap_dss_put_device(ddata->in);
> + return r;
> +}
> +
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* [PATCH v3 3/3] video: xilinxfb: Simplify error path
From: Michal Simek @ 2013-10-10 6:30 UTC (permalink / raw)
To: linux-kernel, monstr
Cc: joe, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
linux-fbdev
In-Reply-To: <631df9a44b366af4129d00f1d4e1d3baad7d4903.1381386616.git.michal.simek@xilinx.com>
[-- Attachment #1: Type: text/plain, Size: 2106 bytes --]
devm_iounmap is called automatically that's why remove it from the code
dev_set_drvdata(dev, NULL) is called by generic code
after device_release or on probe failure.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Jingoo Han <jg1.han@samsung.com>
---
Changes in v3: None
Changes in v2:
- Rebased on git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git for-next
drivers/video/xilinxfb.c | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index c420328..9eedf96 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -260,10 +260,9 @@ static int xilinxfb_assign(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(drvdata->regs)) {
- rc = PTR_ERR(drvdata->regs);
- goto err_region;
- }
+ if (IS_ERR(drvdata->regs))
+ return PTR_ERR(drvdata->regs);
+
drvdata->regs_phys = res->start;
}
@@ -279,11 +278,7 @@ static int xilinxfb_assign(struct platform_device *pdev,
if (!drvdata->fb_virt) {
dev_err(dev, "Could not allocate frame buffer memory\n");
- rc = -ENOMEM;
- if (drvdata->flags & BUS_ACCESS_FLAG)
- goto err_fbmem;
- else
- goto err_region;
+ return -ENOMEM;
}
/* Clear (turn to black) the framebuffer */
@@ -363,11 +358,6 @@ err_cmap:
/* Turn off the display */
xilinx_fb_out32(drvdata, REG_CTRL, 0);
-err_fbmem:
- if (drvdata->flags & BUS_ACCESS_FLAG)
- devm_iounmap(dev, drvdata->regs);
-
-err_region:
return rc;
}
@@ -392,11 +382,9 @@ static int xilinxfb_release(struct device *dev)
/* Turn off the display */
xilinx_fb_out32(drvdata, REG_CTRL, 0);
- /* Release the resources, as allocated based on interface */
- if (drvdata->flags & BUS_ACCESS_FLAG)
- devm_iounmap(dev, drvdata->regs);
#ifdef CONFIG_PPC_DCR
- else
+ /* Release the resources, as allocated based on interface */
+ if (!(drvdata->flags & BUS_ACCESS_FLAG))
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* [PATCH v3 2/3] video: xilinxfb: Use devm_kzalloc instead of kzalloc
From: Michal Simek @ 2013-10-10 6:30 UTC (permalink / raw)
To: linux-kernel, monstr
Cc: joe, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
linux-fbdev
In-Reply-To: <631df9a44b366af4129d00f1d4e1d3baad7d4903.1381386616.git.michal.simek@xilinx.com>
[-- Attachment #1: Type: text/plain, Size: 1612 bytes --]
Simplify driver probe and release function.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Jingoo Han <jg1.han@samsung.com>
---
Changes in v3:
- Remove the unnecessary OOM message
Changes in v2:
- Rebased on git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git for-next
drivers/video/xilinxfb.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index d12345f..c420328 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -368,8 +368,6 @@ err_fbmem:
devm_iounmap(dev, drvdata->regs);
err_region:
- kfree(drvdata);
-
return rc;
}
@@ -402,8 +400,6 @@ static int xilinxfb_release(struct device *dev)
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif
- kfree(drvdata);
-
return 0;
}
@@ -423,11 +419,9 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
pdata = xilinx_fb_default_pdata;
/* Allocate the driver data region */
- drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata) {
- dev_err(&pdev->dev, "Couldn't allocate device private record\n");
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
return -ENOMEM;
- }
/*
* To check whether the core is connected directly to DCR or BUS
@@ -451,7 +445,6 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
if (!DCR_MAP_OK(drvdata->dcr_host)) {
dev_err(&op->dev, "invalid DCR address\n");
- kfree(drvdata);
return -ENODEV;
}
}
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* [PATCH v3 1/3] video: xilinxfb: Use standard variable name convention
From: Michal Simek @ 2013-10-10 6:30 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
monstr-pSz03upnqPeHXe+LvDLADg
Cc: joe-6d6DIl74uiNBDgjK7y7TUQ, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, Grant Likely, Rob Herring,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 2612 bytes --]
s/op/pdev/ in xilinxfb_of_probe().
No functional chagnes.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
Changes in v3: None
Changes in v2: None
drivers/video/xilinxfb.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 0e1dd33..d12345f 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -411,7 +411,7 @@ static int xilinxfb_release(struct device *dev)
* OF bus binding
*/
-static int xilinxfb_of_probe(struct platform_device *op)
+static int xilinxfb_of_probe(struct platform_device *pdev)
{
const u32 *prop;
u32 tft_access = 0;
@@ -425,7 +425,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
/* Allocate the driver data region */
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
- dev_err(&op->dev, "Couldn't allocate device private record\n");
+ dev_err(&pdev->dev, "Couldn't allocate device private record\n");
return -ENOMEM;
}
@@ -433,7 +433,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
* To check whether the core is connected directly to DCR or BUS
* interface and initialize the tft_access accordingly.
*/
- of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if",
+ of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
&tft_access);
/*
@@ -457,29 +457,29 @@ static int xilinxfb_of_probe(struct platform_device *op)
}
#endif
- prop = of_get_property(op->dev.of_node, "phys-size", &size);
+ prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.screen_width_mm = prop[0];
pdata.screen_height_mm = prop[1];
}
- prop = of_get_property(op->dev.of_node, "resolution", &size);
+ prop = of_get_property(pdev->dev.of_node, "resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xres = prop[0];
pdata.yres = prop[1];
}
- prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
+ prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xvirt = prop[0];
pdata.yvirt = prop[1];
}
- if (of_find_property(op->dev.of_node, "rotate-display", NULL))
+ if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
pdata.rotate_screen = 1;
- dev_set_drvdata(&op->dev, drvdata);
- return xilinxfb_assign(op, drvdata, &pdata);
+ dev_set_drvdata(&pdev->dev, drvdata);
+ return xilinxfb_assign(pdev, drvdata, &pdata);
}
static int xilinxfb_of_remove(struct platform_device *op)
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* Re: [PATCH v2 2/3] video: xilinxfb: Use devm_kzalloc instead of kzalloc
From: Michal Simek @ 2013-10-10 6:24 UTC (permalink / raw)
To: Joe Perches
Cc: Michal Simek, linux-kernel, monstr,
Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
In-Reply-To: <1381331583.2050.11.camel@joe-AO722>
[-- Attachment #1: Type: text/plain, Size: 1125 bytes --]
On 10/09/2013 05:13 PM, Joe Perches wrote:
> On Wed, 2013-10-09 at 12:52 +0200, Michal Simek wrote:
>> Simplify driver probe and release function.
> []
>> diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
> []
>> @@ -423,7 +419,7 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
>> pdata = xilinx_fb_default_pdata;
>>
>> /* Allocate the driver data region */
>> - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
>> + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
>> if (!drvdata) {
>> dev_err(&pdev->dev, "Couldn't allocate device private record\n");
>
> Be nice to remove the unnecessary OOM message.
> There's already a generic dump_stack on OOM.
Ah yeah - this series was made before I knew this.
Will send v3.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
^ permalink raw reply
* [PATCH] video: da8xx-fb: remove unwanted define
From: Manish Badarkhe @ 2013-10-10 4:40 UTC (permalink / raw)
To: linux-fbdev, linux-kernel
Cc: plagnioj, tomi.valkeinen, nsekhar, badarkhe.manish
Remove unwanted define "WSI_TIMEOUT" present in code.
Signed-off-by: Manish Badarkhe <badarkhe.manish@gmail.com>
---
:100644 100644 e030e17... fa61323... M drivers/video/da8xx-fb.c
drivers/video/da8xx-fb.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index e030e17..fa61323 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -129,7 +129,6 @@
#define LCD_NUM_BUFFERS 2
-#define WSI_TIMEOUT 50
#define PALETTE_SIZE 256
#define CLK_MIN_DIV 2
--
1.7.10.4
^ permalink raw reply related
* [PATCH] omapdss: Add new panel driver for Topolly td028ttec1 LCD.
From: Marek Belisko @ 2013-10-09 21:08 UTC (permalink / raw)
To: tomi.valkeinen, plagnioj
Cc: linux-kernel, linux-omap, linux-fbdev, Marek Belisko,
H. Nikolaus Schaller
For communicating with driver is used gpio bitbanging because TD028 does
not have a standard compliant SPI interface. It is a 3-wire thing with
direction reversal.
Communication with display is used only during panel enable/disable so it's
not performance issue.
Signed-off-by: Marek Belisko <marek@goldelico.com>
Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
---
drivers/video/omap2/displays-new/Kconfig | 6 +
drivers/video/omap2/displays-new/Makefile | 1 +
.../omap2/displays-new/panel-tpo-td028ttec1.c | 537 +++++++++++++++++++++
include/video/omap-panel-data.h | 22 +
4 files changed, 566 insertions(+)
create mode 100644 drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
index 6c90885..3f86432 100644
--- a/drivers/video/omap2/displays-new/Kconfig
+++ b/drivers/video/omap2/displays-new/Kconfig
@@ -56,6 +56,11 @@ config DISPLAY_PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
+config DISPLAY_PANEL_TPO_TD028TTEC1
+ tristate "TPO TD028TTEC1 LCD Panel"
+ help
+ LCD panel used by Openmoko.
+
config DISPLAY_PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
depends on SPI
@@ -70,4 +75,5 @@ config DISPLAY_PANEL_NEC_NL8048HL11
This NEC NL8048HL11 panel is TFT LCD used in the
Zoom2/3/3630 sdp boards.
+
endmenu
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
index 5aeb11b..0323a8a 100644
--- a/drivers/video/omap2/displays-new/Makefile
+++ b/drivers/video/omap2/displays-new/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o
obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+obj-$(CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o
obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
diff --git a/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
new file mode 100644
index 0000000..b63586e
--- /dev/null
+++ b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c
@@ -0,0 +1,537 @@
+/*
+ * Toppoly TD028TTEC1 panel support
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Neo 1973 code (jbt6k74.c):
+ * Copyright (C) 2006-2007 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * Ported and adapted from Neo 1973 U-Boot by:
+ * H. Nikolaus Schaller <hns@goldelico.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int data_lines;
+
+ struct omap_video_timings videomode;
+
+ int cs_gpio;
+ int scl_gpio;
+ int din_gpio;
+ int dout_gpio;
+
+ u_int16_t tx_buf[4];
+};
+
+static struct omap_video_timings td028ttec1_panel_timings = {
+ .x_res = 480,
+ .y_res = 640,
+ .pixel_clock = 22153,
+ .hfp = 24,
+ .hsw = 8,
+ .hbp = 8,
+ .vfp = 4,
+ .vsw = 2,
+ .vbp = 2,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
+};
+
+#define JBT_COMMAND 0x000
+#define JBT_DATA 0x100
+
+/* 150uS minimum clock cycle, we have two of this plus our other
+ * instructions */
+
+#define SPI_DELAY() udelay(200)
+
+static int jbt_spi_xfer(struct panel_drv_data *data, int wordnum, int bitlen)
+{
+ u_int16_t tmpdout = 0;
+ int i, j;
+
+ gpio_set_value(data->cs_gpio, 0);
+
+ for (i = 0; i < wordnum; i++) {
+ tmpdout = data->tx_buf[i];
+
+ for (j = 0; j < bitlen; j++) {
+ gpio_set_value(data->scl_gpio, 0);
+ if (tmpdout & (1 << (bitlen-1))) {
+ gpio_set_value(data->dout_gpio, 1);
+ if (gpio_get_value(data->din_gpio) = 0)
+ return 1;
+ } else {
+ gpio_set_value(data->dout_gpio, 0);
+ if (gpio_get_value(data->din_gpio) != 0)
+ return 1;
+ }
+ SPI_DELAY();
+ gpio_set_value(data->scl_gpio, 1);
+ SPI_DELAY();
+ tmpdout <<= 1;
+ }
+ }
+
+ gpio_set_value(data->cs_gpio, 1);
+
+ return 0;
+}
+
+#define JBT_COMMAND 0x000
+#define JBT_DATA 0x100
+
+int jbt_reg_write_nodata(struct panel_drv_data *ddata, u_int8_t reg)
+{
+ int rc;
+
+ ddata->tx_buf[0] = JBT_COMMAND | reg;
+
+ rc = jbt_spi_xfer(ddata, 1, 9);
+ if (rc)
+ dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
+
+ return rc;
+}
+
+int jbt_reg_write(struct panel_drv_data *ddata, u_int8_t reg, u_int8_t data)
+{
+ int rc;
+
+ ddata->tx_buf[0] = JBT_COMMAND | reg;
+ ddata->tx_buf[1] = JBT_DATA | data;
+
+ rc = jbt_spi_xfer(ddata, 2, 9);
+ if (rc)
+ dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
+
+ return rc;
+}
+
+int jbt_reg_write16(struct panel_drv_data *ddata, u_int8_t reg, u_int16_t data)
+{
+ int rc;
+
+ ddata->tx_buf[0] = JBT_COMMAND | reg;
+ ddata->tx_buf[1] = JBT_DATA | (data >> 8);
+ ddata->tx_buf[2] = JBT_DATA | (data & 0xff);
+
+ rc = jbt_spi_xfer(ddata, 3, 9);
+ if (rc)
+ dev_warn(ddata->dssdev.dev, "Failed to write reg: %x\n", reg);
+
+ return rc;
+}
+
+enum jbt_register {
+ JBT_REG_SLEEP_IN = 0x10,
+ JBT_REG_SLEEP_OUT = 0x11,
+
+ JBT_REG_DISPLAY_OFF = 0x28,
+ JBT_REG_DISPLAY_ON = 0x29,
+
+ JBT_REG_RGB_FORMAT = 0x3a,
+ JBT_REG_QUAD_RATE = 0x3b,
+
+ JBT_REG_POWER_ON_OFF = 0xb0,
+ JBT_REG_BOOSTER_OP = 0xb1,
+ JBT_REG_BOOSTER_MODE = 0xb2,
+ JBT_REG_BOOSTER_FREQ = 0xb3,
+ JBT_REG_OPAMP_SYSCLK = 0xb4,
+ JBT_REG_VSC_VOLTAGE = 0xb5,
+ JBT_REG_VCOM_VOLTAGE = 0xb6,
+ JBT_REG_EXT_DISPL = 0xb7,
+ JBT_REG_OUTPUT_CONTROL = 0xb8,
+ JBT_REG_DCCLK_DCEV = 0xb9,
+ JBT_REG_DISPLAY_MODE1 = 0xba,
+ JBT_REG_DISPLAY_MODE2 = 0xbb,
+ JBT_REG_DISPLAY_MODE = 0xbc,
+ JBT_REG_ASW_SLEW = 0xbd,
+ JBT_REG_DUMMY_DISPLAY = 0xbe,
+ JBT_REG_DRIVE_SYSTEM = 0xbf,
+
+ JBT_REG_SLEEP_OUT_FR_A = 0xc0,
+ JBT_REG_SLEEP_OUT_FR_B = 0xc1,
+ JBT_REG_SLEEP_OUT_FR_C = 0xc2,
+ JBT_REG_SLEEP_IN_LCCNT_D = 0xc3,
+ JBT_REG_SLEEP_IN_LCCNT_E = 0xc4,
+ JBT_REG_SLEEP_IN_LCCNT_F = 0xc5,
+ JBT_REG_SLEEP_IN_LCCNT_G = 0xc6,
+
+ JBT_REG_GAMMA1_FINE_1 = 0xc7,
+ JBT_REG_GAMMA1_FINE_2 = 0xc8,
+ JBT_REG_GAMMA1_INCLINATION = 0xc9,
+ JBT_REG_GAMMA1_BLUE_OFFSET = 0xca,
+
+ JBT_REG_BLANK_CONTROL = 0xcf,
+ JBT_REG_BLANK_TH_TV = 0xd0,
+ JBT_REG_CKV_ON_OFF = 0xd1,
+ JBT_REG_CKV_1_2 = 0xd2,
+ JBT_REG_OEV_TIMING = 0xd3,
+ JBT_REG_ASW_TIMING_1 = 0xd4,
+ JBT_REG_ASW_TIMING_2 = 0xd5,
+
+ JBT_REG_HCLOCK_VGA = 0xec,
+ JBT_REG_HCLOCK_QVGA = 0xed,
+};
+
+#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
+
+static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return 0;
+
+ r = in->ops.dpi->connect(in, dssdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ in->ops.dpi->disconnect(in, dssdev);
+}
+
+static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ in->ops.dpi->set_timings(in, &ddata->videomode);
+
+ r = in->ops.dpi->enable(in);
+ if (r)
+ return r;
+
+ dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
+ dssdev->state);
+
+ /* three times command zero */
+ r |= jbt_reg_write_nodata(ddata, 0x00);
+ udelay(1000);
+ r |= jbt_reg_write_nodata(ddata, 0x00);
+ udelay(1000);
+ r |= jbt_reg_write_nodata(ddata, 0x00);
+ udelay(1000);
+
+ /* deep standby out */
+ r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x17);
+
+ /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */
+ r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE, 0x80);
+
+ /* Quad mode off */
+ r |= jbt_reg_write(ddata, JBT_REG_QUAD_RATE, 0x00);
+
+ /* AVDD on, XVDD on */
+ r |= jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x16);
+
+ /* Output control */
+ r |= jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9);
+
+ /* Sleep mode off */
+ r |= jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_OUT);
+
+ /* at this point we have like 50% grey */
+
+ /* initialize register set */
+ r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE1, 0x01);
+ r |= jbt_reg_write(ddata, JBT_REG_DISPLAY_MODE2, 0x00);
+ r |= jbt_reg_write(ddata, JBT_REG_RGB_FORMAT, 0x60);
+ r |= jbt_reg_write(ddata, JBT_REG_DRIVE_SYSTEM, 0x10);
+ r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_OP, 0x56);
+ r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_MODE, 0x33);
+ r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
+ r |= jbt_reg_write(ddata, JBT_REG_BOOSTER_FREQ, 0x11);
+ r |= jbt_reg_write(ddata, JBT_REG_OPAMP_SYSCLK, 0x02);
+ r |= jbt_reg_write(ddata, JBT_REG_VSC_VOLTAGE, 0x2b);
+ r |= jbt_reg_write(ddata, JBT_REG_VCOM_VOLTAGE, 0x40);
+ r |= jbt_reg_write(ddata, JBT_REG_EXT_DISPL, 0x03);
+ r |= jbt_reg_write(ddata, JBT_REG_DCCLK_DCEV, 0x04);
+ /*
+ * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement
+ * to avoid red / blue flicker
+ */
+ r |= jbt_reg_write(ddata, JBT_REG_ASW_SLEW, 0x04);
+ r |= jbt_reg_write(ddata, JBT_REG_DUMMY_DISPLAY, 0x00);
+
+ r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11);
+ r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11);
+ r |= jbt_reg_write(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11);
+ r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040);
+ r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0);
+ r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020);
+ r |= jbt_reg_write16(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0);
+
+ r |= jbt_reg_write16(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533);
+ r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_FINE_2, 0x00);
+ r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00);
+ r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
+ r |= jbt_reg_write(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00);
+
+ r |= jbt_reg_write16(ddata, JBT_REG_HCLOCK_VGA, 0x1f0);
+ r |= jbt_reg_write(ddata, JBT_REG_BLANK_CONTROL, 0x02);
+ r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
+ r |= jbt_reg_write16(ddata, JBT_REG_BLANK_TH_TV, 0x0804);
+
+ r |= jbt_reg_write(ddata, JBT_REG_CKV_ON_OFF, 0x01);
+ r |= jbt_reg_write16(ddata, JBT_REG_CKV_1_2, 0x0000);
+
+ r |= jbt_reg_write16(ddata, JBT_REG_OEV_TIMING, 0x0d0e);
+ r |= jbt_reg_write16(ddata, JBT_REG_ASW_TIMING_1, 0x11a4);
+ r |= jbt_reg_write(ddata, JBT_REG_ASW_TIMING_2, 0x0e);
+
+ r |= jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_ON);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return r;
+}
+
+static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
+
+ in->ops.dpi->disable(in);
+
+ jbt_reg_write_nodata(ddata, JBT_REG_DISPLAY_OFF);
+ jbt_reg_write16(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
+ jbt_reg_write_nodata(ddata, JBT_REG_SLEEP_IN);
+ jbt_reg_write(ddata, JBT_REG_POWER_ON_OFF, 0x00);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->videomode = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.dpi->set_timings(in, timings);
+}
+
+static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->videomode;
+}
+
+static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.dpi->check_timings(in, timings);
+}
+
+static struct omap_dss_driver td028ttec1_ops = {
+ .connect = td028ttec1_panel_connect,
+ .disconnect = td028ttec1_panel_disconnect,
+
+ .enable = td028ttec1_panel_enable,
+ .disable = td028ttec1_panel_disable,
+
+ .set_timings = td028ttec1_panel_set_timings,
+ .get_timings = td028ttec1_panel_get_timings,
+ .check_timings = td028ttec1_panel_check_timings,
+};
+
+static int td028ttec1_panel_probe_pdata(struct platform_device *pdev)
+{
+ const struct panel_tpo_td028tec1_platform_data *pdata;
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ in = omap_dss_find_output(pdata->source);
+ if (in = NULL) {
+ dev_err(&pdev->dev, "failed to find video source '%s'\n",
+ pdata->source);
+ return -EPROBE_DEFER;
+ }
+
+ ddata->in = in;
+
+ ddata->data_lines = pdata->data_lines;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ ddata->cs_gpio = pdata->cs_gpio;
+ ddata->scl_gpio = pdata->scl_gpio;
+ ddata->din_gpio = pdata->din_gpio;
+ ddata->dout_gpio = pdata->dout_gpio;
+
+ return 0;
+}
+
+static int td028ttec1_panel_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (ddata = NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = td028ttec1_panel_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->cs_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->cs_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd cs");
+ if (r)
+ goto err_gpio;
+ }
+
+ if (gpio_is_valid(ddata->scl_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->scl_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd scl");
+ if (r)
+ goto err_gpio;
+ }
+
+ if (gpio_is_valid(ddata->dout_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->dout_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd dout");
+ if (r)
+ goto err_gpio;
+ }
+
+ if (gpio_is_valid(ddata->din_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->din_gpio,
+ GPIOF_IN, "lcd din");
+ if (r)
+ goto err_gpio;
+ }
+
+ /* according to data sheet: wait 50ms (Tpos of LCM). However, 50ms
+ * seems unreliable with later LCM batches, increasing to 90ms */
+ mdelay(90);
+
+ ddata->videomode = td028ttec1_panel_timings;
+
+ dssdev = &ddata->dssdev;
+ dssdev->dev = &pdev->dev;
+ dssdev->driver = &td028ttec1_ops;
+ dssdev->type = OMAP_DISPLAY_TYPE_DPI;
+ dssdev->owner = THIS_MODULE;
+ dssdev->panel.timings = ddata->videomode;
+ dssdev->phy.dpi.data_lines = ddata->data_lines;
+
+ r = omapdss_register_display(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register panel\n");
+ goto err_reg;
+ }
+
+ return 0;
+
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit td028ttec1_panel_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_display(dssdev);
+
+ td028ttec1_panel_disable(dssdev);
+ td028ttec1_panel_disconnect(dssdev);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static struct platform_driver td028ttec1_driver = {
+ .probe = td028ttec1_panel_probe,
+ .remove = __exit_p(td028ttec1_panel_remove),
+
+ .driver = {
+ .name = "panel-tpo-td028ttec1",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(td028ttec1_driver);
+
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver");
+MODULE_LICENSE("GPL");
diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h
index f7ac8d9..02565ff 100644
--- a/include/video/omap-panel-data.h
+++ b/include/video/omap-panel-data.h
@@ -238,4 +238,26 @@ struct panel_nec_nl8048hl11_platform_data {
int qvga_gpio;
};
+/**
+ * panel-tpo-td028tec1 platform data
+ * @name: name for display netity
+ * @source: name of the display entity used as a video source
+ * @data_lines: number of DPI datalines
+ * @cs_gpio: CS gpio
+ * @scl_gpio: CLK gpio
+ * @din_gpio: input data gpio
+ * @dout_gpio: output data gpio
+ */
+struct panel_tpo_td028tec1_platform_data {
+ const char *name;
+ const char *source;
+
+ int data_lines;
+
+ int cs_gpio;
+ int scl_gpio;
+ int din_gpio;
+ int dout_gpio;
+};
+
#endif /* __OMAP_PANEL_DATA_H */
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH v2 2/3] video: xilinxfb: Use devm_kzalloc instead of kzalloc
From: Joe Perches @ 2013-10-09 15:13 UTC (permalink / raw)
To: Michal Simek
Cc: linux-kernel, monstr, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, linux-fbdev
In-Reply-To: <748c16093663172918a90a53dc472cb8beb584ca.1381315928.git.michal.simek@xilinx.com>
On Wed, 2013-10-09 at 12:52 +0200, Michal Simek wrote:
> Simplify driver probe and release function.
[]
> diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
[]
> @@ -423,7 +419,7 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
> pdata = xilinx_fb_default_pdata;
>
> /* Allocate the driver data region */
> - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
> + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
> if (!drvdata) {
> dev_err(&pdev->dev, "Couldn't allocate device private record\n");
Be nice to remove the unnecessary OOM message.
There's already a generic dump_stack on OOM.
^ permalink raw reply
* Re: [PATCH/RFC v3 00/19] Common Display Framework
From: Andrzej Hajda @ 2013-10-09 14:08 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Laurent Pinchart, linux-fbdev, dri-devel, Jesse Barnes,
Benjamin Gaignard, Tom Gall, Kyungmin Park, linux-media,
Stephen Warren, Mark Zhang, Alexandre Courbot,
Ragesh Radhakrishnan, Thomas Petazzoni, Sunil Joshi,
Maxime Ripard, Vikas Sajjan, Marcus Lorentzon
In-Reply-To: <524C1E78.6030508@ti.com>
On 10/02/2013 03:24 PM, Tomi Valkeinen wrote:
> Hi Andrzej,
>
> On 02/10/13 15:23, Andrzej Hajda wrote:
>
>>> Using Linux buses for DBI/DSI
>>> ==============>>>
>>> I still don't see how it would work. I've covered this multiple times in
>>> previous posts so I'm not going into more details now.
>>>
>>> I implemented DSI (just command mode for now) as a video bus but with bunch of
>>> extra ops for sending the control messages.
>> Could you post the list of ops you have to create.
> I'd rather not post the ops I have in my prototype, as it's still a
> total hack. However, they are very much based on the current OMAP DSS's
> ops, so I'll describe them below. I hope I find time to polish my CDF
> hacks more, so that I can publish them.
>
>> I have posted some time ago my implementation of DSI bus:
>> http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/69358/focusi362
> A note about the DT data on your series, as I've been stuggling to
> figure out the DT data for OMAP: some of the DT properties look like
> configuration, not hardware description. For example,
> "samsung,bta-timeout" doesn't describe hardware.
As I have adopted existing internal driver for MIPI-DSI bus, I did not
take too much
care for DT. You are right, 'bta-timeout' is a configuration parameter
(however its
minimal value is determined by characteristic of the DSI-slave). On the
other
side currently there is no good place for such configuration parameters
AFAIK.
>> I needed three quite generic ops to make it working:
>> - set_power(on/off),
>> - set_stream(on/off),
>> - transfer(dsi_transaction_type, tx_buf, tx_len, rx_buf, rx_len)
>> I have recently replaced set_power by PM_RUNTIME callbacks,
>> but I had to add .initialize ops.
> We have a bit more on omap:
>
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/video/omapdss.h#n648
>
> Some of those should be removed and some should be omap DSI's internal
> matters, not part of the API. But it gives an idea of the ops we use.
> Shortly about the ops:
>
> - (dis)connect, which might be similar to your initialize. connect is
> meant to "connect" the pipeline, reserving the video ports used, etc.
>
> - enable/disable, enable the DSI bus. If the DSI peripheral requires a
> continous DSI clock, it's also started at this point.
>
> - set_config configures the DSI bus (like, command/video mode, etc.).
>
> - configure_pins can be ignored, I think that function is not needed.
>
> - enable_hs and enable_te, used to enable/disable HS mode and
> tearing-elimination
It seems there should be a way to synchronize TE signal with panel,
in case signal is provided only to dsi-master. Some callback I suppose?
Or transfer synchronization should be done by dsi-master.
>
> - update, which does a single frame transfer
>
> - bus_lock/unlock can be ignored
>
> - enable_video_output starts the video stream, when using DSI video mode
>
> - the request_vc, set_vc_id, release_vc can be ignored
>
> - Bunch of transfer funcs. Perhaps a single func could be used, as you
> do. We have sync write funcs, which do a BTA at the end of the write and
> wait for reply, and nosync version, which just pushes the packet to the
> TX buffers.
>
> - bta_sync, which sends a BTA and waits for the peripheral to reply
>
> - set_max_rx_packet_size, used to configure the max rx packet size.
Similar callbacks should be added to mipi-dsi-bus ops as well, to
make it complete/generic.
>
>> Regarding the discussion how and where to implement control bus I have
>> though about different alternatives:
>> 1. Implement DSI-master as a parent dev which will create DSI-slave
>> platform dev in a similar way as for MFD devices (ssbi.c seems to me a
>> good example).
>> 2. Create universal mipi-display-bus which will cover DSI, DBI and
>> possibly other buses - they have have few common things - for example
>> MIPI-DCS commands.
>>
>> I am not really convinced to either solution all have some advantages
>> and disadvantages.
> I think a dedicated DSI bus and your alternatives all have the same
> issues with splitting the DSI control into two. I've shared some of my
> thoughts here:
>
> http://article.gmane.org/gmane.comp.video.dri.devel/90651
> http://article.gmane.org/gmane.comp.video.dri.devel/91269
> http://article.gmane.org/gmane.comp.video.dri.devel/91272
>
> I still think that it's best to consider DSI and DBI as a video bus (not
> as a separate video bus and a control bus), and provide the packet
> transfer methods as part of the video ops.
I have read all posts regarding this issue and currently I tend
to solution where CDF is used to model only video streams,
with control bus implemented in different framework.
The only concerns I have if we should use Linux bus for that.
Andrzej
> Tomi
>
>
^ permalink raw reply
* Re: [PATCH v2 1/3] video: xilinxfb: Use standard variable name convention
From: Michal Simek @ 2013-10-09 11:18 UTC (permalink / raw)
To: Mark Rutland
Cc: Michal Simek,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20131009110651.GH4981-NuALmloUBlrZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 3046 bytes --]
On 10/09/2013 01:06 PM, Mark Rutland wrote:
> On Wed, Oct 09, 2013 at 11:52:12AM +0100, Michal Simek wrote:
>> s/op/pdev/ in xilinxfb_of_probe().
>> No functional chagnes.
>>
>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>> ---
>> Changes in v2: None
>>
>> drivers/video/xilinxfb.c | 18 +++++++++---------
>> 1 file changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
>> index 0e1dd33..d12345f 100644
>> --- a/drivers/video/xilinxfb.c
>> +++ b/drivers/video/xilinxfb.c
>> @@ -411,7 +411,7 @@ static int xilinxfb_release(struct device *dev)
>> * OF bus binding
>> */
>>
>> -static int xilinxfb_of_probe(struct platform_device *op)
>> +static int xilinxfb_of_probe(struct platform_device *pdev)
>> {
>> const u32 *prop;
>> u32 tft_access = 0;
>> @@ -425,7 +425,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
>> /* Allocate the driver data region */
>> drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
>> if (!drvdata) {
>> - dev_err(&op->dev, "Couldn't allocate device private record\n");
>> + dev_err(&pdev->dev, "Couldn't allocate device private record\n");
>> return -ENOMEM;
>> }
>>
>> @@ -433,7 +433,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
>> * To check whether the core is connected directly to DCR or BUS
>> * interface and initialize the tft_access accordingly.
>> */
>> - of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if",
>> + of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
>> &tft_access);
>>
>> /*
>> @@ -457,29 +457,29 @@ static int xilinxfb_of_probe(struct platform_device *op)
>> }
>> #endif
>>
>> - prop = of_get_property(op->dev.of_node, "phys-size", &size);
>> + prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
>> if ((prop) && (size >= sizeof(u32)*2)) {
>> pdata.screen_width_mm = prop[0];
>> pdata.screen_height_mm = prop[1];
>> }
>
> While you're changing these lines, it would be nice to change this
> pattern (here and elsewhere) to use of_property_read_u32_array, so that
> it's endian-safe and consistent with other devicetree parsing code:
>
> of_property_read_u32_array(pdev->dev.of_node, "phys-size", prop, 2);
>
> It won't read the values if the property data's too short, so that
> should be consistent with the existing code.
>
> It would also make the diffstat negative :)
The intention of this patch is simple rename which is exactly how
patch should look like. It means one change per patch.
It means these changes you have describe should be in separate patch
and I definitely agree with them.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
^ permalink raw reply
* Re: [PATCH v2 1/3] video: xilinxfb: Use standard variable name convention
From: Mark Rutland @ 2013-10-09 11:06 UTC (permalink / raw)
To: Michal Simek
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
monstr-pSz03upnqPeHXe+LvDLADg@public.gmane.org,
Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <631df9a44b366af4129d00f1d4e1d3baad7d4903.1381315928.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
On Wed, Oct 09, 2013 at 11:52:12AM +0100, Michal Simek wrote:
> s/op/pdev/ in xilinxfb_of_probe().
> No functional chagnes.
>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> Changes in v2: None
>
> drivers/video/xilinxfb.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
> index 0e1dd33..d12345f 100644
> --- a/drivers/video/xilinxfb.c
> +++ b/drivers/video/xilinxfb.c
> @@ -411,7 +411,7 @@ static int xilinxfb_release(struct device *dev)
> * OF bus binding
> */
>
> -static int xilinxfb_of_probe(struct platform_device *op)
> +static int xilinxfb_of_probe(struct platform_device *pdev)
> {
> const u32 *prop;
> u32 tft_access = 0;
> @@ -425,7 +425,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
> /* Allocate the driver data region */
> drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
> if (!drvdata) {
> - dev_err(&op->dev, "Couldn't allocate device private record\n");
> + dev_err(&pdev->dev, "Couldn't allocate device private record\n");
> return -ENOMEM;
> }
>
> @@ -433,7 +433,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
> * To check whether the core is connected directly to DCR or BUS
> * interface and initialize the tft_access accordingly.
> */
> - of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if",
> + of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
> &tft_access);
>
> /*
> @@ -457,29 +457,29 @@ static int xilinxfb_of_probe(struct platform_device *op)
> }
> #endif
>
> - prop = of_get_property(op->dev.of_node, "phys-size", &size);
> + prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
> if ((prop) && (size >= sizeof(u32)*2)) {
> pdata.screen_width_mm = prop[0];
> pdata.screen_height_mm = prop[1];
> }
While you're changing these lines, it would be nice to change this
pattern (here and elsewhere) to use of_property_read_u32_array, so that
it's endian-safe and consistent with other devicetree parsing code:
of_property_read_u32_array(pdev->dev.of_node, "phys-size", prop, 2);
It won't read the values if the property data's too short, so that
should be consistent with the existing code.
It would also make the diffstat negative :)
>
> - prop = of_get_property(op->dev.of_node, "resolution", &size);
> + prop = of_get_property(pdev->dev.of_node, "resolution", &size);
> if ((prop) && (size >= sizeof(u32)*2)) {
> pdata.xres = prop[0];
> pdata.yres = prop[1];
> }
>
> - prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
> + prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
> if ((prop) && (size >= sizeof(u32)*2)) {
> pdata.xvirt = prop[0];
> pdata.yvirt = prop[1];
> }
>
> - if (of_find_property(op->dev.of_node, "rotate-display", NULL))
> + if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
> pdata.rotate_screen = 1;
Similarly, this could use of_property_read_bool:
pdata.rotate_screen = of_property_read_bool(pdev->dev.of_node,
"rotate-display");
It won't help the diffstat, but it makes the intent clearer.
Cheers,
Mark.
^ permalink raw reply
* [PATCH v2 3/3] video: xilinxfb: Simplify error path
From: Michal Simek @ 2013-10-09 10:52 UTC (permalink / raw)
To: linux-kernel, monstr
Cc: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
In-Reply-To: <631df9a44b366af4129d00f1d4e1d3baad7d4903.1381315928.git.michal.simek@xilinx.com>
[-- Attachment #1: Type: text/plain, Size: 2084 bytes --]
devm_iounmap is called automatically that's why remove it from the code
dev_set_drvdata(dev, NULL) is called by generic code
after device_release or on probe failure.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Jingoo Han <jg1.han@samsung.com>
---
Changes in v2:
Rebased on git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git for-next
drivers/video/xilinxfb.c | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 98c7a6f..7e3036c 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -260,10 +260,9 @@ static int xilinxfb_assign(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(drvdata->regs)) {
- rc = PTR_ERR(drvdata->regs);
- goto err_region;
- }
+ if (IS_ERR(drvdata->regs))
+ return PTR_ERR(drvdata->regs);
+
drvdata->regs_phys = res->start;
}
@@ -279,11 +278,7 @@ static int xilinxfb_assign(struct platform_device *pdev,
if (!drvdata->fb_virt) {
dev_err(dev, "Could not allocate frame buffer memory\n");
- rc = -ENOMEM;
- if (drvdata->flags & BUS_ACCESS_FLAG)
- goto err_fbmem;
- else
- goto err_region;
+ return -ENOMEM;
}
/* Clear (turn to black) the framebuffer */
@@ -363,11 +358,6 @@ err_cmap:
/* Turn off the display */
xilinx_fb_out32(drvdata, REG_CTRL, 0);
-err_fbmem:
- if (drvdata->flags & BUS_ACCESS_FLAG)
- devm_iounmap(dev, drvdata->regs);
-
-err_region:
return rc;
}
@@ -392,11 +382,9 @@ static int xilinxfb_release(struct device *dev)
/* Turn off the display */
xilinx_fb_out32(drvdata, REG_CTRL, 0);
- /* Release the resources, as allocated based on interface */
- if (drvdata->flags & BUS_ACCESS_FLAG)
- devm_iounmap(dev, drvdata->regs);
#ifdef CONFIG_PPC_DCR
- else
+ /* Release the resources, as allocated based on interface */
+ if (!(drvdata->flags & BUS_ACCESS_FLAG))
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* [PATCH v2 2/3] video: xilinxfb: Use devm_kzalloc instead of kzalloc
From: Michal Simek @ 2013-10-09 10:52 UTC (permalink / raw)
To: linux-kernel, monstr
Cc: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-fbdev
In-Reply-To: <631df9a44b366af4129d00f1d4e1d3baad7d4903.1381315928.git.michal.simek@xilinx.com>
[-- Attachment #1: Type: text/plain, Size: 1457 bytes --]
Simplify driver probe and release function.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Reviewed-by: Jingoo Han <jg1.han@samsung.com>
---
Changes in v2:
Rebased on git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git for-next
drivers/video/xilinxfb.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index d12345f..98c7a6f 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -368,8 +368,6 @@ err_fbmem:
devm_iounmap(dev, drvdata->regs);
err_region:
- kfree(drvdata);
-
return rc;
}
@@ -402,8 +400,6 @@ static int xilinxfb_release(struct device *dev)
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif
- kfree(drvdata);
-
return 0;
}
@@ -423,7 +419,7 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
pdata = xilinx_fb_default_pdata;
/* Allocate the driver data region */
- drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
dev_err(&pdev->dev, "Couldn't allocate device private record\n");
return -ENOMEM;
@@ -451,7 +447,6 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
if (!DCR_MAP_OK(drvdata->dcr_host)) {
dev_err(&op->dev, "invalid DCR address\n");
- kfree(drvdata);
return -ENODEV;
}
}
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* [PATCH v2 1/3] video: xilinxfb: Use standard variable name convention
From: Michal Simek @ 2013-10-09 10:52 UTC (permalink / raw)
To: linux-kernel, monstr
Cc: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Grant Likely,
Rob Herring, linux-fbdev, devicetree
[-- Attachment #1: Type: text/plain, Size: 2592 bytes --]
s/op/pdev/ in xilinxfb_of_probe().
No functional chagnes.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
Changes in v2: None
drivers/video/xilinxfb.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 0e1dd33..d12345f 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -411,7 +411,7 @@ static int xilinxfb_release(struct device *dev)
* OF bus binding
*/
-static int xilinxfb_of_probe(struct platform_device *op)
+static int xilinxfb_of_probe(struct platform_device *pdev)
{
const u32 *prop;
u32 tft_access = 0;
@@ -425,7 +425,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
/* Allocate the driver data region */
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
- dev_err(&op->dev, "Couldn't allocate device private record\n");
+ dev_err(&pdev->dev, "Couldn't allocate device private record\n");
return -ENOMEM;
}
@@ -433,7 +433,7 @@ static int xilinxfb_of_probe(struct platform_device *op)
* To check whether the core is connected directly to DCR or BUS
* interface and initialize the tft_access accordingly.
*/
- of_property_read_u32(op->dev.of_node, "xlnx,dcr-splb-slave-if",
+ of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
&tft_access);
/*
@@ -457,29 +457,29 @@ static int xilinxfb_of_probe(struct platform_device *op)
}
#endif
- prop = of_get_property(op->dev.of_node, "phys-size", &size);
+ prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.screen_width_mm = prop[0];
pdata.screen_height_mm = prop[1];
}
- prop = of_get_property(op->dev.of_node, "resolution", &size);
+ prop = of_get_property(pdev->dev.of_node, "resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xres = prop[0];
pdata.yres = prop[1];
}
- prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
+ prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xvirt = prop[0];
pdata.yvirt = prop[1];
}
- if (of_find_property(op->dev.of_node, "rotate-display", NULL))
+ if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
pdata.rotate_screen = 1;
- dev_set_drvdata(&op->dev, drvdata);
- return xilinxfb_assign(op, drvdata, &pdata);
+ dev_set_drvdata(&pdev->dev, drvdata);
+ return xilinxfb_assign(pdev, drvdata, &pdata);
}
static int xilinxfb_of_remove(struct platform_device *op)
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* Re: [PATCH 3/3] video: xilinxfb: Simplify error path
From: Tomi Valkeinen @ 2013-10-09 10:28 UTC (permalink / raw)
To: monstr
Cc: Michal Simek, linux-kernel, Jean-Christophe Plagniol-Villard,
linux-fbdev
In-Reply-To: <52552F2E.7080007@monstr.eu>
[-- Attachment #1: Type: text/plain, Size: 393 bytes --]
On 09/10/13 13:25, Michal Simek wrote:
>> This series does not apply. Can you rebase on top of linux-next, and resend?
>
> Do you mean Stephen Rothwell linux-next or any your linux-next branch?
> No problem to do so if you send me link to the repo.
Either one, my for-next is in Stephen's tree:
git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git for-next
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* Re: [PATCH 3/3] video: xilinxfb: Simplify error path
From: Michal Simek @ 2013-10-09 10:25 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: monstr, Michal Simek, linux-kernel,
Jean-Christophe Plagniol-Villard, linux-fbdev
In-Reply-To: <52551BAB.40805@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1886 bytes --]
On 10/09/2013 11:02 AM, Tomi Valkeinen wrote:
> On 30/09/13 15:05, Michal Simek wrote:
>> Hi Tomi,
>>
>> On 09/16/2013 12:34 PM, Tomi Valkeinen wrote:
>>> On 16/09/13 13:33, Michal Simek wrote:
>>>> On 09/16/2013 11:51 AM, Tomi Valkeinen wrote:
>>>>> On 12/09/13 08:54, Michal Simek wrote:
>>>>>
>>>>>> @@ -394,16 +382,12 @@ static int xilinxfb_release(struct device *dev)
>>>>>> /* Turn off the display */
>>>>>> xilinx_fb_out32(drvdata, REG_CTRL, 0);
>>>>>>
>>>>>> - /* Release the resources, as allocated based on interface */
>>>>>> - if (drvdata->flags & BUS_ACCESS_FLAG)
>>>>>> - devm_iounmap(dev, drvdata->regs);
>>>>>> #ifdef CONFIG_PPC_DCR
>>>>>> - else
>>>>>> + /* Release the resources, as allocated based on interface */
>>>>>> + if (!(drvdata->flags & BUS_ACCESS_FLAG))
>>>>>> dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
>>>>>> #endif
>>>>>
>>>>> I might be mistaken, and it's not strictly part of this series, but
>>>>> shouldn't dcr_unmap be called somewhere else also, if the probe fails?
>>>>
>>>> yes. It should.
>>>
>>> Do you want me to apply these patches as they are, or do you want to
>>> improve the series to include the dcr_unmap fix?
>>
>> Sorry I have missed this email.
>>
>> Yes please apply it as is. I don't have ppc hw here to be able to test this
>> change.
>
> This series does not apply. Can you rebase on top of linux-next, and resend?
Do you mean Stephen Rothwell linux-next or any your linux-next branch?
No problem to do so if you send me link to the repo.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] hyperv-fb: add pci stub
From: Tomi Valkeinen @ 2013-10-09 9:53 UTC (permalink / raw)
To: Gerd Hoffmann
Cc: K. Y. Srinivasan, Haiyang Zhang, Jean-Christophe Plagniol-Villard,
open list:Hyper-V CORE AND..., FRAMEBUFFER LAYER, open list
In-Reply-To: <1380714911-6254-1-git-send-email-kraxel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1068 bytes --]
On 02/10/13 14:55, Gerd Hoffmann wrote:
> This patch adds a pci stub driver to hyper-fb. The hyperv framebuffer
> driver will bind to the pci device then, so linux kernel and userspace
> know there is a proper kernel driver for the device active. lspci shows
> this for example:
>
> [root@dhcp231 ~]# lspci -vs8
> 00:08.0 VGA compatible controller: Microsoft Corporation Hyper-V virtual
> VGA (prog-if 00 [VGA controller])
> Flags: bus master, fast devsel, latency 0, IRQ 11
> Memory at f8000000 (32-bit, non-prefetchable) [size=64M]
> Expansion ROM at <unassigned> [disabled]
> Kernel driver in use: hyperv_fb
>
> Another effect is that the xorg vesa driver will not attach to the
> device and thus the Xorg server will automatically use the fbdev
> driver instead.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> drivers/video/hyperv_fb.c | 40 +++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 39 insertions(+), 1 deletion(-)
>
Thanks, queuing the series for 3.13.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* Re: [PATCH v3] simplefb: print some info about the registered fb
From: Tomi Valkeinen @ 2013-10-09 9:05 UTC (permalink / raw)
To: Tom Gundersen; +Cc: linux-fbdev, linux-kernel, plagnioj, David Herrmann
In-Reply-To: <1378562915-893-1-git-send-email-teg@jklm.no>
[-- Attachment #1: Type: text/plain, Size: 1287 bytes --]
On 07/09/13 17:08, Tom Gundersen wrote:
> This is similar to the output printed by efifb.
>
> Signed-off-by: Tom Gundersen <teg@jklm.no>
> Acked-by: Stephen Warren <swarren@wwwdotorg.org>
> Cc: David Herrmann <dh.herrmann@gmail.com>
> ---
> v2: also print smem_len, as requested by David
> v3: don't cast, as requested by Geert
>
> drivers/video/simplefb.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
> index a29f1c4..50cbceb 100644
> --- a/drivers/video/simplefb.c
> +++ b/drivers/video/simplefb.c
> @@ -220,6 +220,14 @@ static int simplefb_probe(struct platform_device *pdev)
> }
> info->pseudo_palette = (void *)(info + 1);
>
> + dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
> + info->fix.smem_start, info->fix.smem_len,
> + info->screen_base);
> + dev_info(&pdev->dev, "format=%s, mode=%dx%dx%d, linelength=%d\n",
> + params.format->name,
> + info->var.xres, info->var.yres,
> + info->var.bits_per_pixel, info->fix.line_length);
> +
> ret = register_framebuffer(info);
> if (ret < 0) {
> dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
>
Thanks, queued for 3.13.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox