Re: [PATCH 0/3] USB Mux support for Chipidea

2017-07-15 Thread Peter Rosin
On 2017-07-14 23:27, Stephen Boyd wrote:
> Quoting Stephen Boyd (2017-07-13 15:35:02)
>> Quoting Peter Rosin (2017-07-11 22:04:46)
>>>
>>> Maybe no need for a compatible update either, if it works to do something
>>> like this in the DT?
>>>
>>> usb_switch: usb-switch {
>>> compatible = "gpio-mux";
>>> mux-gpios = <_gpios 4 GPIO_ACTIVE_HIGH>,
>>> <_gpios XXX GPIO_ACTIVE_XXX>;
>>> idle-state = <2>;
>>> #mux-control-cells = <0>;
>>> pinctrl-names = "default";
>>> pinctrl-0 = <_sw_sel_pm>;
>>> };
>>>
>>> But I obviously know little about how things are wired and really works,
>>> so that might be totally off...
>>>
>>> Otherwise, maybe a generic mux-pinctrl driver would do the trick?
>>> (compare with drivers/i2c/muxes/i2c-mux-pinctrl.c)
>>>
>>
>> Agreed.
> 
> Testing looks good when I use the gpio-mux binding. The only thing I

Glad to hear it, I didn't really want a new driver so similar to the
mux-gpio driver...

> noticed is that gpio-mux driver is requesting the gpio with
> GPIOD_OUT_LOW. Is that intentional?

Not really intentional, it was just easy.

> I worry that may randomly mux the
> D+/D- lines during probe if the gpio is asserted at probe time. It isn't
> a problem for me right now, because the mux is power on defaulted to
> have the gpio deasserted, but it may be a problem if the default
> changes.

It will not change, the only change I will accept is if the code in
mux-gpio can be arranged to request the gpios with the idle-state from
the start. But even then, the default idle-state (0) will not change.
So, you should be safe.

I will look at the new patches later.

Cheers,
Peter


Re: [PATCH] drivers: i2c: muxes: Kconfig

2017-07-14 Thread Peter Rosin
On 2017-07-12 19:31, Chris Gorman wrote:
> Kconfig says the resulting module is pinctrl-i2cmux and the module when
> built is i2c-mux-pinctrl.
> 
> Signed-off-by: Chris Gorman 

Yes, thanks!

I took the liberty of changing the Subject to

"i2c: mux: pinctrl: mention the correct module name in Kconfig help text"

and applied it to my for-current branch.

Cheers,
Peter


[PATCH v2] mux: mux-core: unregister mux_class in mux_exit()

2017-07-10 Thread Peter Rosin
From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppusw...@linux.intel.com>

Fixes an obvious and nasty typo.

Fixes: a3b02a9c6591 ("mux: minimal mux subsystem")
Signed-off-by: Kuppuswamy Sathyanarayanan 
<sathyanarayanan.kuppusw...@linux.intel.com>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/mux-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Hi Greg!

Please pick this up and pass on along with the other patch
that removed the unloved Kconfig question [1].

Thanks!

Cheers,
peda

[1] https://lkml.org/lkml/2017/7/4/118

diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index 90b8995f07cb..2fe96c470112 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -46,7 +46,7 @@ static int __init mux_init(void)
 
 static void __exit mux_exit(void)
 {
-   class_register(_class);
+   class_unregister(_class);
ida_destroy(_ida);
 }
 
-- 
2.1.4



Re: [PATCH v1 1/1] mux: consumer: Add dummy functions for !CONFIG_MULTIPLEXER case

2017-07-09 Thread Peter Rosin
On 2017-07-09 01:04, Kuppuswamy, Sathyanarayanan wrote:
> Hi Peter,
> 
> On 7/8/2017 1:55 PM, Peter Rosin wrote:
>> On 2017-07-07 23:41, sathyanarayanan.kuppusw...@linux.intel.com wrote:
>>> From: Kuppuswamy Sathyanarayanan 
>>> <sathyanarayanan.kuppusw...@linux.intel.com>
>>>
>>> Add dummy functions to avoid compile time issues when CONFIG_MULTIPLEXER
>>> is not enabled.
>> Hi!
>>
>> Consumers should "select MULTIPLEXER",
>   If their driver can't work without mux_* calls then  you can make it 
> compulsory. But its not always true.
>>   so this does not make sense.
>> Or do you have a driver that has an optional mux consumer?
> I came across this case when I was working on Intel USB MUX driver. I 
> think you know the history behind it. Although I am not planning to 
> merge that driver now, but I think the use case is still valid.

Yeah, it's a valid use case. But why add a facility that noone uses? Sure,
if there's an actual consumer that needs it. But there isn't...

See, I have spent considerable time taking stuff like this out in order to
get the thing merged at all. I even think I wrote dummy inlines like this
at some point (but I'm not sure if I actually wrote them and I don't think
I submitted them. But I did think about it, that's for sure). Anyway, I'm
not very happy about ballooning the core with support for non-essentials
just yet. Maybe my mind-set will change over time?

(And no, I don't *know* the history behind the "Intel USB MUX driver",
 I e.g. never saw the consumer code. And I have the feeling that stuff
 were discussed in other threads that I was not part of and some (most?)
 questions I asked about it was left unanswered.)

Cheers,
peda


Re: [PATCH v2 1/1] mux: consumer: Add dummy functions for !CONFIG_MULTIPLEXER case

2017-07-09 Thread Peter Rosin
On 2017-07-08 23:22, Andy Shevchenko wrote:
> On Sat, Jul 8, 2017 at 9:12 PM,
>  wrote:
>> From: Kuppuswamy Sathyanarayanan 
>>
>> Add dummy functions to avoid compile time issues when CONFIG_MULTIPLEXER
>> is not enabled.
>>
> 
> I don't think the error return code is okay to all of them. The return
> value should be choosen carefully (for some functions it's okay IMO to
> return 0).

BTW, is ENODEV correct for this situation? I have this nagging feeling
that ENODEV is over-used?

And again, all these stubs should all be inlines, or things will break it
this file is included more than once.

>> Signed-off-by: Kuppuswamy Sathyanarayanan 
>> 
>> ---
>>  include/linux/mux/consumer.h | 38 ++
>>  1 file changed, 38 insertions(+)
>>
>> Changes since v1:
>>  * Changed #ifdef to #if IS_ENABLED.
>>
>> diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
>> index 5577e1b..df78988 100644
>> --- a/include/linux/mux/consumer.h
>> +++ b/include/linux/mux/consumer.h
>> @@ -16,6 +16,7 @@
>>  struct device;
>>  struct mux_control;
>>
>> +#if IS_ENABLED(CONFIG_MULTIPLEXER)
>>  unsigned int mux_control_states(struct mux_control *mux);
>>  int __must_check mux_control_select(struct mux_control *mux,
>> unsigned int state);
>> @@ -29,4 +30,41 @@ void mux_control_put(struct mux_control *mux);
>>  struct mux_control *devm_mux_control_get(struct device *dev,
>>  const char *mux_name);
>>
>> +#else
>> +unsigned int mux_control_states(struct mux_control *mux)
>> +{
>> +   return -ENODEV;
> 
> Peter, is here we are obliged to return error code in such case?

Since it will presumably be difficult to obtain a mux_control
w/o the mux-core being present, it doesn't matter much what
most of these stubs return.

For this stub, 0 is perhaps best, since the kernel-doc for
mux_control_states mentions nothing about any error possibility.

>> +}
>> +
>> +int __must_check mux_control_select(struct mux_control *mux,
>> +   unsigned int state)
>> +{
>> +   return -ENODEV;
> 
> return 0; ?

Maybe. But it doesn't matter much, but in this case the consumer must
handle errors. See above.

>> +}
>> +
>> +int __must_check mux_control_try_select(struct mux_control *mux,
>> +   unsigned int state)
>> +{
>> +   return -ENODEV;
>> +}
> 
> return 0; ?

Maybe. But it doesn't matter much, but in this case the consumer must
handle errors. See above.

>> +
>> +int mux_control_deselect(struct mux_control *mux)
>> +{
>> +   return -ENODEV;
>> +}
> 
> return 0; ?

Probably. See above.

Cheers,
peda

>> +
>> +struct mux_control *mux_control_get(struct device *dev, const char 
>> *mux_name)
>> +{
>> +   return ERR_PTR(-ENODEV);
>> +}
>> +
>> +void mux_control_put(struct mux_control *mux) {}
>> +
>> +struct mux_control *devm_mux_control_get(struct device *dev,
>> +const char *mux_name)
>> +{
>> +   return ERR_PTR(-ENODEV);
>> +}
>> +#endif
>> +
>>  #endif /* _LINUX_MUX_CONSUMER_H */
>> --
>> 2.7.4
>>
> 
> 
> 



Re: [PATCH v2 1/1] mux: mux-core: Add NULL check for dev->of_node

2017-07-09 Thread Peter Rosin
On 2017-07-09 01:12, Kuppuswamy, Sathyanarayanan wrote:
> Hi Peter,
> 
> 
> On 7/8/2017 2:00 PM, Peter Rosin wrote:
>> On 2017-07-07 23:46, sathyanarayanan.kuppusw...@linux.intel.com wrote:
>>> From: Kuppuswamy Sathyanarayanan 
>>> <sathyanarayanan.kuppusw...@linux.intel.com>
>>>
>>> If dev->of_node is NULL, then calling mux_control_get()
>>> function can lead to NULL pointer exception. So adding
>>> a NULL check for dev->of_node.
>>>
>>> Signed-off-by: Kuppuswamy Sathyanarayanan 
>>> <sathyanarayanan.kuppusw...@linux.intel.com>
>> Do you have a driver that might call mux_control_get and not have any
>> of_node?
> For non-device tree drivers, this case is valid. I hit this issue when I 
> was working on Intel USB MUX driver.
>>   If not, I don't see the point of this check.
> Since this is an API for other consumers, I think its better to have 
> some sanity checks.
> 
> If a non device tree driver call this API , I think its better to fail 
> with some error no instead of creating null pointer exception.

Is it? When authoring a new driver, and you make some error like this, why
is a "nice" error better than a big fat fail? If you get a null deref,
you will presumably also get a call stack etc, which will help you find
where you made the error, w/o adding a bunch of traces to find out exactly
what you did wrong.

So, I'm skeptic...

Cheers,
peda

>>
>> Cheers,
>> peda
>>
>>> ---
>>>   drivers/mux/mux-core.c | 3 +++
>>>   1 file changed, 3 insertions(+)
>>>
>>> Changes since v1:
>>>   * Removed dummy new line.
>>>
>>> diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
>>> index 90b8995..924c983 100644
>>> --- a/drivers/mux/mux-core.c
>>> +++ b/drivers/mux/mux-core.c
>>> @@ -438,6 +438,9 @@ struct mux_control *mux_control_get(struct device *dev, 
>>> const char *mux_name)
>>> int index = 0;
>>> int ret;
>>>   
>>> +   if (!np)
>>> +   return ERR_PTR(-ENODEV);
>>> +
>>> if (mux_name) {
>>> index = of_property_match_string(np, "mux-control-names",
>>>  mux_name);
>>>
> 



Re: [PATCH v2 1/3] mux: Add mux_control_get_optional() API

2017-07-19 Thread Peter Rosin
On 2017-07-19 04:08, Stephen Boyd wrote:
> Quoting Peter Rosin (2017-07-17 01:20:14)
>> On 2017-07-14 23:40, Stephen Boyd wrote:
>>> diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
>>> index 90b8995f07cb..a0e5bf16f02f 100644
>>> --- a/drivers/mux/mux-core.c
>>> +++ b/drivers/mux/mux-core.c
>>> @@ -289,6 +289,9 @@ EXPORT_SYMBOL_GPL(devm_mux_chip_register);
>>>   */
>>>  unsigned int mux_control_states(struct mux_control *mux)
>>>  {
>>> + if (!mux)
>>> + return 0;
>>> +
>>
>> I don't think this is appropriate. For this function, it might be ok,
>> but...
>>
>>>   return mux->states;
>>>  }
>>>  EXPORT_SYMBOL_GPL(mux_control_states);
>>> @@ -338,6 +341,9 @@ int mux_control_select(struct mux_control *mux, 
>>> unsigned int state)
>>>  {
>>>   int ret;
>>>  
>>> + if (!mux)
>>> + return 0;
>>> +
>>
>> ...here and for other cases below it's very odd to return "ok", when
>> -EINVAL or something seems much more appropriate. And if -EINVAL is
>> returned here, the benefit of returning fake values for anything
>> pretty much falls apart.
>>
>> I simply don't like it, and prefer if the consumer code is arranged
>> to not call the mux functions when the optional get() does not find
>> the mux.
> 
> Do you want the callers of the mux APIs to know that an optional mux
> isn't there, and then have checks at all callsites on optional muxes to
> make sure consumers don't call the mux functions? Won't that duplicate
> lots of checks in drivers for something the core could treat as a don't
> care case? Sorry, I don't understand why the consumer cares that it was
> there or not when it is optional.

Ok, I had a look around to figure out how others handle this, and e.g.
gpio has (ugly) macros (VALIDATE_DESC) to handle this. I guess you are
right and I'm wrong. So, please keep all the if (!mux) checks.

Thanks for insisting!

>>
>>>   ret = down_killable(>lock);
>>>   if (ret < 0)
>>>   return ret;
>>> @@ -370,6 +376,9 @@ int mux_control_try_select(struct mux_control *mux, 
>>> unsigned int state)
>>>  {
>>>   int ret;
>>>  
>>> + if (!mux)
>>> + return 0;
>>> +
>>>   if (down_trylock(>lock))
>>>   return -EBUSY;
>>>  
>>> @@ -398,6 +407,9 @@ int mux_control_deselect(struct mux_control *mux)
>>>  {
>>>   int ret = 0;
>>>  
>>> + if (!mux)
>>> + return 0;
>>> +
>>>   if (mux->idle_state != MUX_IDLE_AS_IS &&
>>>   mux->idle_state != mux->cached_state)
>>>   ret = mux_control_set(mux, mux->idle_state);
>>> @@ -422,14 +434,8 @@ static struct mux_chip 
>>> *of_find_mux_chip_by_node(struct device_node *np)
>>>   return dev ? to_mux_chip(dev) : NULL;
>>>  }
>>>  
>>> -/**
>>> - * mux_control_get() - Get the mux-control for a device.
>>> - * @dev: The device that needs a mux-control.
>>> - * @mux_name: The name identifying the mux-control.
>>> - *
>>> - * Return: A pointer to the mux-control, or an ERR_PTR with a negative 
>>> errno.
>>> - */
>>> -struct mux_control *mux_control_get(struct device *dev, const char 
>>> *mux_name)
>>> +struct mux_control *
>>> +__mux_control_get(struct device *dev, const char *mux_name, bool optional)
>>>  {
>>>   struct device_node *np = dev->of_node;
>>>   struct of_phandle_args args;
>>> @@ -441,6 +447,8 @@ struct mux_control *mux_control_get(struct device *dev, 
>>> const char *mux_name)
>>>   if (mux_name) {
>>>   index = of_property_match_string(np, "mux-control-names",
>>>mux_name);
>>> + if (index == -EINVAL && optional)
>>> + return NULL;
>>
>> What about -ENODATA?
> 
> At this point in the code we're finding the index of a mux-control-names
> property so I was trying to handle the case where there isn't a
> mux-control-names property at all

Yes, you indeed need to check for -EINVAL to catch that. No argument
about that.

>   but we're looking for something
> optional anyway. If there is a property, then we would see some other
> error if so

Re: [PATCH] drm: atmel-hlcdc: use a default gamma ramp if none is specified

2017-07-03 Thread Peter Rosin
On 2017-07-03 14:02, Boris Brezillon wrote:
> On Mon, 3 Jul 2017 13:53:28 +0200
> Peter Rosin <p...@axentia.se> wrote:
> 
>> On 2017-07-03 13:31, Boris Brezillon wrote:
>>> On Mon,  3 Jul 2017 11:42:10 +0200
>>> Peter Rosin <p...@axentia.se> wrote:
>>>   
>>>> At init and if the gamma_lut property is ever removed, the clut
>>>> registers must be programmed with a default gamma ramp instead of
>>>> being left in some unknown state.
>>>>
>>>> Fixes: 364a7bf574eb ("drm: atmel-hlcdc: add support for 8-bit color lookup 
>>>> table mode")
>>>> Signed-off-by: Peter Rosin <p...@axentia.se>
>>>> ---
>>>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 17 -
>>>>  1 file changed, 16 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c 
>>>> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>>>> index b5bd9b0..0ccd93c 100644
>>>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>>>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>>>> @@ -429,6 +429,14 @@ static void atmel_hlcdc_plane_update_format(struct 
>>>> atmel_hlcdc_plane *plane,
>>>>ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
>>>>  }
>>>>  
>>>> +static void atmel_hlcdc_default_gamma_ramp(struct atmel_hlcdc_layer 
>>>> *layer)
>>>> +{
>>>> +  int idx;
>>>> +
>>>> +  for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++)
>>>> +  atmel_hlcdc_layer_write_clut(layer, idx, idx * 0x10101);
>>>> +}
>>>> +
>>>>  static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane)
>>>>  {
>>>>struct drm_crtc *crtc = plane->base.crtc;
>>>> @@ -438,9 +446,14 @@ static void atmel_hlcdc_plane_update_clut(struct 
>>>> atmel_hlcdc_plane *plane)
>>>>if (!crtc || !crtc->state)
>>>>return;
>>>>  
>>>> -  if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
>>>> +  if (!crtc->state->color_mgmt_changed)
>>>>return;
>>>>  
>>>> +  if (!crtc->state->gamma_lut) {
>>>> +  atmel_hlcdc_default_gamma_ramp(>layer);  
>>>
>>> Hm, I'd prefer to have state->gamma_lut properly initialized in
>>> atmel_hlcdc_crtc_reset(), this way you don't have to do that in the
>>> update path.  
>>
>> The gamma_lut property can be removed, so you have to handle it here anyway. 
>> No?
> 
> Hm, what do you mean by removed? AFAICT, a property, once attached to
> a DRM object, exists until the DRM object is destroyed. The data
> attached to this property (here, the gamma_lut array) can be NULL, but
> once you have allocated the data container, it will be duplicated (and
> possibly updated) every time an atomic operation is triggered.

By remove I meant someone somehow triggering a call like this:

drm_atomic_crtc_set_property(crtc, ...->gamma_lut_property, 0);

By the looks of it, that is not happening? But I'm not sure of that, and
even if it's not happening today, that may change...

> By initializing this field in crtc->reset(), you enforce the
> default/reset state, which IIUC, is what you want here.

Agreed, if it is not possible to remove/clear out the gamma_lut property,
then the only thing needed is to initialize the hw clut registers to the
linear ramp somewhere early.

But is it indeed a fact that there is no way to clear out the gamma_lut prop?

Cheers,
peda


[PATCH v2] mux: remove the Kconfig question for the subsystem

2017-07-04 Thread Peter Rosin
The MULTIPLEXER question in the Kconfig might be confusing and is
of dubious value. Remove it. This makes consumers responsible for
selecting MULTIPLEXER, which they already do.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig | 19 +--
 1 file changed, 5 insertions(+), 14 deletions(-)

On 2017-07-04 08:00, Linus Torvalds wrote:
> On Jul 3, 2017 22:53, "Peter Rosin" <p...@axentia.se 
> <mailto:p...@axentia.se>> wrote:
>> But ok, is something like this what you wanted?
> 
> I *think* this week just result in an empty menu if there are
> no drivers selecting it.
> 
> Shouldn't the 'if' be outside the menu? But I didn't test
> anything, since I'm not in front of my computer any more..

Right, the previous patch also had the problem that it removed
the MULTIPLEXER option completely and was therefore total crap.

I have tested this patch more thoroughly and it should be a
definite improvement. Sorry for the noise...

Cheers,
peda

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 7c754a0..19e4e90 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -2,20 +2,11 @@
 # Multiplexer devices
 #
 
-menuconfig MULTIPLEXER
-   tristate "Multiplexer subsystem"
-   help
- Multiplexer controller subsystem. Multiplexers are used in a
- variety of settings, and this subsystem abstracts their use
- so that the rest of the kernel sees a common interface. When
- multiple parallel multiplexers are controlled by one single
- multiplexer controller, this subsystem also coordinates the
- multiplexer accesses.
-
- To compile the subsystem as a module, choose M here: the module will
- be called mux-core.
+config MULTIPLEXER
+   tristate
 
-if MULTIPLEXER
+menu "Multiplexer drivers"
+   depends on MULTIPLEXER
 
 config MUX_ADG792A
tristate "Analog Devices ADG792A/ADG792G Multiplexers"
@@ -56,4 +47,4 @@ config MUX_MMIO
  To compile the driver as a module, choose M here: the module will
  be called mux-mmio.
 
-endif
+endmenu
-- 
2.1.4



[PATCH] mux: remove the Kconfig question for the subsystem

2017-07-03 Thread Peter Rosin
The MULTIPLEXER question in the Kconfig might be confusing and is
of dubious value. Remove it. This makes consumers responsible for
selecting MULTIPLEXER, which they already do.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig | 15 +++
 1 file changed, 3 insertions(+), 12 deletions(-)

Hi Linus!

My thinking was that I wanted it to be possible to select
mux drivers before any mux consumer was selected. I also
wanted to avoid one question for each of the mux drivers
when the whole thing is not needed most of the time...

But ok, is something like this what you wanted?

Cheers,
peda

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 7c754a0..96d364e 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -2,18 +2,7 @@
 # Multiplexer devices
 #
 
-menuconfig MULTIPLEXER
-   tristate "Multiplexer subsystem"
-   help
- Multiplexer controller subsystem. Multiplexers are used in a
- variety of settings, and this subsystem abstracts their use
- so that the rest of the kernel sees a common interface. When
- multiple parallel multiplexers are controlled by one single
- multiplexer controller, this subsystem also coordinates the
- multiplexer accesses.
-
- To compile the subsystem as a module, choose M here: the module will
- be called mux-core.
+menu "Multiplexer support"
 
 if MULTIPLEXER
 
@@ -57,3 +46,5 @@ config MUX_MMIO
  be called mux-mmio.
 
 endif
+
+endmenu
-- 
2.1.4



[PATCH v3 05/16] drm/fb-helper: do a generic fb_setcmap helper in terms of crtc .gamma_set

2017-07-04 Thread Peter Rosin
This makes the redundant fb helpers .load_lut, .gamma_set and .gamma_get
completely obsolete.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_fb_helper.c | 165 +++-
 1 file changed, 94 insertions(+), 71 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b75b1f2..7f8199a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1257,27 +1257,6 @@ void drm_fb_helper_set_suspend_unlocked(struct 
drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
 
-static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, u16 regno, struct fb_info *info)
-{
-   struct drm_fb_helper *fb_helper = info->par;
-   struct drm_framebuffer *fb = fb_helper->fb;
-
-   /*
-* The driver really shouldn't advertise pseudo/directcolor
-* visuals if it can't deal with the palette.
-*/
-   if (WARN_ON(!fb_helper->funcs->gamma_set ||
-   !fb_helper->funcs->gamma_get))
-   return -EINVAL;
-
-   WARN_ON(fb->format->cpp[0] != 1);
-
-   fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
-
-   return 0;
-}
-
 static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
 {
u32 *palette = (u32 *)info->pseudo_palette;
@@ -1310,54 +1289,68 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, 
struct fb_info *info)
return 0;
 }
 
-/**
- * drm_fb_helper_setcmap - implementation for _ops.fb_setcmap
- * @cmap: cmap to set
- * @info: fbdev registered by the helper
- */
-int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
 {
struct drm_fb_helper *fb_helper = info->par;
-   struct drm_device *dev = fb_helper->dev;
-   const struct drm_crtc_helper_funcs *crtc_funcs;
-   u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc;
u16 *r, *g, *b;
-   int i, j, rc = 0;
-   int start;
+   int i, ret = 0;
 
-   if (oops_in_progress)
-   return -EBUSY;
+   for (i = 0; i < fb_helper->crtc_count; i++) {
+   crtc = fb_helper->crtc_info[i].mode_set.crtc;
+   if (!crtc->funcs->gamma_set || !crtc->gamma_size)
+   return -EINVAL;
 
-   mutex_lock(_helper->lock);
-   if (!drm_fb_helper_is_bound(fb_helper)) {
-   mutex_unlock(_helper->lock);
-   return -EBUSY;
-   }
+   if (cmap->start + cmap->len > crtc->gamma_size)
+   return -EINVAL;
 
-   drm_modeset_lock_all(dev);
-   if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
-   rc = setcmap_pseudo_palette(cmap, info);
-   goto out;
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
+   memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
+   memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
+   memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
+
+   ret = crtc->funcs->gamma_set(crtc, r, g, b,
+crtc->gamma_size, NULL);
+   if (ret)
+   return ret;
}
 
-   for (i = 0; i < fb_helper->crtc_count; i++) {
-   crtc = fb_helper->crtc_info[i].mode_set.crtc;
-   crtc_funcs = crtc->helper_private;
+   return ret;
+}
 
-   red = cmap->red;
-   green = cmap->green;
-   blue = cmap->blue;
-   transp = cmap->transp;
-   start = cmap->start;
+static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
+{
+   struct drm_fb_helper *fb_helper = info->par;
+   struct drm_device *dev = fb_helper->dev;
+   struct drm_modeset_acquire_ctx ctx;
+   struct drm_crtc_state *crtc_state;
+   struct drm_atomic_state *state;
+   struct drm_crtc *crtc;
+   u16 *r, *g, *b;
+   int i, ret = 0;
 
-   if (!crtc->gamma_size) {
-   rc = -EINVAL;
+   state = drm_atomic_state_alloc(dev);
+   if (!state)
+   return -ENOMEM;
+   drm_modeset_acquire_init(, 0);
+retry:
+   ret = drm_modeset_lock_all_ctx(dev, );
+   if (ret)
+   goto fini;
+   state->acquire_ctx = 
+   for (i = 0; i < fb_helper->crtc_count; i++) {
+   crtc = fb_helper->crtc_info[i].mode_set.crtc;
+   if (!crtc->funcs->gamma_set) {
+   ret = -EINVAL;
goto out;
}
 
-   

[PATCH v3 00/16] improve the fb_setcmap helper

2017-07-04 Thread Peter Rosin
Hi!

While trying to get CLUT support for the atmel_hlcdc driver, and
specifically for the emulated fbdev interface, I received some
push-back that my feeble in-driver attempts should be solved
by the core. This is my attempt to do it right.

I have obviously not tested all of this with more than a compile,
but patches 1 through 5 are enough to make the atmel-hlcdc driver
do what I need. The rest is just lots of removals and cleanup made
possible by the improved core.

Please test, I would not be surprised if I have fouled up some
bit-manipulation somewhere, or if I have misunderstood something
about atomics...

Changes since v2:
- Added patch 1/16 which factors out pseudo-palette handling.
- Removed the if (cmap->start + cmap->len < cmap->start)
  sanity check on the assumption that the fbdev core handles it.
- Added patch 4/16 which factors out atomic state and commit
  handling from drm_atomic_helper_legacy_gamma_set to
  drm_mode_gamma_set_ioctl.
- Do one atomic commit for all affected crtc.
- Removed a now obsolete note in include/drm/drm_crtc.h (ammended
  the last patch).
- Cc list is getting long, so I have redused the list for the
  individual patches. If you would like to get the full series
  (or nothing at all) for the next round (if that is needed) just
  say so.

Changes since v1:

- Rebased to next-20170621
- Split 1/11 into a preparatory patch, a cleanup patch and then
  the meat in 3/14.
- Handle pseudo-palette for FB_VISUAL_TRUECOLOR.
- Removed the empty .gamma_get/.gamma_set fb helpers from the
  armada driver that I had somehow managed to ignore but which
  0day found real quick.
- Be less judgemental on drivers only providing .gamma_get and
  .gamma_set, but no .load_lut. That's actually a valid thing
  to do if you only need pseudo-palette for FB_VISUAL_TRUECOLOR.
- Add a comment about colliding bitfields in the nouveau driver.
- Remove gamma_set/gamma_get declarations from the radeon driver
  (the definitions were removed in v1).

Cheers,
peda

Peter Rosin (16):
  drm/fb-helper: factor out pseudo-palette
  drm/fb-helper: keep the .gamma_store updated in drm_fb_helper_setcmap
  drm/fb-helper: remove drm_fb_helper_save_lut_atomic
  drm/color-mgmt: move atomic state/commit out from .gamma_set
  drm/fb-helper: do a generic fb_setcmap helper in terms of crtc
.gamma_set
  drm: amd: remove dead code and pointless local lut storage
  drm: armada: remove dead empty functions
  drm: ast: remove dead code and pointless local lut storage
  drm: cirrus: remove dead code and pointless local lut storage
  drm: gma500: remove dead code and pointless local lut storage
  drm: i915: remove dead code and pointless local lut storage
  drm: mgag200: remove dead code and pointless local lut storage
  drm: nouveau: remove dead code and pointless local lut storage
  drm: radeon: remove dead code and pointless local lut storage
  drm: stm: remove dead code and pointless local lut storage
  drm: remove unused and redundant callbacks

 drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c  |  24 
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h|   1 -
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c  |  29 ++---
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c  |  29 ++---
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c   |  29 ++---
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c   |  29 ++---
 drivers/gpu/drm/amd/amdgpu/dce_virtual.c|  25 +---
 drivers/gpu/drm/armada/armada_crtc.c|  10 --
 drivers/gpu/drm/armada/armada_crtc.h|   2 -
 drivers/gpu/drm/armada/armada_fbdev.c   |   2 -
 drivers/gpu/drm/ast/ast_drv.h   |   1 -
 drivers/gpu/drm/ast/ast_fb.c|  20 ---
 drivers/gpu/drm/ast/ast_mode.c  |  28 +---
 drivers/gpu/drm/cirrus/cirrus_drv.h |   8 --
 drivers/gpu/drm/cirrus/cirrus_fbdev.c   |   2 -
 drivers/gpu/drm/cirrus/cirrus_mode.c|  73 +++
 drivers/gpu/drm/drm_atomic_helper.c |  37 ++
 drivers/gpu/drm/drm_color_mgmt.c|  27 +++-
 drivers/gpu/drm/drm_fb_helper.c | 195 +---
 drivers/gpu/drm/gma500/framebuffer.c|  22 
 drivers/gpu/drm/gma500/gma_display.c|  34 ++---
 drivers/gpu/drm/gma500/gma_display.h|   2 +-
 drivers/gpu/drm/gma500/psb_intel_display.c  |   7 +-
 drivers/gpu/drm/gma500/psb_intel_drv.h  |   1 -
 drivers/gpu/drm/i915/intel_drv.h|   1 -
 drivers/gpu/drm/i915/intel_fbdev.c  |  31 -
 drivers/gpu/drm/mgag200/mgag200_drv.h   |   5 -
 drivers/gpu/drm/mgag200/mgag200_fb.c|   2 -
 drivers/gpu/drm/mgag200/mgag200_mode.c  |  64 +++--
 drivers/gpu/drm/nouveau/dispnv04/crtc.c |  28 ++--
 drivers/gpu/drm/nouveau/nouveau_crtc.h  |   3 -
 drivers/gpu/drm/nouveau/nouveau_fbcon.c |  22 
 drivers/gpu/drm/nouveau/nv50_display.c  |  42 ++
 drivers/gpu/drm/radeon/atombios_crtc.c  |   1 -
 drivers/gpu/drm/radeon/radeon_connectors.c  |   7 +-
 drivers/gpu/drm/radeon/rade

[PATCH v3 03/16] drm/fb-helper: remove drm_fb_helper_save_lut_atomic

2017-07-04 Thread Peter Rosin
drm_fb_helper_save_lut_atomic is redundant since the .gamma_store is
now always kept up to date by drm_fb_helper_setcmap.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_fb_helper.c | 17 -
 1 file changed, 17 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 41fd9e0..b75b1f2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -253,22 +253,6 @@ int drm_fb_helper_remove_one_connector(struct 
drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
 
-static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct 
drm_fb_helper *helper)
-{
-   uint16_t *r_base, *g_base, *b_base;
-   int i;
-
-   if (helper->funcs->gamma_get == NULL)
-   return;
-
-   r_base = crtc->gamma_store;
-   g_base = r_base + crtc->gamma_size;
-   b_base = g_base + crtc->gamma_size;
-
-   for (i = 0; i < crtc->gamma_size; i++)
-   helper->funcs->gamma_get(crtc, _base[i], _base[i], 
_base[i], i);
-}
-
 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 {
uint16_t *r_base, *g_base, *b_base;
@@ -309,7 +293,6 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
continue;
 
-   drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
funcs->mode_set_base_atomic(mode_set->crtc,
mode_set->fb,
mode_set->x,
-- 
2.1.4



Re: [PATCH v3 01/16] drm/fb-helper: factor out pseudo-palette

2017-07-04 Thread Peter Rosin
On 2017-07-04 12:36, Peter Rosin wrote:
> The pseudo-palette has nothing to do with the crtc, so move it
> out of the crtc loop and update the palette once, then break out
> early.
> 
> Signed-off-by: Peter Rosin <p...@axenita.se>

Should of course be p...@axentia.se

I wonder when I managed to Ctrl-T that one?

Cheers,
peda


[PATCH v3 09/16] drm: cirrus: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/cirrus/cirrus_drv.h   |  8 
 drivers/gpu/drm/cirrus/cirrus_fbdev.c |  2 -
 drivers/gpu/drm/cirrus/cirrus_mode.c  | 71 ---
 3 files changed, 16 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h 
b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 8690352..be2d7e48 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -96,7 +96,6 @@
 
 struct cirrus_crtc {
struct drm_crtc base;
-   u8  lut_r[256], lut_g[256], lut_b[256];
int last_dpms;
boolenabled;
 };
@@ -180,13 +179,6 @@ cirrus_bo(struct ttm_buffer_object *bo)
 #define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base)
 #define DRM_FILE_PAGE_OFFSET (0x1ULL >> PAGE_SHIFT)
 
-   /* cirrus_mode.c */
-void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, int regno);
-void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-u16 *blue, int regno);
-
-
/* cirrus_main.c */
 int cirrus_device_init(struct cirrus_device *cdev,
  struct drm_device *ddev,
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c 
b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 7fa58ee..1fedab0 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -265,8 +265,6 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
 }
 
 static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
-   .gamma_set = cirrus_crtc_fb_gamma_set,
-   .gamma_get = cirrus_crtc_fb_gamma_get,
.fb_probe = cirrusfb_create,
 };
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c 
b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 2b4c2c3..92ff7de 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -31,25 +31,6 @@
  * This file contains setup code for the CRTC.
  */
 
-static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
-{
-   struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
-   struct drm_device *dev = crtc->dev;
-   struct cirrus_device *cdev = dev->dev_private;
-   int i;
-
-   if (!crtc->enabled)
-   return;
-
-   for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
-   /* VGA registers */
-   WREG8(PALETTE_INDEX, i);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_r[i]);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_g[i]);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_b[i]);
-   }
-}
-
 /*
  * The DRM core requires DPMS functions, but they make little sense in our
  * case and so are just stubs
@@ -330,15 +311,25 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, 
u16 *red, u16 *green,
 u16 *blue, uint32_t size,
 struct drm_crtc_state *state)
 {
-   struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+   struct drm_device *dev = crtc->dev;
+   struct cirrus_device *cdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
-   for (i = 0; i < size; i++) {
-   cirrus_crtc->lut_r[i] = red[i];
-   cirrus_crtc->lut_g[i] = green[i];
-   cirrus_crtc->lut_b[i] = blue[i];
+   if (!crtc->enabled)
+   return 0;
+
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
+   for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
+   /* VGA registers */
+   WREG8(PALETTE_INDEX, i);
+   WREG8(PALETTE_DATA, *r++ >> 8);
+   WREG8(PALETTE_DATA, *g++ >> 8);
+   WREG8(PALETTE_DATA, *b++ >> 8);
}
-   cirrus_crtc_load_lut(crtc);
 
return 0;
 }
@@ -365,7 +356,6 @@ static const struct drm_crtc_helper_funcs 
cirrus_helper_funcs = {
.mode_set_base = cirrus_crtc_mode_set_base,
.prepare = cirrus_crtc_prepare,
.commit = cirrus_crtc_commit,
-   .load_lut = cirrus_crtc_load_lut,
 };
 
 /* CRTC setup */
@@ -373,7 +363,6 @@ static void cirrus_crtc_init(struct drm_device *dev)
 {
struct cirrus_device *cdev = dev->dev_private;
struct cirrus_crtc *cirrus_crtc;
-   int i;
 
cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
  (CIRRUSFB_CONN_LIMIT * sizeof(struct 
drm_connector *)),
@@ -387,37 +376,9 @@ static void cirrus_crtc_init(st

[PATCH v3 13/16] drm: nouveau: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/nouveau/dispnv04/crtc.c | 26 -
 drivers/gpu/drm/nouveau/nouveau_crtc.h  |  3 ---
 drivers/gpu/drm/nouveau/nouveau_fbcon.c | 22 --
 drivers/gpu/drm/nouveau/nv50_display.c  | 40 +++--
 4 files changed, 22 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c 
b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index f562824..b233412 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -764,13 +764,18 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = nv_crtc->base.dev;
struct rgb { uint8_t r, g, b; } __attribute__((packed)) *rgbs;
+   u16 *r, *g, *b;
int i;
 
rgbs = (struct rgb 
*)nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].DAC;
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
for (i = 0; i < 256; i++) {
-   rgbs[i].r = nv_crtc->lut.r[i] >> 8;
-   rgbs[i].g = nv_crtc->lut.g[i] >> 8;
-   rgbs[i].b = nv_crtc->lut.b[i] >> 8;
+   rgbs[i].r = *r++ >> 8;
+   rgbs[i].g = *g++ >> 8;
+   rgbs[i].b = *b++ >> 8;
}
 
nouveau_hw_load_state_palette(dev, nv_crtc->index, 
_display(dev)->mode_reg);
@@ -792,13 +797,6 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, 
u16 *b,
  struct drm_crtc_state *state)
 {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   nv_crtc->lut.r[i] = r[i];
-   nv_crtc->lut.g[i] = g[i];
-   nv_crtc->lut.b[i] = b[i];
-   }
 
/* We need to know the depth before we upload, but it's possible to
 * get called before a framebuffer is bound.  If this is the case,
@@ -1095,7 +1093,6 @@ static const struct drm_crtc_helper_funcs 
nv04_crtc_helper_funcs = {
.mode_set = nv_crtc_mode_set,
.mode_set_base = nv04_crtc_mode_set_base,
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
-   .load_lut = nv_crtc_gamma_load,
.disable = nv_crtc_disable,
 };
 
@@ -1103,17 +1100,12 @@ int
 nv04_crtc_create(struct drm_device *dev, int crtc_num)
 {
struct nouveau_crtc *nv_crtc;
-   int ret, i;
+   int ret;
 
nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
if (!nv_crtc)
return -ENOMEM;
 
-   for (i = 0; i < 256; i++) {
-   nv_crtc->lut.r[i] = i << 8;
-   nv_crtc->lut.g[i] = i << 8;
-   nv_crtc->lut.b[i] = i << 8;
-   }
nv_crtc->lut.depth = 0;
 
nv_crtc->index = crtc_num;
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h 
b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 050fcf3..b7a18fb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -61,9 +61,6 @@ struct nouveau_crtc {
 
struct {
struct nouveau_bo *nvbo;
-   uint16_t r[256];
-   uint16_t g[256];
-   uint16_t b[256];
int depth;
} lut;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c 
b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 2665a07..f770784 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -278,26 +278,6 @@ nouveau_fbcon_accel_init(struct drm_device *dev)
info->fbops = _fbcon_ops;
 }
 
-static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
-   nv_crtc->lut.r[regno] = red;
-   nv_crtc->lut.g[regno] = green;
-   nv_crtc->lut.b[regno] = blue;
-}
-
-static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
-   u16 *blue, int regno)
-{
-   struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
-   *red = nv_crtc->lut.r[regno];
-   *green = nv_crtc->lut.g[regno];
-   *blue = nv_crtc->lut.b[regno];
-}
-
 static void
 nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
@@ -467,8 +447,6 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
 }
 
 static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
-   .gamma_set = nouveau_fbcon_gamma_set,
-   .gamma_get = nouveau_fbcon_gamma_get,

[PATCH v3 11/16] drm: i915: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The driver stores lut values from the fbdev interface, and is able
to give them back, but does not appear to do anything with these
lut values. The generic fb helpers have replaced this function,
and may even have made the driver work for the C8 mode from the
fbdev interface. But that is untested.

Since the fb helpers .gamma_set and .gamma_get are obsolete,
remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/i915/intel_drv.h   |  1 -
 drivers/gpu/drm/i915/intel_fbdev.c | 31 ---
 2 files changed, 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d93efb4..bc7bfa0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -786,7 +786,6 @@ struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
enum plane plane;
-   u8 lut_r[256], lut_g[256], lut_b[256];
/*
 * Whether the crtc and the connected output pipeline is active. Implies
 * that crtc->enabled is set, i.e. the current mode configuration has
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c 
b/drivers/gpu/drm/i915/intel_fbdev.c
index 03347c6..5bac953 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -281,27 +281,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
return ret;
 }
 
-/** Sets the color ramps on behalf of RandR */
-static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-   intel_crtc->lut_r[regno] = red >> 8;
-   intel_crtc->lut_g[regno] = green >> 8;
-   intel_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
-   u16 *blue, int regno)
-{
-   struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-   *red = intel_crtc->lut_r[regno] << 8;
-   *green = intel_crtc->lut_g[regno] << 8;
-   *blue = intel_crtc->lut_b[regno] << 8;
-}
-
 static struct drm_fb_helper_crtc *
 intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
 {
@@ -370,7 +349,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_fb_helper_crtc *new_crtc;
-   struct intel_crtc *intel_crtc;
 
fb_conn = fb_helper->connector_info[i];
connector = fb_conn->connector;
@@ -412,13 +390,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
 
num_connectors_enabled++;
 
-   intel_crtc = to_intel_crtc(connector->state->crtc);
-   for (j = 0; j < 256; j++) {
-   intel_crtc->lut_r[j] = j;
-   intel_crtc->lut_g[j] = j;
-   intel_crtc->lut_b[j] = j;
-   }
-
new_crtc = intel_fb_helper_crtc(fb_helper,
connector->state->crtc);
 
@@ -519,8 +490,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
 
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
.initial_config = intel_fb_initial_config,
-   .gamma_set = intel_crtc_fb_gamma_set,
-   .gamma_get = intel_crtc_fb_gamma_get,
.fb_probe = intelfb_create,
 };
 
-- 
2.1.4



[PATCH v3 14/16] drm: radeon: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/radeon/atombios_crtc.c  |  1 -
 drivers/gpu/drm/radeon/radeon_connectors.c  |  7 ++-
 drivers/gpu/drm/radeon/radeon_display.c | 71 -
 drivers/gpu/drm/radeon/radeon_fb.c  |  2 -
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c |  1 -
 drivers/gpu/drm/radeon/radeon_mode.h|  4 --
 6 files changed, 33 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c 
b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3c492a0..02baaaf 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -2217,7 +2217,6 @@ static const struct drm_crtc_helper_funcs 
atombios_helper_funcs = {
.mode_set_base_atomic = atombios_crtc_set_base_atomic,
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
-   .load_lut = radeon_crtc_load_lut,
.disable = atombios_crtc_disable,
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c 
b/drivers/gpu/drm/radeon/radeon_connectors.c
index 27affbd..2f642cb 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -773,12 +773,15 @@ static int radeon_connector_set_property(struct 
drm_connector *connector, struct
 
if (connector->encoder->crtc) {
struct drm_crtc *crtc  = connector->encoder->crtc;
-   const struct drm_crtc_helper_funcs *crtc_funcs = 
crtc->helper_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 
radeon_crtc->output_csc = radeon_encoder->output_csc;
 
-   (*crtc_funcs->load_lut)(crtc);
+   /*
+* Our .gamma_set assumes the .gamma_store has been
+* prefilled and don't care about its arguments.
+*/
+   crtc->funcs->gamma_set(crtc, NULL, NULL, NULL, 0, NULL);
}
}
 
diff --git a/drivers/gpu/drm/radeon/radeon_display.c 
b/drivers/gpu/drm/radeon/radeon_display.c
index 0ea575d..3d7394d4 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -42,6 +42,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
@@ -60,11 +61,14 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x003f);
 
WREG8(AVIVO_DC_LUT_RW_INDEX, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(AVIVO_DC_LUT_30_COLOR,
-(radeon_crtc->lut_r[i] << 20) |
-(radeon_crtc->lut_g[i] << 10) |
-(radeon_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 
/* Only change bit 0 of LUT_SEL, other bits are set elsewhere */
@@ -76,6 +80,7 @@ static void dce4_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
@@ -93,11 +98,14 @@ static void dce4_crtc_load_lut(struct drm_crtc *crtc)
WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 
0x0007);
 
WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset,
-  (radeon_crtc->lut_r[i] << 20) |
-  (radeon_crtc->lut_g[i] << 10) |
-  (radeon_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 }
 
@@ -106,6 +114,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
struct rad

[PATCH v3 16/16] drm: remove unused and redundant callbacks

2017-07-04 Thread Peter Rosin
Drivers no longer have any need for these callbacks, and there are no
users. Zap. Zap-zap-zzzap-p-pp-p.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 include/drm/drm_crtc.h   |  8 
 include/drm/drm_fb_helper.h  | 32 
 include/drm/drm_modeset_helper_vtables.h | 16 
 3 files changed, 56 deletions(-)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index d442d30..7bb0a6e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -358,14 +358,6 @@ struct drm_crtc_funcs {
 * drm_crtc_enable_color_mgmt(), which then supports the legacy gamma
 * interface through the drm_atomic_helper_legacy_gamma_set()
 * compatibility implementation.
-*
-* NOTE:
-*
-* Drivers that support gamma tables and also fbdev emulation through
-* the provided helper library need to take care to fill out the gamma
-* hooks for both. Currently there's a bit an unfortunate duplication
-* going on, which should eventually be unified to just one set of
-* hooks.
 */
int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
 uint32_t size, struct drm_crtc_state *state);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index a5ea6ff..33fe959 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -85,38 +85,6 @@ struct drm_fb_helper_surface_size {
  */
 struct drm_fb_helper_funcs {
/**
-* @gamma_set:
-*
-* Set the given gamma LUT register on the given CRTC.
-*
-* This callback is optional.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
- u16 blue, int regno);
-   /**
-* @gamma_get:
-*
-* Read the given gamma LUT register on the given CRTC, used to save the
-* current LUT when force-restoring the fbdev for e.g. kdbg.
-*
-* This callback is optional.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, int regno);
-
-   /**
 * @fb_probe:
 *
 * Driver callback to allocate and initialize the fbdev info structure.
diff --git a/include/drm/drm_modeset_helper_vtables.h 
b/include/drm/drm_modeset_helper_vtables.h
index 85984b2..0773db9 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -267,22 +267,6 @@ struct drm_crtc_helper_funcs {
enum mode_set_atomic);
 
/**
-* @load_lut:
-*
-* Load a LUT prepared with the _fb_helper_funcs.gamma_set vfunc.
-*
-* This callback is optional and is only used by the fbdev emulation
-* helpers.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*load_lut)(struct drm_crtc *crtc);
-
-   /**
 * @disable:
 *
 * This callback should be used to disable the CRTC. With the atomic
-- 
2.1.4



[PATCH v3 10/16] drm: gma500: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .gamma_set and .gamma_get are no longer
used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/gma500/framebuffer.c   | 22 
 drivers/gpu/drm/gma500/gma_display.c   | 32 ++
 drivers/gpu/drm/gma500/psb_intel_display.c |  7 +--
 drivers/gpu/drm/gma500/psb_intel_drv.h |  1 -
 4 files changed, 12 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/gma500/framebuffer.c 
b/drivers/gpu/drm/gma500/framebuffer.c
index 7da70b6..2570c7f 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -479,26 +479,6 @@ static struct drm_framebuffer *psb_user_framebuffer_create
return psb_framebuffer_create(dev, cmd, r);
 }
 
-static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-
-   gma_crtc->lut_r[regno] = red >> 8;
-   gma_crtc->lut_g[regno] = green >> 8;
-   gma_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
-   u16 *green, u16 *blue, int regno)
-{
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-
-   *red = gma_crtc->lut_r[regno] << 8;
-   *green = gma_crtc->lut_g[regno] << 8;
-   *blue = gma_crtc->lut_b[regno] << 8;
-}
-
 static int psbfb_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
 {
@@ -525,8 +505,6 @@ static int psbfb_probe(struct drm_fb_helper *helper,
 }
 
 static const struct drm_fb_helper_funcs psb_fb_helper_funcs = {
-   .gamma_set = psbfb_gamma_set,
-   .gamma_get = psbfb_gamma_get,
.fb_probe = psbfb_probe,
 };
 
diff --git a/drivers/gpu/drm/gma500/gma_display.c 
b/drivers/gpu/drm/gma500/gma_display.c
index ccf8c33..3bf65d4 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -144,33 +144,32 @@ void gma_crtc_load_lut(struct drm_crtc *crtc)
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
const struct psb_offset *map = _priv->regmap[gma_crtc->pipe];
int palreg = map->palette;
+   u16 *r, *g, *b;
int i;
 
/* The clocks have to be on to load the palette. */
if (!crtc->enabled)
return;
 
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
if (gma_power_begin(dev, false)) {
for (i = 0; i < 256; i++) {
REG_WRITE(palreg + 4 * i,
- ((gma_crtc->lut_r[i] +
- gma_crtc->lut_adj[i]) << 16) |
- ((gma_crtc->lut_g[i] +
- gma_crtc->lut_adj[i]) << 8) |
- (gma_crtc->lut_b[i] +
- gma_crtc->lut_adj[i]));
+ (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
+ (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
+ ((*b++ >> 8) + gma_crtc->lut_adj[i]));
}
gma_power_end(dev);
} else {
for (i = 0; i < 256; i++) {
/* FIXME: Why pipe[0] and not pipe[..._crtc->pipe]? */
dev_priv->regs.pipe[0].palette[i] =
- ((gma_crtc->lut_r[i] +
- gma_crtc->lut_adj[i]) << 16) |
- ((gma_crtc->lut_g[i] +
- gma_crtc->lut_adj[i]) << 8) |
- (gma_crtc->lut_b[i] +
- gma_crtc->lut_adj[i]);
+   (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
+   (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
+   ((*b++ >> 8) + gma_crtc->lut_adj[i]);
}
 
}
@@ -180,15 +179,6 @@ int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, 
u16 *green, u16 *blue,
   u32 size,
   struct drm_crtc_state *state)
 {
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   gma_crtc->lut_r[i] = red[i] >> 8;
-   gma_crtc->lut_g[i] = green[i] >> 8;
-   gma_crtc->lut_b[i] = blue[i] >> 8;
-   }
-
 

[PATCH v3 08/16] drm: ast: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/ast/ast_drv.h  |  1 -
 drivers/gpu/drm/ast/ast_fb.c   | 20 
 drivers/gpu/drm/ast/ast_mode.c | 26 ++
 3 files changed, 6 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 8880f0b..569a148 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -245,7 +245,6 @@ struct ast_connector {
 
 struct ast_crtc {
struct drm_crtc base;
-   u8 lut_r[256], lut_g[256], lut_b[256];
struct drm_gem_object *cursor_bo;
uint64_t cursor_addr;
int cursor_width, cursor_height;
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 4ad4acd..dbabcac 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -255,27 +255,7 @@ static int astfb_create(struct drm_fb_helper *helper,
return ret;
 }
 
-static void ast_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-  u16 blue, int regno)
-{
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   ast_crtc->lut_r[regno] = red >> 8;
-   ast_crtc->lut_g[regno] = green >> 8;
-   ast_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-  u16 *blue, int regno)
-{
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   *red = ast_crtc->lut_r[regno] << 8;
-   *green = ast_crtc->lut_g[regno] << 8;
-   *blue = ast_crtc->lut_b[regno] << 8;
-}
-
 static const struct drm_fb_helper_funcs ast_fb_helper_funcs = {
-   .gamma_set = ast_fb_gamma_set,
-   .gamma_get = ast_fb_gamma_get,
.fb_probe = astfb_create,
 };
 
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 6f0335b..e686072 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -63,15 +63,18 @@ static inline void ast_load_palette_index(struct 
ast_private *ast,
 static void ast_crtc_load_lut(struct drm_crtc *crtc)
 {
struct ast_private *ast = crtc->dev->dev_private;
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+   u16 *r, *g, *b;
int i;
 
if (!crtc->enabled)
return;
 
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
for (i = 0; i < 256; i++)
-   ast_load_palette_index(ast, i, ast_crtc->lut_r[i],
-  ast_crtc->lut_g[i], ast_crtc->lut_b[i]);
+   ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8);
 }
 
 static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct 
drm_display_mode *mode,
@@ -633,7 +636,6 @@ static const struct drm_crtc_helper_funcs 
ast_crtc_helper_funcs = {
.mode_set = ast_crtc_mode_set,
.mode_set_base = ast_crtc_mode_set_base,
.disable = ast_crtc_disable,
-   .load_lut = ast_crtc_load_lut,
.prepare = ast_crtc_prepare,
.commit = ast_crtc_commit,
 
@@ -648,15 +650,6 @@ static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 
*red, u16 *green,
  u16 *blue, uint32_t size,
  struct drm_crtc_state *state)
 {
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   int i;
-
-   /* userspace palettes are always correct as is */
-   for (i = 0; i < size; i++) {
-   ast_crtc->lut_r[i] = red[i] >> 8;
-   ast_crtc->lut_g[i] = green[i] >> 8;
-   ast_crtc->lut_b[i] = blue[i] >> 8;
-   }
ast_crtc_load_lut(crtc);
 
return 0;
@@ -681,7 +674,6 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
 static int ast_crtc_init(struct drm_device *dev)
 {
struct ast_crtc *crtc;
-   int i;
 
crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
if (!crtc)
@@ -690,12 +682,6 @@ static int ast_crtc_init(struct drm_device *dev)
drm_crtc_init(dev, >base, _crtc_funcs);
drm_mode_crtc_set_gamma_size(>base, 256);
drm_crtc_helper_add(>base, _crtc_helper_funcs);
-
-   for (i = 0; i < 256; i++) {
-   crtc->lut_r[i] = i;
-   crtc->lut_g[i] = i;
-   crtc->lut_b[i] = i;
-   }
return 0;
 }
 
-- 
2.1.4



[PATCH v3 12/16] drm: mgag200: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  5 ---
 drivers/gpu/drm/mgag200/mgag200_fb.c   |  2 --
 drivers/gpu/drm/mgag200/mgag200_mode.c | 62 --
 3 files changed, 15 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index c88b6ec..04f1dfb 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -237,11 +237,6 @@ mgag200_bo(struct ttm_buffer_object *bo)
 {
return container_of(bo, struct mgag200_bo, bo);
 }
-   /* mgag200_crtc.c */
-void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, int regno);
-void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-u16 *blue, int regno);
 
/* mgag200_mode.c */
 int mgag200_modeset_init(struct mga_device *mdev);
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c 
b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 5d3b1fa..5cf980a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -258,8 +258,6 @@ static int mga_fbdev_destroy(struct drm_device *dev,
 }
 
 static const struct drm_fb_helper_funcs mga_fb_helper_funcs = {
-   .gamma_set = mga_crtc_fb_gamma_set,
-   .gamma_get = mga_crtc_fb_gamma_get,
.fb_probe = mgag200fb_create,
 };
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 2141796..dc500ef 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -27,15 +27,19 @@
 
 static void mga_crtc_load_lut(struct drm_crtc *crtc)
 {
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
+   u16 *r_ptr, *g_ptr, *b_ptr;
int i;
 
if (!crtc->enabled)
return;
 
+   r_ptr = crtc->gamma_store;
+   g_ptr = r_ptr + crtc->gamma_size;
+   b_ptr = g_ptr + crtc->gamma_size;
+
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
 
if (fb && fb->format->cpp[0] * 8 == 16) {
@@ -46,25 +50,27 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
if (i > (MGAG200_LUT_SIZE >> 1)) {
r = b = 0;
} else {
-   r = mga_crtc->lut_r[i << 1];
-   b = mga_crtc->lut_b[i << 1];
+   r = *r_ptr++ >> 8;
+   b = *b_ptr++ >> 8;
+   r_ptr++;
+   b_ptr++;
}
} else {
-   r = mga_crtc->lut_r[i];
-   b = mga_crtc->lut_b[i];
+   r = *r_ptr++ >> 8;
+   b = *b_ptr++ >> 8;
}
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
}
return;
}
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
/* VGA registers */
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_b[i]);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8);
}
 }
 
@@ -1399,14 +1405,6 @@ static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 
*red, u16 *green,
  u16 *blue, uint32_t size,
  struct drm_crtc_state *state)
 {
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   mga_crtc->lut_r[i] = red[i] >> 8;
-   mga_crtc->lut_g[i] = green[i] >> 8;
-   mga_crtc->lut_b[i] = blue[i] >> 8;
-  

[PATCH v3 15/16] drm: stm: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helper .load_lut is no longer used, and can not
work right without also providing the fb helpers .gamma_set and
.gamma_get thus rendering the code in this driver suspect.

Just remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/stm/ltdc.c | 12 
 drivers/gpu/drm/stm/ltdc.h |  1 -
 2 files changed, 13 deletions(-)

diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 1b9483d..87829b9 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -375,17 +375,6 @@ static irqreturn_t ltdc_irq(int irq, void *arg)
  * DRM_CRTC
  */
 
-static void ltdc_crtc_load_lut(struct drm_crtc *crtc)
-{
-   struct ltdc_device *ldev = crtc_to_ltdc(crtc);
-   unsigned int i, lay;
-
-   for (lay = 0; lay < ldev->caps.nb_layers; lay++)
-   for (i = 0; i < 256; i++)
-   reg_write(ldev->regs, LTDC_L1CLUTWR + lay * LAY_OFS,
- ldev->clut[i]);
-}
-
 static void ltdc_crtc_enable(struct drm_crtc *crtc)
 {
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
@@ -523,7 +512,6 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
 }
 
 static struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
-   .load_lut = ltdc_crtc_load_lut,
.enable = ltdc_crtc_enable,
.disable = ltdc_crtc_disable,
.mode_set_nofb = ltdc_crtc_mode_set_nofb,
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index d7a9c73..620ca55 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -27,7 +27,6 @@ struct ltdc_device {
struct drm_panel *panel;
struct mutex err_lock;  /* protecting error_status */
struct ltdc_caps caps;
-   u32 clut[256];  /* color look up table */
u32 error_status;
u32 irq_status;
 };
-- 
2.1.4



[PATCH v3 04/16] drm/color-mgmt: move atomic state/commit out from .gamma_set

2017-07-04 Thread Peter Rosin
Handle the atomics directly in the ioctl instead, in preparation for the
fb_setcmap helper needing to commit the gamma map for several crtc in one
commit.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c   |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c|  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c|  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_virtual.c |  2 +-
 drivers/gpu/drm/ast/ast_mode.c   |  2 +-
 drivers/gpu/drm/cirrus/cirrus_mode.c |  2 +-
 drivers/gpu/drm/drm_atomic_helper.c  | 37 +++-
 drivers/gpu/drm/drm_color_mgmt.c | 27 ++-
 drivers/gpu/drm/gma500/gma_display.c |  2 +-
 drivers/gpu/drm/gma500/gma_display.h |  2 +-
 drivers/gpu/drm/mgag200/mgag200_mode.c   |  2 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c  |  2 +-
 drivers/gpu/drm/nouveau/nv50_display.c   |  2 +-
 drivers/gpu/drm/radeon/radeon_display.c  |  2 +-
 drivers/gpu/drm/vc4/vc4_crtc.c   |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c  |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h  |  2 +-
 include/drm/drm_atomic_helper.h  |  2 +-
 include/drm/drm_crtc.h   |  3 +--
 20 files changed, 52 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 9f78c03..31c977b 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -2622,7 +2622,7 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
 
 static int dce_v10_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 
*green,
u16 *blue, uint32_t size,
-   struct drm_modeset_acquire_ctx *ctx)
+   struct drm_crtc_state *state)
 {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int i;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 4bcf01d..cf42640 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -2642,7 +2642,7 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
 
 static int dce_v11_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 
*green,
u16 *blue, uint32_t size,
-   struct drm_modeset_acquire_ctx *ctx)
+   struct drm_crtc_state *state)
 {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int i;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index fd134a4..045014d 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -2494,7 +2494,7 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
 
 static int dce_v6_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
   u16 *blue, uint32_t size,
-  struct drm_modeset_acquire_ctx *ctx)
+  struct drm_crtc_state *state)
 {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int i;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index a9e8695..ee9389f 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -2473,7 +2473,7 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
 
 static int dce_v8_0_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
   u16 *blue, uint32_t size,
-  struct drm_modeset_acquire_ctx *ctx)
+  struct drm_crtc_state *state)
 {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int i;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c 
b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
index 90bb083..f194dfc 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
@@ -166,7 +166,7 @@ static void dce_virtual_bandwidth_update(struct 
amdgpu_device *adev)
 
 static int dce_virtual_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
  u16 *green, u16 *blue, uint32_t size,
- struct drm_modeset_acquire_ctx *ctx)
+ struct drm_crtc_state *state)
 {
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int i;
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index aaef0a6..6f0335b 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -646,7 +646,7 @@ static void ast_crtc_reset(struct drm_crtc *crtc)
 
 static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
  u16

[PATCH v3 06/16] drm: amd: remove dead code and pointless local lut storage

2017-07-04 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c   | 24 
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h |  1 -
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c   | 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c   | 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c| 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c| 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 23 ---
 7 files changed, 28 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
index c0d8c6f..7dc3780 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -312,31 +312,7 @@ static int amdgpu_fbdev_destroy(struct drm_device *dev, 
struct amdgpu_fbdev *rfb
return 0;
 }
 
-/** Sets the color ramps on behalf of fbcon */
-static void amdgpu_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
- u16 blue, int regno)
-{
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-
-   amdgpu_crtc->lut_r[regno] = red >> 6;
-   amdgpu_crtc->lut_g[regno] = green >> 6;
-   amdgpu_crtc->lut_b[regno] = blue >> 6;
-}
-
-/** Gets the color ramps on behalf of fbcon */
-static void amdgpu_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
- u16 *blue, int regno)
-{
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-
-   *red = amdgpu_crtc->lut_r[regno] << 6;
-   *green = amdgpu_crtc->lut_g[regno] << 6;
-   *blue = amdgpu_crtc->lut_b[regno] << 6;
-}
-
 static const struct drm_fb_helper_funcs amdgpu_fb_helper_funcs = {
-   .gamma_set = amdgpu_crtc_fb_gamma_set,
-   .gamma_get = amdgpu_crtc_fb_gamma_get,
.fb_probe = amdgpufb_create,
 };
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 43a9d3a..39f7eda 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -369,7 +369,6 @@ struct amdgpu_atom_ss {
 struct amdgpu_crtc {
struct drm_crtc base;
int crtc_id;
-   u16 lut_r[256], lut_g[256], lut_b[256];
bool enabled;
bool can_tile;
uint32_t crtc_offset;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 31c977b..717be5f 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -2267,6 +2267,7 @@ static void dce_v10_0_crtc_load_lut(struct drm_crtc *crtc)
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct amdgpu_device *adev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
u32 tmp;
 
@@ -2304,11 +2305,14 @@ static void dce_v10_0_crtc_load_lut(struct drm_crtc 
*crtc)
WREG32(mmDC_LUT_WRITE_EN_MASK + amdgpu_crtc->crtc_offset, 0x0007);
 
WREG32(mmDC_LUT_RW_INDEX + amdgpu_crtc->crtc_offset, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(mmDC_LUT_30_COLOR + amdgpu_crtc->crtc_offset,
-  (amdgpu_crtc->lut_r[i] << 20) |
-  (amdgpu_crtc->lut_g[i] << 10) |
-  (amdgpu_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 
tmp = RREG32(mmDEGAMMA_CONTROL + amdgpu_crtc->crtc_offset);
@@ -2624,15 +2628,6 @@ static int dce_v10_0_crtc_gamma_set(struct drm_crtc 
*crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size,
struct drm_crtc_state *state)
 {
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-   int i;
-
-   /* userspace palettes are always correct as is */
-   for (i = 0; i < size; i++) {
-   amdgpu_crtc->lut_r[i] = red[i] >> 6;
-   amdgpu_crtc->lut_g[i] = green[i] >> 6;
-   amdgpu_crtc->lut_b[i] = blue[i] >> 6;
-   }
dce_v10_0_crtc_load_lut(crtc);
 
return 0;
@@ -2844,14 +2839,12 @@ static const struct drm_crtc_helper_funcs 
dce_v10_0_crtc_helper_funcs = {
.mode_set_base_atomic = dce_v10_0_crtc_set_base_atomic,
.prepare = dce_v10_0_crtc_prepare,
.commi

[PATCH v3 02/16] drm/fb-helper: keep the .gamma_store updated in drm_fb_helper_setcmap

2017-07-04 Thread Peter Rosin
I think the gamma_store can end up invalid on error. But the way I read
it, that can happen in drm_mode_gamma_set_ioctl as well, so why should
this pesky legacy fbdev stuff be any better?

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_fb_helper.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 9c76b8c..41fd9e0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1339,6 +1339,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct 
fb_info *info)
const struct drm_crtc_helper_funcs *crtc_funcs;
u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc;
+   u16 *r, *g, *b;
int i, j, rc = 0;
int start;
 
@@ -1367,6 +1368,24 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct 
fb_info *info)
transp = cmap->transp;
start = cmap->start;
 
+   if (!crtc->gamma_size) {
+   rc = -EINVAL;
+   goto out;
+   }
+
+   if (cmap->start + cmap->len > crtc->gamma_size) {
+   rc = -EINVAL;
+   goto out;
+   }
+
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
+   memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
+   memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
+   memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
+
for (j = 0; j < cmap->len; j++) {
u16 hred, hgreen, hblue, htransp = 0x;
 
-- 
2.1.4



[PATCH v3 07/16] drm: armada: remove dead empty functions

2017-07-04 Thread Peter Rosin
The redundant fb helpers .gamma_set and .gamma_get are no longer used.
Remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/armada/armada_crtc.c  | 10 --
 drivers/gpu/drm/armada/armada_crtc.h  |  2 --
 drivers/gpu/drm/armada/armada_fbdev.c |  2 --
 3 files changed, 14 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c 
b/drivers/gpu/drm/armada/armada_crtc.c
index 4fe19fd..96bccf8 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -334,16 +334,6 @@ static void armada_drm_vblank_off(struct armada_crtc 
*dcrtc)
armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
 }
 
-void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
-   int idx)
-{
-}
-
-void armada_drm_crtc_gamma_get(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-   int idx)
-{
-}
-
 /* The mode_config.mutex will be held for this call */
 static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)
 {
diff --git a/drivers/gpu/drm/armada/armada_crtc.h 
b/drivers/gpu/drm/armada/armada_crtc.h
index 7e8906d..bab11f4 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -102,8 +102,6 @@ struct armada_crtc {
 };
 #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
 
-void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
-void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
 void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
 
 void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c 
b/drivers/gpu/drm/armada/armada_fbdev.c
index 602dfea..5fa076d 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -118,8 +118,6 @@ static int armada_fb_probe(struct drm_fb_helper *fbh,
 }
 
 static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
-   .gamma_set  = armada_drm_crtc_gamma_set,
-   .gamma_get  = armada_drm_crtc_gamma_get,
.fb_probe   = armada_fb_probe,
 };
 
-- 
2.1.4



[PATCH v3 01/16] drm/fb-helper: factor out pseudo-palette

2017-07-04 Thread Peter Rosin
The pseudo-palette has nothing to do with the crtc, so move it
out of the crtc loop and update the palette once, then break out
early.

Signed-off-by: Peter Rosin <p...@axenita.se>
---
 drivers/gpu/drm/drm_fb_helper.c | 60 +
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a4cfef9..9c76b8c 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1280,29 +1280,6 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 
green,
struct drm_fb_helper *fb_helper = info->par;
struct drm_framebuffer *fb = fb_helper->fb;
 
-   if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
-   u32 *palette;
-   u32 value;
-   /* place color in psuedopalette */
-   if (regno > 16)
-   return -EINVAL;
-   palette = (u32 *)info->pseudo_palette;
-   red >>= (16 - info->var.red.length);
-   green >>= (16 - info->var.green.length);
-   blue >>= (16 - info->var.blue.length);
-   value = (red << info->var.red.offset) |
-   (green << info->var.green.offset) |
-   (blue << info->var.blue.offset);
-   if (info->var.transp.length > 0) {
-   u32 mask = (1 << info->var.transp.length) - 1;
-
-   mask <<= info->var.transp.offset;
-   value |= mask;
-   }
-   palette[regno] = value;
-   return 0;
-   }
-
/*
 * The driver really shouldn't advertise pseudo/directcolor
 * visuals if it can't deal with the palette.
@@ -1318,6 +1295,38 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 
green,
return 0;
 }
 
+static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
+{
+   u32 *palette = (u32 *)info->pseudo_palette;
+   int i;
+
+   if (cmap->start + cmap->len > 16)
+   return -EINVAL;
+
+   for (i = 0; i < cmap->len; ++i) {
+   u16 red = cmap->red[i];
+   u16 green = cmap->green[i];
+   u16 blue = cmap->blue[i];
+   u32 value;
+
+   red >>= 16 - info->var.red.length;
+   green >>= 16 - info->var.green.length;
+   blue >>= 16 - info->var.blue.length;
+   value = (red << info->var.red.offset) |
+   (green << info->var.green.offset) |
+   (blue << info->var.blue.offset);
+   if (info->var.transp.length > 0) {
+   u32 mask = (1 << info->var.transp.length) - 1;
+
+   mask <<= info->var.transp.offset;
+   value |= mask;
+   }
+   palette[cmap->start + i] = value;
+   }
+
+   return 0;
+}
+
 /**
  * drm_fb_helper_setcmap - implementation for _ops.fb_setcmap
  * @cmap: cmap to set
@@ -1343,6 +1352,11 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct 
fb_info *info)
}
 
drm_modeset_lock_all(dev);
+   if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+   rc = setcmap_pseudo_palette(cmap, info);
+   goto out;
+   }
+
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
crtc_funcs = crtc->helper_private;
-- 
2.1.4



[PATCH] drm: atmel-hlcdc: use a default gamma ramp if none is specified

2017-07-03 Thread Peter Rosin
At init and if the gamma_lut property is ever removed, the clut
registers must be programmed with a default gamma ramp instead of
being left in some unknown state.

Fixes: 364a7bf574eb ("drm: atmel-hlcdc: add support for 8-bit color lookup 
table mode")
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c 
b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index b5bd9b0..0ccd93c 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -429,6 +429,14 @@ static void atmel_hlcdc_plane_update_format(struct 
atmel_hlcdc_plane *plane,
ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
 }
 
+static void atmel_hlcdc_default_gamma_ramp(struct atmel_hlcdc_layer *layer)
+{
+   int idx;
+
+   for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++)
+   atmel_hlcdc_layer_write_clut(layer, idx, idx * 0x10101);
+}
+
 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane)
 {
struct drm_crtc *crtc = plane->base.crtc;
@@ -438,9 +446,14 @@ static void atmel_hlcdc_plane_update_clut(struct 
atmel_hlcdc_plane *plane)
if (!crtc || !crtc->state)
return;
 
-   if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
+   if (!crtc->state->color_mgmt_changed)
return;
 
+   if (!crtc->state->gamma_lut) {
+   atmel_hlcdc_default_gamma_ramp(>layer);
+   return;
+   }
+
lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
 
for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
@@ -918,6 +931,8 @@ static int atmel_hlcdc_plane_init_properties(struct 
atmel_hlcdc_plane *plane,
0x40040890);
}
 
+   atmel_hlcdc_default_gamma_ramp(>layer);
+
return 0;
 }
 
-- 
2.1.4



Re: [PATCH] drm: atmel-hlcdc: use a default gamma ramp if none is specified

2017-07-03 Thread Peter Rosin
On 2017-07-03 13:31, Boris Brezillon wrote:
> On Mon,  3 Jul 2017 11:42:10 +0200
> Peter Rosin <p...@axentia.se> wrote:
> 
>> At init and if the gamma_lut property is ever removed, the clut
>> registers must be programmed with a default gamma ramp instead of
>> being left in some unknown state.
>>
>> Fixes: 364a7bf574eb ("drm: atmel-hlcdc: add support for 8-bit color lookup 
>> table mode")
>> Signed-off-by: Peter Rosin <p...@axentia.se>
>> ---
>>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 17 -
>>  1 file changed, 16 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c 
>> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> index b5bd9b0..0ccd93c 100644
>> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
>> @@ -429,6 +429,14 @@ static void atmel_hlcdc_plane_update_format(struct 
>> atmel_hlcdc_plane *plane,
>>  ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
>>  }
>>  
>> +static void atmel_hlcdc_default_gamma_ramp(struct atmel_hlcdc_layer *layer)
>> +{
>> +int idx;
>> +
>> +for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++)
>> +atmel_hlcdc_layer_write_clut(layer, idx, idx * 0x10101);
>> +}
>> +
>>  static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane)
>>  {
>>  struct drm_crtc *crtc = plane->base.crtc;
>> @@ -438,9 +446,14 @@ static void atmel_hlcdc_plane_update_clut(struct 
>> atmel_hlcdc_plane *plane)
>>  if (!crtc || !crtc->state)
>>  return;
>>  
>> -if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
>> +if (!crtc->state->color_mgmt_changed)
>>  return;
>>  
>> +if (!crtc->state->gamma_lut) {
>> +atmel_hlcdc_default_gamma_ramp(>layer);
> 
> Hm, I'd prefer to have state->gamma_lut properly initialized in
> atmel_hlcdc_crtc_reset(), this way you don't have to do that in the
> update path.

The gamma_lut property can be removed, so you have to handle it here anyway. No?

Cheers,
peda

>> +return;
>> +}
>> +
>>  lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
>>  
>>  for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
>> @@ -918,6 +931,8 @@ static int atmel_hlcdc_plane_init_properties(struct 
>> atmel_hlcdc_plane *plane,
>>  0x40040890);
>>  }
>>  
>> +atmel_hlcdc_default_gamma_ramp(>layer);
>> +
>>  return 0;
>>  }
>>  
> 



Re: [Intel-gfx] [PATCH v3 00/16] improve the fb_setcmap helper

2017-07-05 Thread Peter Rosin
On 2017-07-05 08:08, Daniel Vetter wrote:
> On Tue, Jul 04, 2017 at 12:36:56PM +0200, Peter Rosin wrote:
>> Hi!
>>
>> While trying to get CLUT support for the atmel_hlcdc driver, and
>> specifically for the emulated fbdev interface, I received some
>> push-back that my feeble in-driver attempts should be solved
>> by the core. This is my attempt to do it right.
>>
>> I have obviously not tested all of this with more than a compile,
>> but patches 1 through 5 are enough to make the atmel-hlcdc driver
>> do what I need. The rest is just lots of removals and cleanup made
>> possible by the improved core.
>>
>> Please test, I would not be surprised if I have fouled up some
>> bit-manipulation somewhere, or if I have misunderstood something
>> about atomics...
>>
>> Changes since v2:
>> - Added patch 1/16 which factors out pseudo-palette handling.
>> - Removed the if (cmap->start + cmap->len < cmap->start)
>>   sanity check on the assumption that the fbdev core handles it.
>> - Added patch 4/16 which factors out atomic state and commit
>>   handling from drm_atomic_helper_legacy_gamma_set to
>>   drm_mode_gamma_set_ioctl.
>> - Do one atomic commit for all affected crtc.
>> - Removed a now obsolete note in include/drm/drm_crtc.h (ammended
>>   the last patch).
>> - Cc list is getting long, so I have redused the list for the
>>   individual patches. If you would like to get the full series
>>   (or nothing at all) for the next round (if that is needed) just
>>   say so.
> 
> Is this still on top of my locking rework? I tried to apply patches 1-3,
> but there's minor conflicts ...
> -Daniel

v3 has the same base as v2. I collected your locking rework sometime
after june 21, you have perhaps changed things since? I saw an update
of that dpms patch you Cc me, but figured there were no significant
changes that I needed to handle since I didn't get the full set
this time either. A bad assumption it seems...

Anyway, the base I have for v3 (and v2) is linux next-20170621 plus
the following locking rework commits (in reverse order):

Author: Thierry Reding <tred...@nvidia.com>
Date: Wed Jun 21 20:28:15 2017 +0200
Subject: drm/hisilicon: Remove custom FB helper deferred setup

Author: Thierry Reding <tred...@nvidia.com>
Date: Wed Jun 21 20:28:14 2017 +0200
Subject: drm/exynos: Remove custom FB helper deferred setup

Author: Thierry Reding <tred...@nvidia.com>
Date: Wed Jun 21 20:28:13 2017 +0200
Subject: drm/fb-helper: Support deferred setup

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:12 2017 +0200
Subject: drm/fb-helper: Split dpms handling into legacy and atomic paths

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:11 2017 +0200
Subject: drm/fb-helper: Stop using mode_config.mutex for internals

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:10 2017 +0200
Subject: drm/fb-helper: Push locking into restore_fbdev_mode_atomic|legacy

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:09 2017 +0200
Subject: drm/fb-helper: Push locking into pan_display_atomic|legacy

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:08 2017 +0200
Subject: drm/fb-helper: Drop locking from the vsync wait ioctl code

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:07 2017 +0200
Subject: drm/fb-helper: Push locking in fb_is_bound

Author: Thierry Reding <tred...@nvidia.com>
Date: Wed Jun 21 20:28:06 2017 +0200
Subject: drm/fb-helper: Add top-level lock

Author: Daniel Vetter <daniel.vet...@ffwll.ch>
Date: Wed Jun 21 20:28:05 2017 +0200
Subject: drm/i915: Drop FBDEV #ifdev in mst code

Author: Thierry Reding <tred...@nvidia.com>
Date: Wed Jun 21 20:28:04 2017 +0200
Subject: drm/fb-helper: Push down modeset lock into FB helpers

Cheers,
peda


Re: [PATCH v3 05/16] drm/fb-helper: do a generic fb_setcmap helper in terms of crtc .gamma_set

2017-07-06 Thread Peter Rosin
On 2017-07-06 07:55, Daniel Vetter wrote:
> On Wed, Jul 5, 2017 at 7:50 PM, Peter Rosin <p...@axentia.se> wrote:
>>>> +retry:
>>>> +ret = drm_modeset_lock_all_ctx(dev, );
>>>
>>> With atomic you don't need to grab locks, this is done behind the scenes
>>> (as long as you handle the retry/backoff correctly). See the kerneldoc for
>>> the various drm_atomic_get_*_state functions.
>>
>> It doesn't work if I remove it. What is the disconnect?
> 
> Good question,

Duh, for symmetry I also removed the dropping of the locks. So the next
call of course had no chance of getting access. How silly of me...

>didn't spot this at first, but your backoff/retry logic
> is proken. When typing drm_modeset_lock locking code please make sure
> you've enabled both CONFIG_PROVE_LOCKING and
> CONFIG_DEBUG_WW_MUTEX_SLOWPATH. Without these two it's really easy to
> get this wrong. Please also read
> https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#kms-locking
> carefully plus all the kernel-doc of the various hooks. This stuff is
> a really tricky locking scheme, it takes a while to understand it and
> implement it correctly. Which is why all the locking magic is in
> shared code and for normal drivers no need think about it. For the
> fundamental algorithm, you can also check out the docs for w/w mutexes
> at https://www.kernel.org/doc/Documentation/locking/ww-mutex-design.txt
> 
> Might also help to read a bunch of the other locking paths again, with
> my patches there's a few just in drm_fbdev_helper.c. I'll leave you
> with these snippets here since I think this is fun to learn, but when
> you're stuck I'm happy to help learn.

I'll take a long look at this before I send a cleaned up v4. Thanks for
the pointers...

Cheers,
peda


[PATCH v4 08/14] drm: gma500: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .gamma_set and .gamma_get are no longer
used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/gma500/framebuffer.c   | 22 
 drivers/gpu/drm/gma500/gma_display.c   | 32 ++
 drivers/gpu/drm/gma500/psb_intel_display.c |  7 +--
 drivers/gpu/drm/gma500/psb_intel_drv.h |  1 -
 4 files changed, 12 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/gma500/framebuffer.c 
b/drivers/gpu/drm/gma500/framebuffer.c
index 7da70b6..2570c7f 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -479,26 +479,6 @@ static struct drm_framebuffer *psb_user_framebuffer_create
return psb_framebuffer_create(dev, cmd, r);
 }
 
-static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-
-   gma_crtc->lut_r[regno] = red >> 8;
-   gma_crtc->lut_g[regno] = green >> 8;
-   gma_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
-   u16 *green, u16 *blue, int regno)
-{
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-
-   *red = gma_crtc->lut_r[regno] << 8;
-   *green = gma_crtc->lut_g[regno] << 8;
-   *blue = gma_crtc->lut_b[regno] << 8;
-}
-
 static int psbfb_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
 {
@@ -525,8 +505,6 @@ static int psbfb_probe(struct drm_fb_helper *helper,
 }
 
 static const struct drm_fb_helper_funcs psb_fb_helper_funcs = {
-   .gamma_set = psbfb_gamma_set,
-   .gamma_get = psbfb_gamma_get,
.fb_probe = psbfb_probe,
 };
 
diff --git a/drivers/gpu/drm/gma500/gma_display.c 
b/drivers/gpu/drm/gma500/gma_display.c
index e7fd356..f3c48a2 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -144,33 +144,32 @@ void gma_crtc_load_lut(struct drm_crtc *crtc)
struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
const struct psb_offset *map = _priv->regmap[gma_crtc->pipe];
int palreg = map->palette;
+   u16 *r, *g, *b;
int i;
 
/* The clocks have to be on to load the palette. */
if (!crtc->enabled)
return;
 
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
if (gma_power_begin(dev, false)) {
for (i = 0; i < 256; i++) {
REG_WRITE(palreg + 4 * i,
- ((gma_crtc->lut_r[i] +
- gma_crtc->lut_adj[i]) << 16) |
- ((gma_crtc->lut_g[i] +
- gma_crtc->lut_adj[i]) << 8) |
- (gma_crtc->lut_b[i] +
- gma_crtc->lut_adj[i]));
+ (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
+ (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
+ ((*b++ >> 8) + gma_crtc->lut_adj[i]));
}
gma_power_end(dev);
} else {
for (i = 0; i < 256; i++) {
/* FIXME: Why pipe[0] and not pipe[..._crtc->pipe]? */
dev_priv->regs.pipe[0].palette[i] =
- ((gma_crtc->lut_r[i] +
- gma_crtc->lut_adj[i]) << 16) |
- ((gma_crtc->lut_g[i] +
- gma_crtc->lut_adj[i]) << 8) |
- (gma_crtc->lut_b[i] +
- gma_crtc->lut_adj[i]);
+   (((*r++ >> 8) + gma_crtc->lut_adj[i]) << 16) |
+   (((*g++ >> 8) + gma_crtc->lut_adj[i]) << 8) |
+   ((*b++ >> 8) + gma_crtc->lut_adj[i]);
}
 
}
@@ -180,15 +179,6 @@ int gma_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, 
u16 *green, u16 *blue,
   u32 size,
   struct drm_modeset_acquire_ctx *ctx)
 {
-   struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   gma_crtc->lut_r[i] = red[i] >> 8;
-   gma_crtc->lut_g[i] = green[i] >> 8;
-   gma_crtc->lut_b[i] = blue[i] >> 8;
-   }
-
 

[PATCH v4 07/14] drm: cirrus: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/cirrus/cirrus_drv.h   |  8 
 drivers/gpu/drm/cirrus/cirrus_fbdev.c |  2 -
 drivers/gpu/drm/cirrus/cirrus_mode.c  | 71 ---
 3 files changed, 16 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h 
b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 8690352..be2d7e48 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -96,7 +96,6 @@
 
 struct cirrus_crtc {
struct drm_crtc base;
-   u8  lut_r[256], lut_g[256], lut_b[256];
int last_dpms;
boolenabled;
 };
@@ -180,13 +179,6 @@ cirrus_bo(struct ttm_buffer_object *bo)
 #define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base)
 #define DRM_FILE_PAGE_OFFSET (0x1ULL >> PAGE_SHIFT)
 
-   /* cirrus_mode.c */
-void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, int regno);
-void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-u16 *blue, int regno);
-
-
/* cirrus_main.c */
 int cirrus_device_init(struct cirrus_device *cdev,
  struct drm_device *ddev,
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c 
b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 7fa58ee..1fedab0 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -265,8 +265,6 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
 }
 
 static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
-   .gamma_set = cirrus_crtc_fb_gamma_set,
-   .gamma_get = cirrus_crtc_fb_gamma_get,
.fb_probe = cirrusfb_create,
 };
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c 
b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 53f6f0f..a4c4a46 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -31,25 +31,6 @@
  * This file contains setup code for the CRTC.
  */
 
-static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
-{
-   struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
-   struct drm_device *dev = crtc->dev;
-   struct cirrus_device *cdev = dev->dev_private;
-   int i;
-
-   if (!crtc->enabled)
-   return;
-
-   for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
-   /* VGA registers */
-   WREG8(PALETTE_INDEX, i);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_r[i]);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_g[i]);
-   WREG8(PALETTE_DATA, cirrus_crtc->lut_b[i]);
-   }
-}
-
 /*
  * The DRM core requires DPMS functions, but they make little sense in our
  * case and so are just stubs
@@ -330,15 +311,25 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, 
u16 *red, u16 *green,
 u16 *blue, uint32_t size,
 struct drm_modeset_acquire_ctx *ctx)
 {
-   struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+   struct drm_device *dev = crtc->dev;
+   struct cirrus_device *cdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
-   for (i = 0; i < size; i++) {
-   cirrus_crtc->lut_r[i] = red[i];
-   cirrus_crtc->lut_g[i] = green[i];
-   cirrus_crtc->lut_b[i] = blue[i];
+   if (!crtc->enabled)
+   return 0;
+
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
+   for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
+   /* VGA registers */
+   WREG8(PALETTE_INDEX, i);
+   WREG8(PALETTE_DATA, *r++ >> 8);
+   WREG8(PALETTE_DATA, *g++ >> 8);
+   WREG8(PALETTE_DATA, *b++ >> 8);
}
-   cirrus_crtc_load_lut(crtc);
 
return 0;
 }
@@ -365,7 +356,6 @@ static const struct drm_crtc_helper_funcs 
cirrus_helper_funcs = {
.mode_set_base = cirrus_crtc_mode_set_base,
.prepare = cirrus_crtc_prepare,
.commit = cirrus_crtc_commit,
-   .load_lut = cirrus_crtc_load_lut,
 };
 
 /* CRTC setup */
@@ -373,7 +363,6 @@ static void cirrus_crtc_init(struct drm_device *dev)
 {
struct cirrus_device *cdev = dev->dev_private;
struct cirrus_crtc *cirrus_crtc;
-   int i;
 
cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
  (CIRRUSFB_CONN_LIMIT * sizeof(struct 
drm_connector *)),
@@ -387,37 +376,9 @@ static void cirrus_crtc_init(st

[PATCH v4 10/14] drm: mgag200: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/mgag200/mgag200_drv.h  |  5 ---
 drivers/gpu/drm/mgag200/mgag200_fb.c   |  2 --
 drivers/gpu/drm/mgag200/mgag200_mode.c | 62 --
 3 files changed, 15 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h 
b/drivers/gpu/drm/mgag200/mgag200_drv.h
index c88b6ec..04f1dfb 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -237,11 +237,6 @@ mgag200_bo(struct ttm_buffer_object *bo)
 {
return container_of(bo, struct mgag200_bo, bo);
 }
-   /* mgag200_crtc.c */
-void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, int regno);
-void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-u16 *blue, int regno);
 
/* mgag200_mode.c */
 int mgag200_modeset_init(struct mga_device *mdev);
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c 
b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 5d3b1fa..5cf980a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -258,8 +258,6 @@ static int mga_fbdev_destroy(struct drm_device *dev,
 }
 
 static const struct drm_fb_helper_funcs mga_fb_helper_funcs = {
-   .gamma_set = mga_crtc_fb_gamma_set,
-   .gamma_get = mga_crtc_fb_gamma_get,
.fb_probe = mgag200fb_create,
 };
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c 
b/drivers/gpu/drm/mgag200/mgag200_mode.c
index f4b5358..5e9cd4c 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -27,15 +27,19 @@
 
 static void mga_crtc_load_lut(struct drm_crtc *crtc)
 {
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
+   u16 *r_ptr, *g_ptr, *b_ptr;
int i;
 
if (!crtc->enabled)
return;
 
+   r_ptr = crtc->gamma_store;
+   g_ptr = r_ptr + crtc->gamma_size;
+   b_ptr = g_ptr + crtc->gamma_size;
+
WREG8(DAC_INDEX + MGA1064_INDEX, 0);
 
if (fb && fb->format->cpp[0] * 8 == 16) {
@@ -46,25 +50,27 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
if (i > (MGAG200_LUT_SIZE >> 1)) {
r = b = 0;
} else {
-   r = mga_crtc->lut_r[i << 1];
-   b = mga_crtc->lut_b[i << 1];
+   r = *r_ptr++ >> 8;
+   b = *b_ptr++ >> 8;
+   r_ptr++;
+   b_ptr++;
}
} else {
-   r = mga_crtc->lut_r[i];
-   b = mga_crtc->lut_b[i];
+   r = *r_ptr++ >> 8;
+   b = *b_ptr++ >> 8;
}
/* VGA registers */
WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
}
return;
}
for (i = 0; i < MGAG200_LUT_SIZE; i++) {
/* VGA registers */
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
-   WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_b[i]);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
+   WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8);
}
 }
 
@@ -1399,14 +1405,6 @@ static int mga_crtc_gamma_set(struct drm_crtc *crtc, u16 
*red, u16 *green,
  u16 *blue, uint32_t size,
  struct drm_modeset_acquire_ctx *ctx)
 {
-   struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   mga_crtc->lut_r[i] = red[i] >> 8;
-   mga_crtc->lut_g[i] = green[i] >> 8;
-   mga_crtc->lut_b[i] = blue[i] >> 8;
-  

[PATCH v4 14/14] drm: remove unused and redundant callbacks

2017-07-06 Thread Peter Rosin
Drivers no longer have any need for these callbacks, and there are no
users. Zap. Zap-zap-zzzap-p-pp-p.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 include/drm/drm_crtc.h   |  8 
 include/drm/drm_fb_helper.h  | 32 
 include/drm/drm_modeset_helper_vtables.h | 16 
 3 files changed, 56 deletions(-)

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3a911a6..0cc8962 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -358,14 +358,6 @@ struct drm_crtc_funcs {
 * drm_crtc_enable_color_mgmt(), which then supports the legacy gamma
 * interface through the drm_atomic_helper_legacy_gamma_set()
 * compatibility implementation.
-*
-* NOTE:
-*
-* Drivers that support gamma tables and also fbdev emulation through
-* the provided helper library need to take care to fill out the gamma
-* hooks for both. Currently there's a bit an unfortunate duplication
-* going on, which should eventually be unified to just one set of
-* hooks.
 */
int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
 uint32_t size,
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index ea170b9..21c5630 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -85,38 +85,6 @@ struct drm_fb_helper_surface_size {
  */
 struct drm_fb_helper_funcs {
/**
-* @gamma_set:
-*
-* Set the given gamma LUT register on the given CRTC.
-*
-* This callback is optional.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
- u16 blue, int regno);
-   /**
-* @gamma_get:
-*
-* Read the given gamma LUT register on the given CRTC, used to save the
-* current LUT when force-restoring the fbdev for e.g. kdbg.
-*
-* This callback is optional.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, int regno);
-
-   /**
 * @fb_probe:
 *
 * Driver callback to allocate and initialize the fbdev info structure.
diff --git a/include/drm/drm_modeset_helper_vtables.h 
b/include/drm/drm_modeset_helper_vtables.h
index 0656984..6cdcb42 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -267,22 +267,6 @@ struct drm_crtc_helper_funcs {
enum mode_set_atomic);
 
/**
-* @load_lut:
-*
-* Load a LUT prepared with the _fb_helper_funcs.gamma_set vfunc.
-*
-* This callback is optional and is only used by the fbdev emulation
-* helpers.
-*
-* FIXME:
-*
-* This callback is functionally redundant with the core gamma table
-* support and simply exists because the fbdev hasn't yet been
-* refactored to use the core gamma table interfaces.
-*/
-   void (*load_lut)(struct drm_crtc *crtc);
-
-   /**
 * @disable:
 *
 * This callback should be used to disable the CRTC. With the atomic
-- 
2.1.4



[PATCH v4 12/14] drm: radeon: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/radeon/atombios_crtc.c  |  1 -
 drivers/gpu/drm/radeon/radeon_connectors.c  |  7 ++-
 drivers/gpu/drm/radeon/radeon_display.c | 71 -
 drivers/gpu/drm/radeon/radeon_fb.c  |  2 -
 drivers/gpu/drm/radeon/radeon_legacy_crtc.c |  1 -
 drivers/gpu/drm/radeon/radeon_mode.h|  4 --
 6 files changed, 33 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c 
b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3c492a0..02baaaf 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -2217,7 +2217,6 @@ static const struct drm_crtc_helper_funcs 
atombios_helper_funcs = {
.mode_set_base_atomic = atombios_crtc_set_base_atomic,
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
-   .load_lut = radeon_crtc_load_lut,
.disable = atombios_crtc_disable,
 };
 
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c 
b/drivers/gpu/drm/radeon/radeon_connectors.c
index 27affbd..2f642cb 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -773,12 +773,15 @@ static int radeon_connector_set_property(struct 
drm_connector *connector, struct
 
if (connector->encoder->crtc) {
struct drm_crtc *crtc  = connector->encoder->crtc;
-   const struct drm_crtc_helper_funcs *crtc_funcs = 
crtc->helper_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 
radeon_crtc->output_csc = radeon_encoder->output_csc;
 
-   (*crtc_funcs->load_lut)(crtc);
+   /*
+* Our .gamma_set assumes the .gamma_store has been
+* prefilled and don't care about its arguments.
+*/
+   crtc->funcs->gamma_set(crtc, NULL, NULL, NULL, 0, NULL);
}
}
 
diff --git a/drivers/gpu/drm/radeon/radeon_display.c 
b/drivers/gpu/drm/radeon/radeon_display.c
index 17d3daf..8b7d7a0 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -42,6 +42,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
@@ -60,11 +61,14 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x003f);
 
WREG8(AVIVO_DC_LUT_RW_INDEX, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(AVIVO_DC_LUT_30_COLOR,
-(radeon_crtc->lut_r[i] << 20) |
-(radeon_crtc->lut_g[i] << 10) |
-(radeon_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 
/* Only change bit 0 of LUT_SEL, other bits are set elsewhere */
@@ -76,6 +80,7 @@ static void dce4_crtc_load_lut(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
 
DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id);
@@ -93,11 +98,14 @@ static void dce4_crtc_load_lut(struct drm_crtc *crtc)
WREG32(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 
0x0007);
 
WREG32(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset,
-  (radeon_crtc->lut_r[i] << 20) |
-  (radeon_crtc->lut_g[i] << 10) |
-  (radeon_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 }
 
@@ -106,6 +114,7 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
struct rad

[PATCH v4 13/14] drm: stm: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helper .load_lut is no longer used, and can not
work right without also providing the fb helpers .gamma_set and
.gamma_get thus rendering the code in this driver suspect.

Just remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/stm/ltdc.c | 12 
 drivers/gpu/drm/stm/ltdc.h |  1 -
 2 files changed, 13 deletions(-)

diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
index 5331760..3e95b4d 100644
--- a/drivers/gpu/drm/stm/ltdc.c
+++ b/drivers/gpu/drm/stm/ltdc.c
@@ -375,17 +375,6 @@ static irqreturn_t ltdc_irq(int irq, void *arg)
  * DRM_CRTC
  */
 
-static void ltdc_crtc_load_lut(struct drm_crtc *crtc)
-{
-   struct ltdc_device *ldev = crtc_to_ltdc(crtc);
-   unsigned int i, lay;
-
-   for (lay = 0; lay < ldev->caps.nb_layers; lay++)
-   for (i = 0; i < 256; i++)
-   reg_write(ldev->regs, LTDC_L1CLUTWR + lay * LAY_OFS,
- ldev->clut[i]);
-}
-
 static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
 {
@@ -525,7 +514,6 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
 }
 
 static struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
-   .load_lut = ltdc_crtc_load_lut,
.mode_set_nofb = ltdc_crtc_mode_set_nofb,
.atomic_flush = ltdc_crtc_atomic_flush,
.atomic_enable = ltdc_crtc_atomic_enable,
diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h
index d7a9c73..620ca55 100644
--- a/drivers/gpu/drm/stm/ltdc.h
+++ b/drivers/gpu/drm/stm/ltdc.h
@@ -27,7 +27,6 @@ struct ltdc_device {
struct drm_panel *panel;
struct mutex err_lock;  /* protecting error_status */
struct ltdc_caps caps;
-   u32 clut[256];  /* color look up table */
u32 error_status;
u32 irq_status;
 };
-- 
2.1.4



[PATCH v4 03/14] drm/fb-helper: separate the fb_setcmap helper into atomic and legacy paths

2017-07-06 Thread Peter Rosin
The legacy path implements setcmap in terms of crtc .gamma_set.

The atomic path implements setcmap by directly updating the crtc gamma_lut
property.

This has a couple of benefits:
- it makes the redundant fb helpers .load_lut, .gamma_set and .gamma_get
  completely obsolete. They are now unused and subject for removal.
- atomic drivers that support clut modes get fbdev support for those from
  the drm core. This includes atmel-hlcdc, but perhaps others as well?

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_fb_helper.c | 232 
 1 file changed, 161 insertions(+), 71 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 721511d..32d6ea1 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1195,27 +1195,6 @@ void drm_fb_helper_set_suspend_unlocked(struct 
drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
 
-static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
-u16 blue, u16 regno, struct fb_info *info)
-{
-   struct drm_fb_helper *fb_helper = info->par;
-   struct drm_framebuffer *fb = fb_helper->fb;
-
-   /*
-* The driver really shouldn't advertise pseudo/directcolor
-* visuals if it can't deal with the palette.
-*/
-   if (WARN_ON(!fb_helper->funcs->gamma_set ||
-   !fb_helper->funcs->gamma_get))
-   return -EINVAL;
-
-   WARN_ON(fb->format->cpp[0] != 1);
-
-   fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
-
-   return 0;
-}
-
 static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
 {
u32 *palette = (u32 *)info->pseudo_palette;
@@ -1248,57 +1227,140 @@ static int setcmap_pseudo_palette(struct fb_cmap 
*cmap, struct fb_info *info)
return 0;
 }
 
-/**
- * drm_fb_helper_setcmap - implementation for _ops.fb_setcmap
- * @cmap: cmap to set
- * @info: fbdev registered by the helper
- */
-int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
 {
struct drm_fb_helper *fb_helper = info->par;
-   struct drm_device *dev = fb_helper->dev;
-   const struct drm_crtc_helper_funcs *crtc_funcs;
-   u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc;
u16 *r, *g, *b;
-   int i, j, rc = 0;
-   int start;
+   int i, ret = 0;
 
-   if (oops_in_progress)
-   return -EBUSY;
+   drm_modeset_lock_all(fb_helper->dev);
+   for (i = 0; i < fb_helper->crtc_count; i++) {
+   crtc = fb_helper->crtc_info[i].mode_set.crtc;
+   if (!crtc->funcs->gamma_set || !crtc->gamma_size)
+   return -EINVAL;
 
-   mutex_lock(_helper->lock);
-   if (!drm_fb_helper_is_bound(fb_helper)) {
-   mutex_unlock(_helper->lock);
-   return -EBUSY;
+   if (cmap->start + cmap->len > crtc->gamma_size)
+   return -EINVAL;
+
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
+   memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
+   memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
+   memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
+
+   ret = crtc->funcs->gamma_set(crtc, r, g, b,
+crtc->gamma_size, NULL);
+   if (ret)
+   return ret;
}
+   drm_modeset_unlock_all(fb_helper->dev);
 
-   drm_modeset_lock_all(dev);
-   if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
-   rc = setcmap_pseudo_palette(cmap, info);
-   goto out;
+   return ret;
+}
+
+static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
+  struct fb_cmap *cmap)
+{
+   struct drm_device *dev = crtc->dev;
+   struct drm_property_blob *gamma_lut;
+   struct drm_color_lut *lut;
+   int size = crtc->gamma_size;
+   int i;
+
+   if (!size || cmap->start + cmap->len > size)
+   return ERR_PTR(-EINVAL);
+
+   gamma_lut = drm_property_create_blob(dev, sizeof(*lut) * size, NULL);
+   if (IS_ERR(gamma_lut))
+   return gamma_lut;
+
+   lut = (struct drm_color_lut *)gamma_lut->data;
+   if (cmap->start || cmap->len != size) {
+   u16 *r = crtc->gamma_store;
+   u16 *g = r + crtc->gamma_size;
+   u16 *b = g + crtc->gamma_size;
+
+   for (i = 0; i < cmap->start; i++) {
+   lut

[PATCH v4 04/14] drm: amd: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c   | 24 
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h |  1 -
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c   | 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c   | 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c| 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c| 27 +++
 drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 23 ---
 7 files changed, 28 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
index c0d8c6f..7dc3780 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
@@ -312,31 +312,7 @@ static int amdgpu_fbdev_destroy(struct drm_device *dev, 
struct amdgpu_fbdev *rfb
return 0;
 }
 
-/** Sets the color ramps on behalf of fbcon */
-static void amdgpu_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
- u16 blue, int regno)
-{
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-
-   amdgpu_crtc->lut_r[regno] = red >> 6;
-   amdgpu_crtc->lut_g[regno] = green >> 6;
-   amdgpu_crtc->lut_b[regno] = blue >> 6;
-}
-
-/** Gets the color ramps on behalf of fbcon */
-static void amdgpu_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
- u16 *blue, int regno)
-{
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-
-   *red = amdgpu_crtc->lut_r[regno] << 6;
-   *green = amdgpu_crtc->lut_g[regno] << 6;
-   *blue = amdgpu_crtc->lut_b[regno] << 6;
-}
-
 static const struct drm_fb_helper_funcs amdgpu_fb_helper_funcs = {
-   .gamma_set = amdgpu_crtc_fb_gamma_set,
-   .gamma_get = amdgpu_crtc_fb_gamma_get,
.fb_probe = amdgpufb_create,
 };
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 43a9d3a..39f7eda 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -369,7 +369,6 @@ struct amdgpu_atom_ss {
 struct amdgpu_crtc {
struct drm_crtc base;
int crtc_id;
-   u16 lut_r[256], lut_g[256], lut_b[256];
bool enabled;
bool can_tile;
uint32_t crtc_offset;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c 
b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 9f78c03..c958023 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -2267,6 +2267,7 @@ static void dce_v10_0_crtc_load_lut(struct drm_crtc *crtc)
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct amdgpu_device *adev = dev->dev_private;
+   u16 *r, *g, *b;
int i;
u32 tmp;
 
@@ -2304,11 +2305,14 @@ static void dce_v10_0_crtc_load_lut(struct drm_crtc 
*crtc)
WREG32(mmDC_LUT_WRITE_EN_MASK + amdgpu_crtc->crtc_offset, 0x0007);
 
WREG32(mmDC_LUT_RW_INDEX + amdgpu_crtc->crtc_offset, 0);
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
WREG32(mmDC_LUT_30_COLOR + amdgpu_crtc->crtc_offset,
-  (amdgpu_crtc->lut_r[i] << 20) |
-  (amdgpu_crtc->lut_g[i] << 10) |
-  (amdgpu_crtc->lut_b[i] << 0));
+  ((*r++ & 0xffc0) << 14) |
+  ((*g++ & 0xffc0) << 4) |
+  (*b++ >> 6));
}
 
tmp = RREG32(mmDEGAMMA_CONTROL + amdgpu_crtc->crtc_offset);
@@ -2624,15 +2628,6 @@ static int dce_v10_0_crtc_gamma_set(struct drm_crtc 
*crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size,
struct drm_modeset_acquire_ctx *ctx)
 {
-   struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-   int i;
-
-   /* userspace palettes are always correct as is */
-   for (i = 0; i < size; i++) {
-   amdgpu_crtc->lut_r[i] = red[i] >> 6;
-   amdgpu_crtc->lut_g[i] = green[i] >> 6;
-   amdgpu_crtc->lut_b[i] = blue[i] >> 6;
-   }
dce_v10_0_crtc_load_lut(crtc);
 
return 0;
@@ -2844,14 +2839,12 @@ static const struct drm_crtc_helper_funcs 
dce_v10_0_crtc_helper_funcs = {
.mode_set_base_atomic = dce_v10_0_crtc_set_base_atomic,
.prepare = dce_v10_0_crtc_prepare,

[PATCH v4 00/14] improve the fb_setcmap helper

2017-07-06 Thread Peter Rosin
Hi!

While trying to get CLUT support for the atmel_hlcdc driver, and
specifically for the emulated fbdev interface, I received some
push-back that my feeble in-driver attempts should be solved
by the core. This is my attempt to do it right.

I have obviously not tested all of this with more than a compile,
but patches 1 and 3 are enough to make the atmel-hlcdc driver
do what I need. The rest is just lots of removals and cleanup made
possible by the other improvements.

Please test, I would not be surprised if I have fouled up some
bit-manipulation somewhere, or if I have misunderstood something
about atomics...

Changes since v3:
- Rebased onto drm-misc-next and dropped patches 1-3 from v3, since
  they are already merged.
- Dropped the v3 patch 4/16 ("drm/color-mgmt: move atomic state/commit
  out from .gamma_set") since the atomic setcmap no longer uses
  the crtc .gamma_set callback.
- Added patch 1/14 which exports drm_atomic_replace_property_blob...
- ...and patch 2/14 which uses this new export to simplify
  drm_atomic_helper_legacy_gamma_set.
- Big changes to patch 3/14 (was 5/16 in v3). It had various locking
  issues and the atomic setcmap is rather different.

Changes since v2:
- Added patch 1/16 which factors out pseudo-palette handling.
- Removed the if (cmap->start + cmap->len < cmap->start)
  sanity check on the assumption that the fbdev core handles it.
- Added patch 4/16 which factors out atomic state and commit
  handling from drm_atomic_helper_legacy_gamma_set to
  drm_mode_gamma_set_ioctl.
- Do one atomic commit for all affected crtc.
- Removed a now obsolete note in include/drm/drm_crtc.h (ammended
  the last patch).
- Cc list is getting long, so I have redused the list for the
  individual patches. If you would like to get the full series
  (or nothing at all) for the next round (if that is needed) just
  say so.

Changes since v1:

- Rebased to next-20170621
- Split 1/11 into a preparatory patch, a cleanup patch and then
  the meat in 3/14.
- Handle pseudo-palette for FB_VISUAL_TRUECOLOR.
- Removed the empty .gamma_get/.gamma_set fb helpers from the
  armada driver that I had somehow managed to ignore but which
  0day found real quick.
- Be less judgemental on drivers only providing .gamma_get and
  .gamma_set, but no .load_lut. That's actually a valid thing
  to do if you only need pseudo-palette for FB_VISUAL_TRUECOLOR.
- Add a comment about colliding bitfields in the nouveau driver.
- Remove gamma_set/gamma_get declarations from the radeon driver
  (the definitions were removed in v1).

Cheers,
peda

Peter Rosin (14):
  drm/atomic: export drm_atomic_replace_property_blob
  drm/atomic-helper: update lut props directly in ..._legacy_gamma_set
  drm/fb-helper: separate the fb_setcmap helper into atomic and legacy
paths
  drm: amd: remove dead code and pointless local lut storage
  drm: armada: remove dead empty functions
  drm: ast: remove dead code and pointless local lut storage
  drm: cirrus: remove dead code and pointless local lut storage
  drm: gma500: remove dead code and pointless local lut storage
  drm: i915: remove dead code and pointless local lut storage
  drm: mgag200: remove dead code and pointless local lut storage
  drm: nouveau: remove dead code and pointless local lut storage
  drm: radeon: remove dead code and pointless local lut storage
  drm: stm: remove dead code and pointless local lut storage
  drm: remove unused and redundant callbacks

 drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c  |  24 ---
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h|   1 -
 drivers/gpu/drm/amd/amdgpu/dce_v10_0.c  |  27 +---
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c  |  27 +---
 drivers/gpu/drm/amd/amdgpu/dce_v6_0.c   |  27 +---
 drivers/gpu/drm/amd/amdgpu/dce_v8_0.c   |  27 +---
 drivers/gpu/drm/amd/amdgpu/dce_virtual.c|  23 ---
 drivers/gpu/drm/armada/armada_crtc.c|  10 --
 drivers/gpu/drm/armada/armada_crtc.h|   2 -
 drivers/gpu/drm/armada/armada_fbdev.c   |   2 -
 drivers/gpu/drm/ast/ast_drv.h   |   1 -
 drivers/gpu/drm/ast/ast_fb.c|  20 ---
 drivers/gpu/drm/ast/ast_mode.c  |  26 +---
 drivers/gpu/drm/cirrus/cirrus_drv.h |   8 -
 drivers/gpu/drm/cirrus/cirrus_fbdev.c   |   2 -
 drivers/gpu/drm/cirrus/cirrus_mode.c|  71 ++---
 drivers/gpu/drm/drm_atomic.c|  17 +-
 drivers/gpu/drm/drm_atomic_helper.c |  23 +--
 drivers/gpu/drm/drm_fb_helper.c | 232 +++-
 drivers/gpu/drm/gma500/framebuffer.c|  22 ---
 drivers/gpu/drm/gma500/gma_display.c|  32 ++--
 drivers/gpu/drm/gma500/psb_intel_display.c  |   7 +-
 drivers/gpu/drm/gma500/psb_intel_drv.h  |   1 -
 drivers/gpu/drm/i915/intel_drv.h|   1 -
 drivers/gpu/drm/i915/intel_fbdev.c  |  31 
 drivers/gpu/drm/mgag200/mgag200_drv.h   |   5 -
 drivers/gpu/drm/mgag200/mgag200_fb.c|   2 -
 drivers/gpu/drm/

[PATCH v4 06/14] drm: ast: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/ast/ast_drv.h  |  1 -
 drivers/gpu/drm/ast/ast_fb.c   | 20 
 drivers/gpu/drm/ast/ast_mode.c | 26 ++
 3 files changed, 6 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 8880f0b..569a148 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -245,7 +245,6 @@ struct ast_connector {
 
 struct ast_crtc {
struct drm_crtc base;
-   u8 lut_r[256], lut_g[256], lut_b[256];
struct drm_gem_object *cursor_bo;
uint64_t cursor_addr;
int cursor_width, cursor_height;
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 4ad4acd..dbabcac 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -255,27 +255,7 @@ static int astfb_create(struct drm_fb_helper *helper,
return ret;
 }
 
-static void ast_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-  u16 blue, int regno)
-{
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   ast_crtc->lut_r[regno] = red >> 8;
-   ast_crtc->lut_g[regno] = green >> 8;
-   ast_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
-  u16 *blue, int regno)
-{
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   *red = ast_crtc->lut_r[regno] << 8;
-   *green = ast_crtc->lut_g[regno] << 8;
-   *blue = ast_crtc->lut_b[regno] << 8;
-}
-
 static const struct drm_fb_helper_funcs ast_fb_helper_funcs = {
-   .gamma_set = ast_fb_gamma_set,
-   .gamma_get = ast_fb_gamma_get,
.fb_probe = astfb_create,
 };
 
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index aaef0a6..724c16b 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -63,15 +63,18 @@ static inline void ast_load_palette_index(struct 
ast_private *ast,
 static void ast_crtc_load_lut(struct drm_crtc *crtc)
 {
struct ast_private *ast = crtc->dev->dev_private;
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+   u16 *r, *g, *b;
int i;
 
if (!crtc->enabled)
return;
 
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
for (i = 0; i < 256; i++)
-   ast_load_palette_index(ast, i, ast_crtc->lut_r[i],
-  ast_crtc->lut_g[i], ast_crtc->lut_b[i]);
+   ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8);
 }
 
 static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct 
drm_display_mode *mode,
@@ -633,7 +636,6 @@ static const struct drm_crtc_helper_funcs 
ast_crtc_helper_funcs = {
.mode_set = ast_crtc_mode_set,
.mode_set_base = ast_crtc_mode_set_base,
.disable = ast_crtc_disable,
-   .load_lut = ast_crtc_load_lut,
.prepare = ast_crtc_prepare,
.commit = ast_crtc_commit,
 
@@ -648,15 +650,6 @@ static int ast_crtc_gamma_set(struct drm_crtc *crtc, u16 
*red, u16 *green,
  u16 *blue, uint32_t size,
  struct drm_modeset_acquire_ctx *ctx)
 {
-   struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
-   int i;
-
-   /* userspace palettes are always correct as is */
-   for (i = 0; i < size; i++) {
-   ast_crtc->lut_r[i] = red[i] >> 8;
-   ast_crtc->lut_g[i] = green[i] >> 8;
-   ast_crtc->lut_b[i] = blue[i] >> 8;
-   }
ast_crtc_load_lut(crtc);
 
return 0;
@@ -681,7 +674,6 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
 static int ast_crtc_init(struct drm_device *dev)
 {
struct ast_crtc *crtc;
-   int i;
 
crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
if (!crtc)
@@ -690,12 +682,6 @@ static int ast_crtc_init(struct drm_device *dev)
drm_crtc_init(dev, >base, _crtc_funcs);
drm_mode_crtc_set_gamma_size(>base, 256);
drm_crtc_helper_add(>base, _crtc_helper_funcs);
-
-   for (i = 0; i < 256; i++) {
-   crtc->lut_r[i] = i;
-   crtc->lut_g[i] = i;
-   crtc->lut_b[i] = i;
-   }
return 0;
 }
 
-- 
2.1.4



[PATCH v4 11/14] drm: nouveau: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
no longer used. Remove the dead code and hook up the crtc .gamma_set
to use the crtc gamma_store directly instead of duplicating that
info locally.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/nouveau/dispnv04/crtc.c | 26 -
 drivers/gpu/drm/nouveau/nouveau_crtc.h  |  3 ---
 drivers/gpu/drm/nouveau/nouveau_fbcon.c | 22 --
 drivers/gpu/drm/nouveau/nv50_display.c  | 40 +++--
 4 files changed, 22 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c 
b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 4b4b0b4..8f689f1 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -764,13 +764,18 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = nv_crtc->base.dev;
struct rgb { uint8_t r, g, b; } __attribute__((packed)) *rgbs;
+   u16 *r, *g, *b;
int i;
 
rgbs = (struct rgb 
*)nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].DAC;
+   r = crtc->gamma_store;
+   g = r + crtc->gamma_size;
+   b = g + crtc->gamma_size;
+
for (i = 0; i < 256; i++) {
-   rgbs[i].r = nv_crtc->lut.r[i] >> 8;
-   rgbs[i].g = nv_crtc->lut.g[i] >> 8;
-   rgbs[i].b = nv_crtc->lut.b[i] >> 8;
+   rgbs[i].r = *r++ >> 8;
+   rgbs[i].g = *g++ >> 8;
+   rgbs[i].b = *b++ >> 8;
}
 
nouveau_hw_load_state_palette(dev, nv_crtc->index, 
_display(dev)->mode_reg);
@@ -792,13 +797,6 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, 
u16 *b,
  struct drm_modeset_acquire_ctx *ctx)
 {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-   int i;
-
-   for (i = 0; i < size; i++) {
-   nv_crtc->lut.r[i] = r[i];
-   nv_crtc->lut.g[i] = g[i];
-   nv_crtc->lut.b[i] = b[i];
-   }
 
/* We need to know the depth before we upload, but it's possible to
 * get called before a framebuffer is bound.  If this is the case,
@@ -1095,7 +1093,6 @@ static const struct drm_crtc_helper_funcs 
nv04_crtc_helper_funcs = {
.mode_set = nv_crtc_mode_set,
.mode_set_base = nv04_crtc_mode_set_base,
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
-   .load_lut = nv_crtc_gamma_load,
.disable = nv_crtc_disable,
 };
 
@@ -1103,17 +1100,12 @@ int
 nv04_crtc_create(struct drm_device *dev, int crtc_num)
 {
struct nouveau_crtc *nv_crtc;
-   int ret, i;
+   int ret;
 
nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
if (!nv_crtc)
return -ENOMEM;
 
-   for (i = 0; i < 256; i++) {
-   nv_crtc->lut.r[i] = i << 8;
-   nv_crtc->lut.g[i] = i << 8;
-   nv_crtc->lut.b[i] = i << 8;
-   }
nv_crtc->lut.depth = 0;
 
nv_crtc->index = crtc_num;
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h 
b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 050fcf3..b7a18fb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -61,9 +61,6 @@ struct nouveau_crtc {
 
struct {
struct nouveau_bo *nvbo;
-   uint16_t r[256];
-   uint16_t g[256];
-   uint16_t b[256];
int depth;
} lut;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c 
b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 2665a07..f770784 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -278,26 +278,6 @@ nouveau_fbcon_accel_init(struct drm_device *dev)
info->fbops = _fbcon_ops;
 }
 
-static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
-   nv_crtc->lut.r[regno] = red;
-   nv_crtc->lut.g[regno] = green;
-   nv_crtc->lut.b[regno] = blue;
-}
-
-static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
-   u16 *blue, int regno)
-{
-   struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-
-   *red = nv_crtc->lut.r[regno];
-   *green = nv_crtc->lut.g[regno];
-   *blue = nv_crtc->lut.b[regno];
-}
-
 static void
 nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
@@ -467,8 +447,6 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
 }
 
 static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
-   .gamma_set = nouveau_fbcon_gamma_set,
-   .gamma_get = nouveau_fbcon_gamma_get,

[PATCH v4 01/14] drm/atomic: export drm_atomic_replace_property_blob

2017-07-06 Thread Peter Rosin
While at it, add some words in the kernel-doc about the 'replaced' arg and
remove a faulty kernel-doc comment on the return value.

Also remove a redundant return statement.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_atomic.c | 17 +
 include/drm/drm_atomic.h |  4 
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 09ca662..b7d9696 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -414,13 +414,15 @@ EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
  * @new_blob: the new blob to replace with
  * @replaced: whether the blob has been replaced
  *
- * RETURNS:
- * Zero on success, error code on failure
+ * Note that you are required to initialize @replaced to false before the
+ * call, since it is only set to true when the blob property is changed and
+ * not set to false when the property is not changed. This enables a series
+ * of calls to be made where you are interested in if any property is
+ * replaced, but not care so much about exactly which of them was replaced.
  */
-static void
-drm_atomic_replace_property_blob(struct drm_property_blob **blob,
-struct drm_property_blob *new_blob,
-bool *replaced)
+void drm_atomic_replace_property_blob(struct drm_property_blob **blob,
+ struct drm_property_blob *new_blob,
+ bool *replaced)
 {
struct drm_property_blob *old_blob = *blob;
 
@@ -432,9 +434,8 @@ drm_atomic_replace_property_blob(struct drm_property_blob 
**blob,
drm_property_blob_get(new_blob);
*blob = new_blob;
*replaced = true;
-
-   return;
 }
+EXPORT_SYMBOL(drm_atomic_replace_property_blob);
 
 static int
 drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index dcc8e0c..8b32ea5 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -321,6 +321,10 @@ int drm_atomic_connector_set_property(struct drm_connector 
*connector,
struct drm_connector_state *state, struct drm_property 
*property,
uint64_t val);
 
+void drm_atomic_replace_property_blob(struct drm_property_blob **blob,
+ struct drm_property_blob *new_blob,
+ bool *replaced);
+
 void * __must_check
 drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
  void *obj,
-- 
2.1.4



[PATCH v4 02/14] drm/atomic-helper: update lut props directly in ..._legacy_gamma_set

2017-07-06 Thread Peter Rosin
Do not waste cycles looking up the property id when we have the
actual property already.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/drm_atomic_helper.c | 23 ---
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index 667ec97..5a4a344 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3769,11 +3769,11 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc 
*crtc,
   struct drm_modeset_acquire_ctx *ctx)
 {
struct drm_device *dev = crtc->dev;
-   struct drm_mode_config *config = >mode_config;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct drm_property_blob *blob = NULL;
struct drm_color_lut *blob_data;
+   bool replaced = false;
int i, ret = 0;
 
state = drm_atomic_state_alloc(crtc->dev);
@@ -3805,20 +3805,13 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc 
*crtc,
}
 
/* Reset DEGAMMA_LUT and CTM properties. */
-   ret = drm_atomic_crtc_set_property(crtc, crtc_state,
-   config->degamma_lut_property, 0);
-   if (ret)
-   goto fail;
-
-   ret = drm_atomic_crtc_set_property(crtc, crtc_state,
-   config->ctm_property, 0);
-   if (ret)
-   goto fail;
-
-   ret = drm_atomic_crtc_set_property(crtc, crtc_state,
-   config->gamma_lut_property, blob->base.id);
-   if (ret)
-   goto fail;
+   drm_atomic_replace_property_blob(_state->degamma_lut,
+NULL, );
+   drm_atomic_replace_property_blob(_state->ctm,
+NULL, );
+   drm_atomic_replace_property_blob(_state->gamma_lut,
+blob, );
+   crtc_state->color_mgmt_changed |= replaced;
 
ret = drm_atomic_commit(state);
 
-- 
2.1.4



[PATCH v4 05/14] drm: armada: remove dead empty functions

2017-07-06 Thread Peter Rosin
The redundant fb helpers .gamma_set and .gamma_get are no longer used.
Remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/armada/armada_crtc.c  | 10 --
 drivers/gpu/drm/armada/armada_crtc.h  |  2 --
 drivers/gpu/drm/armada/armada_fbdev.c |  2 --
 3 files changed, 14 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c 
b/drivers/gpu/drm/armada/armada_crtc.c
index b57fb80..5d5cc32 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -334,16 +334,6 @@ static void armada_drm_vblank_off(struct armada_crtc 
*dcrtc)
armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
 }
 
-void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
-   int idx)
-{
-}
-
-void armada_drm_crtc_gamma_get(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-   int idx)
-{
-}
-
 /* The mode_config.mutex will be held for this call */
 static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)
 {
diff --git a/drivers/gpu/drm/armada/armada_crtc.h 
b/drivers/gpu/drm/armada/armada_crtc.h
index 7e8906d..bab11f4 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -102,8 +102,6 @@ struct armada_crtc {
 };
 #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
 
-void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
-void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
 void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
 
 void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c 
b/drivers/gpu/drm/armada/armada_fbdev.c
index 602dfea..5fa076d 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -118,8 +118,6 @@ static int armada_fb_probe(struct drm_fb_helper *fbh,
 }
 
 static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
-   .gamma_set  = armada_drm_crtc_gamma_set,
-   .gamma_get  = armada_drm_crtc_gamma_get,
.fb_probe   = armada_fb_probe,
 };
 
-- 
2.1.4



[PATCH v4 09/14] drm: i915: remove dead code and pointless local lut storage

2017-07-06 Thread Peter Rosin
The driver stores lut values from the fbdev interface, and is able
to give them back, but does not appear to do anything with these
lut values. The generic fb helpers have replaced this function,
and may even have made the driver work for the C8 mode from the
fbdev interface. But that is untested.

Since the fb helpers .gamma_set and .gamma_get are obsolete,
remove the dead code.

Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/gpu/drm/i915/intel_drv.h   |  1 -
 drivers/gpu/drm/i915/intel_fbdev.c | 31 ---
 2 files changed, 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d93efb4..bc7bfa0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -786,7 +786,6 @@ struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
enum plane plane;
-   u8 lut_r[256], lut_g[256], lut_b[256];
/*
 * Whether the crtc and the connected output pipeline is active. Implies
 * that crtc->enabled is set, i.e. the current mode configuration has
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c 
b/drivers/gpu/drm/i915/intel_fbdev.c
index 460ca0b..19d650b 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -281,27 +281,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
return ret;
 }
 
-/** Sets the color ramps on behalf of RandR */
-static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
-   u16 blue, int regno)
-{
-   struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-   intel_crtc->lut_r[regno] = red >> 8;
-   intel_crtc->lut_g[regno] = green >> 8;
-   intel_crtc->lut_b[regno] = blue >> 8;
-}
-
-static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 
*green,
-   u16 *blue, int regno)
-{
-   struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-   *red = intel_crtc->lut_r[regno] << 8;
-   *green = intel_crtc->lut_g[regno] << 8;
-   *blue = intel_crtc->lut_b[regno] << 8;
-}
-
 static struct drm_fb_helper_crtc *
 intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
 {
@@ -376,7 +355,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_fb_helper_crtc *new_crtc;
-   struct intel_crtc *intel_crtc;
 
fb_conn = fb_helper->connector_info[i];
connector = fb_conn->connector;
@@ -418,13 +396,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
 
num_connectors_enabled++;
 
-   intel_crtc = to_intel_crtc(connector->state->crtc);
-   for (j = 0; j < 256; j++) {
-   intel_crtc->lut_r[j] = j;
-   intel_crtc->lut_g[j] = j;
-   intel_crtc->lut_b[j] = j;
-   }
-
new_crtc = intel_fb_helper_crtc(fb_helper,
connector->state->crtc);
 
@@ -527,8 +498,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
 
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
.initial_config = intel_fb_initial_config,
-   .gamma_set = intel_crtc_fb_gamma_set,
-   .gamma_get = intel_crtc_fb_gamma_get,
.fb_probe = intelfb_create,
 };
 
-- 
2.1.4



Re: [PATCH v3 05/16] drm/fb-helper: do a generic fb_setcmap helper in terms of crtc .gamma_set

2017-07-05 Thread Peter Rosin
On 2017-07-05 08:21, Daniel Vetter wrote:
> On Tue, Jul 04, 2017 at 12:37:01PM +0200, Peter Rosin wrote:
>> This makes the redundant fb helpers .load_lut, .gamma_set and .gamma_get
>> completely obsolete.
>>
>> Signed-off-by: Peter Rosin <p...@axentia.se>
>> ---
>>  drivers/gpu/drm/drm_fb_helper.c | 165 
>> +++-
>>  1 file changed, 94 insertions(+), 71 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c 
>> b/drivers/gpu/drm/drm_fb_helper.c
>> index b75b1f2..7f8199a 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -1257,27 +1257,6 @@ void drm_fb_helper_set_suspend_unlocked(struct 
>> drm_fb_helper *fb_helper,
>>  }
>>  EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
>>  
>> -static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
>> - u16 blue, u16 regno, struct fb_info *info)
>> -{
>> -struct drm_fb_helper *fb_helper = info->par;
>> -struct drm_framebuffer *fb = fb_helper->fb;
>> -
>> -/*
>> - * The driver really shouldn't advertise pseudo/directcolor
>> - * visuals if it can't deal with the palette.
>> - */
>> -if (WARN_ON(!fb_helper->funcs->gamma_set ||
>> -!fb_helper->funcs->gamma_get))
>> -return -EINVAL;
>> -
>> -WARN_ON(fb->format->cpp[0] != 1);
>> -
>> -fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
>> -
>> -return 0;
>> -}
>> -
>>  static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info 
>> *info)
>>  {
>>  u32 *palette = (u32 *)info->pseudo_palette;
>> @@ -1310,54 +1289,68 @@ static int setcmap_pseudo_palette(struct fb_cmap 
>> *cmap, struct fb_info *info)
>>  return 0;
>>  }
>>  
>> -/**
>> - * drm_fb_helper_setcmap - implementation for _ops.fb_setcmap
>> - * @cmap: cmap to set
>> - * @info: fbdev registered by the helper
>> - */
>> -int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>> +static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
>>  {
>>  struct drm_fb_helper *fb_helper = info->par;
>> -struct drm_device *dev = fb_helper->dev;
>> -const struct drm_crtc_helper_funcs *crtc_funcs;
>> -u16 *red, *green, *blue, *transp;
>>  struct drm_crtc *crtc;
>>  u16 *r, *g, *b;
>> -int i, j, rc = 0;
>> -int start;
>> +int i, ret = 0;
>>  
>> -if (oops_in_progress)
>> -return -EBUSY;
>> +for (i = 0; i < fb_helper->crtc_count; i++) {
>> +crtc = fb_helper->crtc_info[i].mode_set.crtc;
>> +if (!crtc->funcs->gamma_set || !crtc->gamma_size)
>> +return -EINVAL;
>>  
>> -mutex_lock(_helper->lock);
>> -if (!drm_fb_helper_is_bound(fb_helper)) {
>> -mutex_unlock(_helper->lock);
>> -return -EBUSY;
>> -}
>> +if (cmap->start + cmap->len > crtc->gamma_size)
>> +return -EINVAL;
>>  
>> -drm_modeset_lock_all(dev);
>> -if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
>> -rc = setcmap_pseudo_palette(cmap, info);
>> -goto out;
>> +r = crtc->gamma_store;
>> +g = r + crtc->gamma_size;
>> +b = g + crtc->gamma_size;
>> +
>> +memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
>> +memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
>> +memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
>> +
>> +ret = crtc->funcs->gamma_set(crtc, r, g, b,
>> + crtc->gamma_size, NULL);
>> +if (ret)
>> +return ret;
>>  }
>>  
>> -for (i = 0; i < fb_helper->crtc_count; i++) {
>> -crtc = fb_helper->crtc_info[i].mode_set.crtc;
>> -crtc_funcs = crtc->helper_private;
>> +return ret;
>> +}
> 
> For the legacy path you need to keep the drm_modeset_lock_all (but only in
> setcmap_legacy). Otherwise this part here looks good.

Oops, didn't intend to zap that one. Thanks for catching!

>>  
>> -red = cmap->red;
>> -green = cmap->green;
>> -blue = cmap-&g

Re: [PATCH] iio: multiplexer: add NULL check on devm_kzalloc() return value

2017-07-06 Thread Peter Rosin
On 2017-07-07 00:08, Gustavo A. R. Silva wrote:
> Check return value from call to devm_kzalloc()
> in order to prevent a NULL pointer dereference.

Right, thanks for finding that one! There's another one inside the
for loop that is just starting in the context of this patch. Care
to fix checking the return value of that devm_kmemdup as well?

And someone should perhaps teach Coccinelle about devm_kmemdup...

> This issue was detected using Coccinelle and the following semantic patch:
> 
> @@
> expression x;
> identifier fld;
> @@
> 
> * x = devm_kzalloc(...);
>   ... when != x == NULL
>   x->fld
> 
> 

One of these blank lines should perhaps be a "Fixes:" tag?

Cheers,
peda

> Signed-off-by: Gustavo A. R. Silva 
> ---
>  drivers/iio/multiplexer/iio-mux.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/iio/multiplexer/iio-mux.c 
> b/drivers/iio/multiplexer/iio-mux.c
> index 37ba007..a8d672b 100644
> --- a/drivers/iio/multiplexer/iio-mux.c
> +++ b/drivers/iio/multiplexer/iio-mux.c
> @@ -285,6 +285,9 @@ static int mux_configure_channel(struct device *dev, 
> struct mux *mux,
>   child->ext_info_cache = devm_kzalloc(dev,
>sizeof(*child->ext_info_cache) *
>num_ext_info, GFP_KERNEL);
> + if (!child->ext_info_cache)
> + return -ENOMEM;
> +
>   for (i = 0; i < num_ext_info; ++i) {
>   child->ext_info_cache[i].size = -1;
>  
> 



Re: [PATCH] iio: multiplexer: add NULL check on devm_kzalloc() return value

2017-07-06 Thread Peter Rosin
On 2017-07-07 06:35, Gustavo A. R. Silva wrote:
> Hi Peter,
> 
> Quoting Peter Rosin <p...@axentia.se>:
> 
>> On 2017-07-07 00:08, Gustavo A. R. Silva wrote:
>>> Check return value from call to devm_kzalloc()
>>> in order to prevent a NULL pointer dereference.
>>
>> Right, thanks for finding that one! There's another one inside the
>> for loop that is just starting in the context of this patch. Care
>> to fix checking the return value of that devm_kmemdup as well?
>>
> 
> Sure, I'll send a new patch shortly.
> 
>> And someone should perhaps teach Coccinelle about devm_kmemdup...
>>
> 
> Good catch, I just implemented that script.
> 
>>> This issue was detected using Coccinelle and the following semantic patch:
>>>
>>> @@
>>> expression x;
>>> identifier fld;
>>> @@
>>>
>>> * x = devm_kzalloc(...);
>>>   ... when != x == NULL
>>>   x->fld
>>>
>>>
>>
>> One of these blank lines should perhaps be a "Fixes:" tag?
>>
> 
> mmm, I don't get this...

If you add a Fixes-tag, like below, you help the stable kernel maintainers
decide what to look at. In this case it might be overkill since the thing
you fix is so fresh and does not apply to any old kernel. But I think it
is a good habit...

Fixes: 7ba9df54b091 ("iio: multiplexer: new iio category and iio-mux driver")

(and it is a bit unusual to see two blank lines before the SoB-tag)

Sorry for not spelling it out the first time.

Cheers,
peda


Re: [PATCH] iio: multiplexer: add NULL check on devm_kzalloc() and devm_kmemdup() return values

2017-07-06 Thread Peter Rosin
On 2017-07-07 06:53, Gustavo A. R. Silva wrote:
> Check return values from call to devm_kzalloc() and devm_kmemup()

If someone cares enough: s/devm_kmemup/evm_kmemdup/


> in order to prevent a NULL pointer dereference.
> 
> This issue was detected using Coccinelle and the following semantic patch:
> 
> @@
> expression x;
> identifier fld;
> @@
> 
> * x = devm_kzalloc(...);
>... when != x == NULL
>x->fld
> 
> Cc: Peter Rosin <p...@axentia.se>
> Signed-off-by: Gustavo A. R. Silva <garsi...@embeddedor.com>

Either way,

Reviewed-by: Peter Rosin <p...@axentia.se>

Thanks!


Re: [PATCH v13 03/10] mux: minimal mux subsystem and gpio-based mux controller

2017-04-21 Thread Peter Rosin
On 2017-04-20 23:53, Peter Rosin wrote:
> On 2017-04-18 23:53, Peter Rosin wrote:
>> On 2017-04-18 13:44, Greg Kroah-Hartman wrote:
>>> On Tue, Apr 18, 2017 at 12:59:50PM +0200, Peter Rosin wrote:
>>>> On 2017-04-18 10:51, Greg Kroah-Hartman wrote:
>>>>> On Thu, Apr 13, 2017 at 06:43:07PM +0200, Peter Rosin wrote:
> 
> *snip*
> 
>>>>>> +if (mux->idle_state != MUX_IDLE_AS_IS &&
>>>>>> +mux->idle_state != mux->cached_state)
>>>>>> +ret = mux_control_set(mux, mux->idle_state);
>>>>>> +
>>>>>> +up_read(>lock);
>>>>>
>>>>> You require a lock to be held for a "global" function?  Without
>>>>> documentation?  Or even a sparse marking?  That's asking for trouble...
>>>>
>>>> Documentation I can handle, but where should I look to understand how I
>>>> should add sparse markings?
>>>
>>> Run sparse on the code and see what it says :)
>>
>> Will do.
> 
> I just did, and even went through the trouble of getting the bleeding
> edge sparse from the git repo when sparse 0.5.0 came up empty, but it's
> all silence for me. So, how do I add sparse markings?

I looked some more into this, and the markings I find that seem related
are __acquire() and __release(). But neither mutex_lock() nor up_read()
has markings like that, so adding them when using those kinds of locks
in an imbalanced way seems like a sure way of *getting* sparse messages
about context imbalance...

So, either that, or you are talking about __must_check markings?

I feel like I'm missing something, please advise further.

Cheers,
peda



Re: [PATCH] iio: inkern: fix a static checker error

2017-04-25 Thread Peter Rosin
On 2017-04-25 18:01, Lars-Peter Clausen wrote:
> On 04/24/2017 11:32 AM, Peter Rosin wrote:
>> On 2017-04-20 23:13, Peter Rosin wrote:
>>> On 2017-04-20 23:12, Lars-Peter Clausen wrote:
>>>> On 04/20/2017 11:01 PM, Peter Rosin wrote:
>>>>> Avoid this smatch error:
>>>>> drivers/iio/inkern.c:751 iio_read_avail_channel_raw() error: double 
>>>>> unlock 'mutex:>indio_dev->info_exist_lock'
>>>>
>>>> Looks good, but it's not just the smatch error, this is a real issue. This
>>>> even seems to be a endless loop, always jumping back to err_unlock.
>>>
>>> Yes, it should probably go to stable too...
>>
>> Nope, not an endless loop, but I of course only noticed after sending
>> a v2 [1] which falsely stated just that. Ignore that v2 patch and take
>> this one instead, for the reasons stated in my followup [2] to that
>> message.
>>
>> Involving stable is probably not needed either...
> 
> Right, my fault for sending you the wrong way. Sorry for that.

No no, don't worry, I was already down that path without your help.

I just thought everybody would see the obvious bug and the urgency
when it was pointed out to them with a patch. Like you did. And I
was in a hurry for it to have a slim chance of getting in before
4.12 (but then -rc8 happened instead) so didn't spend a lot of time
crafting a thorough commit message (nor analyzing the problem, but
why would I when I had a very clear picture of an endless loop on
error?). But in the end it wasn't really that obvious, was it? And
not that urgent either. Stupid damn bug...

Cheers,
peda



[PATCH v2] iio: inkern: fix endless loop in error path

2017-04-24 Thread Peter Rosin
If ret ends up negative, mutex_unlock is called repeatedly in an infinite
loop, which of course is pretty nasty...

Issue found by smatch:
drivers/iio/inkern.c:751 iio_read_avail_channel_raw() error: double unlock 
'mutex:>indio_dev->info_exist_lock'

Fixes: 00c5f80c2fad ("iio: inkern: add helpers to query available values from 
channels")
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/iio/inkern.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

v1 -> v2 changes:
- Be clear about that there is a real nasty issue and that it isn't only
  about avoiding some insignificant static checker issue.

v1:  https://lkml.org/lkml/2017/4/20/887

Cheers,
peda

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 7a13535dc3e9..a3941bade6a7 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
 err_unlock:
mutex_unlock(>indio_dev->info_exist_lock);
 
-   if (ret >= 0 && type != IIO_VAL_INT) {
+   if (ret >= 0 && type != IIO_VAL_INT)
/* raw values are assumed to be IIO_VAL_INT */
ret = -EINVAL;
-   goto err_unlock;
-   }
 
return ret;
 }
-- 
2.1.4



[PATCH v14 02/11] dt-bindings: document devicetree bindings for mux-controllers and gpio-mux

2017-04-24 Thread Peter Rosin
Allow specifying that a single multiplexer controller can be used to
control several parallel multiplexers, thus enabling sharing of the
multiplexer controller by different consumers.

Add a binding for a first mux controller in the form of a GPIO based mux
controller.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/devicetree/bindings/mux/gpio-mux.txt |  69 +
 .../devicetree/bindings/mux/mux-controller.txt | 157 +
 MAINTAINERS|   6 +
 include/dt-bindings/mux/mux.h  |  16 +++
 4 files changed, 248 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/gpio-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
 create mode 100644 include/dt-bindings/mux/mux.h

diff --git a/Documentation/devicetree/bindings/mux/gpio-mux.txt 
b/Documentation/devicetree/bindings/mux/gpio-mux.txt
new file mode 100644
index ..b8f746344d80
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/gpio-mux.txt
@@ -0,0 +1,69 @@
+GPIO-based multiplexer controller bindings
+
+Define what GPIO pins are used to control a multiplexer. Or several
+multiplexers, if the same pins control more than one multiplexer.
+
+Required properties:
+- compatible : "gpio-mux"
+- mux-gpios : list of gpios used to control the multiplexer, least
+ significant bit first.
+- #mux-control-cells : <0>
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-state : if present, the state the mux will have when idle. The
+  special state MUX_IDLE_AS_IS is the default.
+
+The multiplexer state is defined as the number represented by the
+multiplexer GPIO pins, where the first pin is the least significant
+bit. An active pin is a binary 1, an inactive pin is a binary 0.
+
+Example:
+
+   mux: mux-controller {
+   compatible = "gpio-mux";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync-1", "in", "out", "sync-2";
+   };
+
+   i2c-mux {
+   compatible = "i2c-mux";
+   i2c-parent = <>;
+
+   mux-controls = <>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   i2c@0 {
+   reg = <0>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   ssd1307: oled@3c {
+   /* ... */
+   };
+   };
+
+   i2c@3 {
+   reg = <3>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   pca9555: pca9555@20 {
+   /* ... */
+   };
+   };
+   };
diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt 
b/Documentation/devicetree/bindings/mux/mux-controller.txt
new file mode 100644
index ..4f47e4bd2fa0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
@@ -0,0 +1,157 @@
+Common multiplexer controller bindings
+==
+
+A multiplexer (or mux) controller will have one, or several, consumer devices
+that uses the mux controller. Thus, a mux controller can possibly control
+several parallel multiplexers. Presumably there will be at least one
+multiplexer needed by each consumer, but a single mux controller can of course
+control several multiplexers for a single consumer.
+
+A mux controller provides a number of states to its consumers, and the state
+space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
+0-7 for an 8-way multiplexer, etc.
+
+
+Consumers
+-
+
+Mux controller consumers should specify a list of mux controllers that they
+want to use with a property containing a 'mux-ctrl-list':
+
+   mux-ctrl-list ::=  [mux-ctrl-list]
+   single-mux-ctrl ::=  [mux-ctrl-specifier]
+   mux-ctrl-phandle : phandle to mux controller node
+   mux-ctrl-specifier : array of #mux-control-cells specifying the
+given mux controller (controller specific)
+
+Mux controller properties should be named "mux-controls". The exact meaning of
+each mux controller property must be documented in the device tree bind

[PATCH v14 05/11] iio: inkern: api for manipulating ext_info of iio channels

2017-04-24 Thread Peter Rosin
Extend the inkern api with functions for reading and writing ext_info
of iio channels.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/iio/inkern.c | 60 
 include/linux/iio/consumer.h | 37 +++
 2 files changed, 97 insertions(+)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 7a13535dc3e9..8292ad4435ea 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -869,3 +869,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int 
val)
return ret;
 }
 EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+   unsigned int i = 0;
+
+   if (!chan->channel->ext_info)
+   return i;
+
+   for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
+   ++i;
+
+   return i;
+}
+EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+
+static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
+   const struct iio_channel *chan,
+   const char *attr)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   if (!chan->channel->ext_info)
+   return NULL;
+
+   for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+   if (!strcmp(attr, ext_info->name))
+   return ext_info;
+   }
+
+   return NULL;
+}
+
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   ext_info = iio_lookup_ext_info(chan, attr);
+   if (!ext_info)
+   return -EINVAL;
+
+   return ext_info->read(chan->indio_dev, ext_info->private,
+ chan->channel, buf);
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+  const char *buf, size_t len)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   ext_info = iio_lookup_ext_info(chan, attr);
+   if (!ext_info)
+   return -EINVAL;
+
+   return ext_info->write(chan->indio_dev, ext_info->private,
+  chan->channel, buf, len);
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 47eeec3218b5..5e347a9805fd 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int 
*val,
 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale);
 
+/**
+ * iio_get_channel_ext_info_count() - get number of ext_info attributes
+ *   connected to the channel.
+ * @chan:  The channel being queried
+ *
+ * Returns the number of ext_info attributes
+ */
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
+
+/**
+ * iio_read_channel_ext_info() - read ext_info attribute from a given channel
+ * @chan:  The channel being queried.
+ * @attr:  The ext_info attribute to read.
+ * @buf:   Where to store the attribute value. Assumed to hold
+ * at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf (perhaps w/o zero termination;
+ * it need not even be a string), or an error code.
+ */
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf);
+
+/**
+ * iio_write_channel_ext_info() - write ext_info attribute from a given channel
+ * @chan:  The channel being queried.
+ * @attr:  The ext_info attribute to read.
+ * @buf:   The new attribute value. Strings needs to be zero-
+ * terminated, but the terminator should not be included
+ * in the below len.
+ * @len:   The size of the new attribute value.
+ *
+ * Returns the number of accepted bytes, which should be the same as len.
+ * An error code can also be returned.
+ */
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+  const char *buf, size_t len);
+
 #endif
-- 
2.1.4



[PATCH v14 03/11] mux: minimal mux subsystem

2017-04-24 Thread Peter Rosin
Add a new minimalistic subsystem that handles multiplexer controllers.
When multiplexers are used in various places in the kernel, and the
same multiplexer controller can be used for several independent things,
there should be one place to implement support for said multiplexer
controller.

A single multiplexer controller can also be used to control several
parallel multiplexers, that are in turn used by different subsystems
in the kernel, leading to a need to coordinate multiplexer accesses.
The multiplexer subsystem handles this coordination.

Thanks go out to Lars-Peter Clausen, Jonathan Cameron, Rob Herring,
Wolfram Sang, Paul Gortmaker, Dan Carpenter, Colin Ian King, Greg
Kroah-Hartman and last but certainly not least to Philipp Zabel for
helpful comments, reviews, patches and general encouragement!

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/ABI/testing/sysfs-class-mux |  16 +
 Documentation/driver-model/devres.txt |   8 +
 MAINTAINERS   |   3 +
 drivers/Kconfig   |   2 +
 drivers/Makefile  |   1 +
 drivers/mux/Kconfig   |  16 +
 drivers/mux/Makefile  |   5 +
 drivers/mux/mux-core.c| 593 ++
 include/linux/mux/consumer.h  |  33 ++
 include/linux/mux/driver.h| 111 ++
 10 files changed, 788 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-mux
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 include/linux/mux/consumer.h
 create mode 100644 include/linux/mux/driver.h

diff --git a/Documentation/ABI/testing/sysfs-class-mux 
b/Documentation/ABI/testing/sysfs-class-mux
new file mode 100644
index ..8715f9c7bd4f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-mux
@@ -0,0 +1,16 @@
+What:  /sys/class/mux/
+Date:  April 2017
+KernelVersion: 4.13
+Contact:   Peter Rosin <p...@axentia.se>
+Description:
+   The mux/ class sub-directory belongs to the Generic MUX
+   Framework and provides a sysfs interface for using MUX
+   controllers.
+
+What:  /sys/class/mux/muxchipN/
+Date:  April 2017
+KernelVersion: 4.13
+Contact:   Peter Rosin <p...@axentia.se>
+Description:
+   A /sys/class/mux/muxchipN directory is created for each
+   probed MUX chip where N is a simple enumeration.
diff --git a/Documentation/driver-model/devres.txt 
b/Documentation/driver-model/devres.txt
index efb8200819d6..e2343d9cbec7 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -337,6 +337,14 @@ MEM
 MFD
   devm_mfd_add_devices()
 
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_free()
+  devm_mux_chip_register()
+  devm_mux_chip_unregister()
+  devm_mux_control_get()
+  devm_mux_control_put()
+
 PER-CPU MEM
   devm_alloc_percpu()
   devm_free_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index 7fc06739c8ad..4cfa080878e2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8561,8 +8561,11 @@ F:   include/linux/spi/mmc_spi.h
 MULTIPLEXER SUBSYSTEM
 M: Peter Rosin <p...@axentia.se>
 S: Maintained
+F: Documentation/ABI/testing/mux/sysfs-class-mux*
 F: Documentation/devicetree/bindings/mux/
 F: include/linux/dt-bindings/mux/
+F: include/linux/mux/
+F: drivers/mux/
 
 MULTISOUND SOUND DRIVER
 M: Andrew Veliath <andre...@usa.net>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 117ca14ccf85..a7ea13e1b869 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -204,4 +204,6 @@ source "drivers/fpga/Kconfig"
 
 source "drivers/fsi/Kconfig"
 
+source "drivers/mux/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 2eced9afba53..c0436f6dd5a9 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -177,3 +177,4 @@ obj-$(CONFIG_ANDROID)   += android/
 obj-$(CONFIG_NVMEM)+= nvmem/
 obj-$(CONFIG_FPGA) += fpga/
 obj-$(CONFIG_FSI)  += fsi/
+obj-$(CONFIG_MULTIPLEXER)  += mux/
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
new file mode 100644
index ..23ab2cde83b1
--- /dev/null
+++ b/drivers/mux/Kconfig
@@ -0,0 +1,16 @@
+#
+# Multiplexer devices
+#
+
+menuconfig MULTIPLEXER
+   tristate "Multiplexer subsystem"
+   help
+ Multiplexer controller subsystem. Multiplexers are used in a
+ variety of settings, and this subsystem abstracts their use
+ so that the rest of the kernel sees a common interface. When
+ multiple parallel multiplexers are controlled by one single
+ multiplexer controller, this subsystem also coordinates the
+ multiplexer accesses.

[PATCH v14 04/11] mux: gpio: add mux controller driver for gpio based multiplexers

2017-04-24 Thread Peter Rosin
The driver builds a single multiplexer controller using a number
of gpio pins. For N pins, there will be 2^N possible multiplexer
states. The GPIO pins can be connected (by the hardware) to several
multiplexers, which in that case will be operated in parallel.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig|  18 
 drivers/mux/Makefile   |   1 +
 drivers/mux/mux-gpio.c | 114 +
 3 files changed, 133 insertions(+)
 create mode 100644 drivers/mux/mux-gpio.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 23ab2cde83b1..e580c2d028d2 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -14,3 +14,21 @@ menuconfig MULTIPLEXER
 
  To compile the subsystem as a module, choose M here: the module will
  be called mux-core.
+
+if MULTIPLEXER
+
+config MUX_GPIO
+   tristate "GPIO-controlled Multiplexer"
+   depends on GPIOLIB
+   help
+ GPIO-controlled Multiplexer controller.
+
+ The driver builds a single multiplexer controller using a number
+ of gpio pins. For N pins, there will be 2^N possible multiplexer
+ states. The GPIO pins can be connected (by the hardware) to several
+ multiplexers, which in that case will be operated in parallel.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-gpio.
+
+endif
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 09f0299e109d..bb16953f6290 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)  += mux-core.o
+obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
new file mode 100644
index ..468bf1709606
--- /dev/null
+++ b/drivers/mux/mux-gpio.c
@@ -0,0 +1,114 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux_gpio {
+   struct gpio_descs *gpios;
+   int *val;
+};
+
+static int mux_gpio_set(struct mux_control *mux, int state)
+{
+   struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
+   int i;
+
+   for (i = 0; i < mux_gpio->gpios->ndescs; i++)
+   mux_gpio->val[i] = (state >> i) & 1;
+
+   gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
+  mux_gpio->gpios->desc,
+  mux_gpio->val);
+
+   return 0;
+}
+
+static const struct mux_control_ops mux_gpio_ops = {
+   .set = mux_gpio_set,
+};
+
+static const struct of_device_id mux_gpio_dt_ids[] = {
+   { .compatible = "gpio-mux", },
+   { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+   struct device *dev = >dev;
+   struct mux_chip *mux_chip;
+   struct mux_gpio *mux_gpio;
+   int pins;
+   s32 idle_state;
+   int ret;
+
+   pins = gpiod_count(dev, "mux");
+   if (pins < 0)
+   return pins;
+
+   mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
+  pins * sizeof(*mux_gpio->val));
+   if (IS_ERR(mux_chip))
+   return PTR_ERR(mux_chip);
+
+   mux_gpio = mux_chip_priv(mux_chip);
+   mux_gpio->val = (int *)(mux_gpio + 1);
+   mux_chip->ops = _gpio_ops;
+
+   mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
+   if (IS_ERR(mux_gpio->gpios)) {
+   ret = PTR_ERR(mux_gpio->gpios);
+   if (ret != -EPROBE_DEFER)
+   dev_err(dev, "failed to get gpios\n");
+   return ret;
+   }
+   WARN_ON(pins != mux_gpio->gpios->ndescs);
+   mux_chip->mux->states = 1 << pins;
+
+   ret = device_property_read_u32(dev, "idle-state", (u32 *)_state);
+   if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) {
+   if (idle_state < 0 || idle_state >= mux_chip->mux->states) {
+   dev_err(dev, "invalid idle-state %u\n", idle_state);
+   return -EINVAL;
+   }
+
+   mux_chip->mux->idle_state = idle_state;
+   }
+
+   ret = devm_mux_chip_register(dev, mux_chip);
+   if (ret < 0)
+   return ret;
+
+   dev_info(dev, "%u-way mux-controller registered\n",
+  

Re: [PATCH v2] iio: inkern: fix endless loop in error path

2017-04-24 Thread Peter Rosin
Arrh!

Actually, this updated description is not at all accurate! It is still pretty
nasty to loop back and unlock the mutex again, but the loop isn't endless.
The code will only jump back once. That's of course bad enough, but there's
also the fact that the bug can only happen if type is not IIO_VAL_INT. And
IIUC, that really shouldn't be the case for raw values? Because inkern.c
iio_write_channel_raw() certainly implies it. If raw values really are
IIO_VAL_INT *always*, then the double unlock should never trigger.

And in that case the description of the original v1 patch is much more
accurate, since it really mostly is about a static checker issue.

So, please ignore this update and pick the original patch instead. I.e.
https://lkml.org/lkml/2017/4/20/887

Sorry for the noise.

Cheers,
peda


On 2017-04-24 10:57, Peter Rosin wrote:
> If ret ends up negative, mutex_unlock is called repeatedly in an infinite
> loop, which of course is pretty nasty...
> 
> Issue found by smatch:
> drivers/iio/inkern.c:751 iio_read_avail_channel_raw() error: double unlock 
> 'mutex:>indio_dev->info_exist_lock'
> 
> Fixes: 00c5f80c2fad ("iio: inkern: add helpers to query available values from 
> channels")
> Signed-off-by: Peter Rosin <p...@axentia.se>
> ---
>  drivers/iio/inkern.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> v1 -> v2 changes:
> - Be clear about that there is a real nasty issue and that it isn't only
>   about avoiding some insignificant static checker issue.
> 
> v1:  https://lkml.org/lkml/2017/4/20/887
> 
> Cheers,
> peda
> 
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index 7a13535dc3e9..a3941bade6a7 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
>  err_unlock:
>   mutex_unlock(>indio_dev->info_exist_lock);
>  
> - if (ret >= 0 && type != IIO_VAL_INT) {
> + if (ret >= 0 && type != IIO_VAL_INT)
>   /* raw values are assumed to be IIO_VAL_INT */
>   ret = -EINVAL;
> - goto err_unlock;
> - }
>  
>   return ret;
>  }
> 



[PATCH v14 07/11] iio: multiplexer: new iio category and iio-mux driver

2017-04-24 Thread Peter Rosin
When a multiplexer changes how an iio device behaves (for example
by feeding different signals to an ADC), this driver can be used
to create one virtual iio channel for each multiplexer state.

Depends on the generic multiplexer subsystem.

Cache any ext_info values from the parent iio channel, creating a private
copy of the ext_info attributes for each multiplexer state/channel.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 MAINTAINERS   |   1 +
 drivers/iio/Kconfig   |   1 +
 drivers/iio/Makefile  |   1 +
 drivers/iio/multiplexer/Kconfig   |  18 ++
 drivers/iio/multiplexer/Makefile  |   6 +
 drivers/iio/multiplexer/iio-mux.c | 459 ++
 6 files changed, 486 insertions(+)
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1cde195bba25..519719069211 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6365,6 +6365,7 @@ M:    Peter Rosin <p...@axentia.se>
 L: linux-...@vger.kernel.org
 S: Maintained
 F: Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+F: drivers/iio/multiplexer/iio-mux.c
 
 IIO SUBSYSTEM AND DRIVERS
 M: Jonathan Cameron <ji...@kernel.org>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index a918270d6f54..b3c8c6ef0dff 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
 source "drivers/iio/imu/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/magnetometer/Kconfig"
+source "drivers/iio/multiplexer/Kconfig"
 source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 33fa4026f92c..93c769cd99bf 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -28,6 +28,7 @@ obj-y += humidity/
 obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
+obj-y += multiplexer/
 obj-y += orientation/
 obj-y += potentiometer/
 obj-y += potentiostat/
diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
new file mode 100644
index ..70a044510686
--- /dev/null
+++ b/drivers/iio/multiplexer/Kconfig
@@ -0,0 +1,18 @@
+#
+# Multiplexer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Multiplexers"
+
+config IIO_MUX
+   tristate "IIO multiplexer driver"
+   select MULTIPLEXER
+   depends on OF
+   help
+ Say yes here to build support for the IIO multiplexer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-mux.
+
+endmenu
diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
new file mode 100644
index ..68be3c4abd07
--- /dev/null
+++ b/drivers/iio/multiplexer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O multiplexer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_MUX) += iio-mux.o
diff --git a/drivers/iio/multiplexer/iio-mux.c 
b/drivers/iio/multiplexer/iio-mux.c
new file mode 100644
index ..37ba007f8dca
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,459 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux_ext_info_cache {
+   char *data;
+   ssize_t size;
+};
+
+struct mux_child {
+   struct mux_ext_info_cache *ext_info_cache;
+};
+
+struct mux {
+   int cached_state;
+   struct mux_control *control;
+   struct iio_channel *parent;
+   struct iio_dev *indio_dev;
+   struct iio_chan_spec *chan;
+   struct iio_chan_spec_ext_info *ext_info;
+   struct mux_child *child;
+};
+
+static int iio_mux_select(struct mux *mux, int idx)
+{
+   struct mux_child *child = >child[idx];
+   struct iio_chan_spec const *chan = >chan[idx];
+   int ret;
+   int i;
+
+   ret = mux_control_select(mux->control, chan->channel);
+   if (ret < 0) {
+   mux->cached_state = -1;
+   return ret;
+   }
+
+   if (mux->cached_state == chan->channel)
+   return 0;
+
+   if (chan->ext_info) {
+   for (i = 0; chan->ext_info[i].name; ++i) {
+   const char *attr = chan->ext_info[i].name;
+   

[PATCH v14 09/11] i2c: i2c-mux-gpmux: new driver

2017-04-24 Thread Peter Rosin
This is a general purpose i2c mux that uses a multiplexer controlled by
the multiplexer subsystem to do the muxing.

The user can select if the mux is to be mux-locked and parent-locked
as described in Documentation/i2c/i2c-topology.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Wolfram Sang <w...@the-dreams.de>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/i2c/muxes/Kconfig |  13 +++
 drivers/i2c/muxes/Makefile|   1 +
 drivers/i2c/muxes/i2c-mux-gpmux.c | 173 ++
 3 files changed, 187 insertions(+)
 create mode 100644 drivers/i2c/muxes/i2c-mux-gpmux.c

diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 10b3d17ae3ea..5fb34f24 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -30,6 +30,19 @@ config I2C_MUX_GPIO
  This driver can also be built as a module.  If so, the module
  will be called i2c-mux-gpio.
 
+config I2C_MUX_GPMUX
+   tristate "General Purpose I2C multiplexer"
+   select MULTIPLEXER
+   depends on OF
+   help
+ If you say yes to this option, support will be included for a
+ general purpose I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which in turn is controlled
+ by a MUX-controller from the MUX subsystem.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-mux-gpmux.
+
 config I2C_MUX_PCA9541
tristate "NXP PCA9541 I2C Master Selector"
help
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 9948fa45037f..af43c6c3e861 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE)+= 
i2c-arb-gpio-challenge.o
 obj-$(CONFIG_I2C_DEMUX_PINCTRL)+= i2c-demux-pinctrl.o
 
 obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
+obj-$(CONFIG_I2C_MUX_GPMUX)+= i2c-mux-gpmux.o
 obj-$(CONFIG_I2C_MUX_MLXCPLD)  += i2c-mux-mlxcpld.o
 obj-$(CONFIG_I2C_MUX_PCA9541)  += i2c-mux-pca9541.o
 obj-$(CONFIG_I2C_MUX_PCA954x)  += i2c-mux-pca954x.o
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c 
b/drivers/i2c/muxes/i2c-mux-gpmux.c
new file mode 100644
index ..92cf5f48afe6
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -0,0 +1,173 @@
+/*
+ * General Purpose I2C multiplexer
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux {
+   struct mux_control *control;
+
+   bool do_not_deselect;
+};
+
+static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+   struct mux *mux = i2c_mux_priv(muxc);
+   int ret;
+
+   ret = mux_control_select(mux->control, chan);
+   mux->do_not_deselect = ret < 0;
+
+   return ret;
+}
+
+static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+   struct mux *mux = i2c_mux_priv(muxc);
+
+   if (mux->do_not_deselect)
+   return 0;
+
+   return mux_control_deselect(mux->control);
+}
+
+static struct i2c_adapter *mux_parent_adapter(struct device *dev)
+{
+   struct device_node *np = dev->of_node;
+   struct device_node *parent_np;
+   struct i2c_adapter *parent;
+
+   parent_np = of_parse_phandle(np, "i2c-parent", 0);
+   if (!parent_np) {
+   dev_err(dev, "Cannot parse i2c-parent\n");
+   return ERR_PTR(-ENODEV);
+   }
+   parent = of_find_i2c_adapter_by_node(parent_np);
+   of_node_put(parent_np);
+   if (!parent)
+   return ERR_PTR(-EPROBE_DEFER);
+
+   return parent;
+}
+
+static const struct of_device_id i2c_mux_of_match[] = {
+   { .compatible = "i2c-mux", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
+
+static int i2c_mux_probe(struct platform_device *pdev)
+{
+   struct device *dev = >dev;
+   struct device_node *np = dev->of_node;
+   struct device_node *child;
+   struct i2c_mux_core *muxc;
+   struct mux *mux;
+   struct i2c_adapter *parent;
+   int children;
+   int ret;
+
+   if (!np)
+   return -ENODEV;
+
+   mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+   if (!mux)
+   return -ENOMEM;
+
+   mux->control = devm_mux_control_get(dev, NULL);
+   if (IS_ERR(mux->control)) {
+   if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+   dev_err(dev, "failed to get control-mux\n");
+   return PTR_ERR(mux->control);
+   }
+
+   

[PATCH v14 10/11] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux

2017-04-24 Thread Peter Rosin
Analog Devices ADG792A/G is a triple 4:1 mux.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Reviewed-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../devicetree/bindings/mux/adi,adg792a.txt| 75 ++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/adi,adg792a.txt

diff --git a/Documentation/devicetree/bindings/mux/adi,adg792a.txt 
b/Documentation/devicetree/bindings/mux/adi,adg792a.txt
new file mode 100644
index ..96b787a69f50
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/adi,adg792a.txt
@@ -0,0 +1,75 @@
+Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
+
+Required properties:
+- compatible : "adi,adg792a" or "adi,adg792g"
+- #mux-control-cells : <0> if parallel (the three muxes are bound together
+  with a single mux controller controlling all three muxes), or <1> if
+  not (one mux controller for each mux).
+* Standard mux-controller bindings as described in mux-controller.txt
+
+Optional properties for ADG792G:
+- gpio-controller : if present, #gpio-cells below is required.
+- #gpio-cells : should be <2>
+ - First cell is the GPO line number, i.e. 0 or 1
+ - Second cell is used to specify active high (0)
+   or active low (1)
+
+Optional properties:
+- idle-state : if present, array of states that the mux controllers will have
+  when idle. The special state MUX_IDLE_AS_IS is the default and
+  MUX_IDLE_DISCONNECT is also supported.
+
+States 0 through 3 correspond to signals A through D in the datasheet.
+
+Example:
+
+   /*
+* Three independent mux controllers (of which one is used).
+* Mux 0 is disconnected when idle, mux 1 idles in the previously
+* selected state and mux 2 idles with signal B.
+*/
+{
+   mux: mux-controller@50 {
+   compatible = "adi,adg792a";
+   reg = <0x50>;
+   #mux-control-cells = <1>;
+
+   idle-state = ;
+   };
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = < 2>;
+
+   channels = "sync-1", "", "out";
+   };
+
+
+   /*
+* Three parallel muxes with one mux controller, useful e.g. if
+* the adc is differential, thus needing two signals to be muxed
+* simultaneously for correct operation.
+*/
+{
+   pmux: mux-controller@50 {
+   compatible = "adi,adg792a";
+   reg = <0x50>;
+   #mux-control-cells = <0>;
+
+   idle-state = <1>;
+   };
+   };
+
+   diff-adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync-1", "", "out";
+   };
-- 
2.1.4



[PATCH v14 11/11] mux: adg792a: add mux controller driver for ADG792A/G

2017-04-24 Thread Peter Rosin
Analog Devices ADG792A/G is a triple 4:1 mux.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig   |  12 
 drivers/mux/Makefile  |   1 +
 drivers/mux/mux-adg792a.c | 157 ++
 3 files changed, 170 insertions(+)
 create mode 100644 drivers/mux/mux-adg792a.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index e580c2d028d2..34b8284d6d29 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -17,6 +17,18 @@ menuconfig MULTIPLEXER
 
 if MULTIPLEXER
 
+config MUX_ADG792A
+   tristate "Analog Devices ADG792A/ADG792G Multiplexers"
+   depends on I2C
+   help
+ ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
+
+ The driver supports both operating the three multiplexers in
+ parallel and operating them independently.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-adg792a.
+
 config MUX_GPIO
tristate "GPIO-controlled Multiplexer"
depends on GPIOLIB
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index bb16953f6290..b00a7d37d2fb 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)  += mux-core.o
+obj-$(CONFIG_MUX_ADG792A)  += mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
diff --git a/drivers/mux/mux-adg792a.c b/drivers/mux/mux-adg792a.c
new file mode 100644
index ..12aa221ab90d
--- /dev/null
+++ b/drivers/mux/mux-adg792a.c
@@ -0,0 +1,157 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define ADG792A_LDSW   BIT(0)
+#define ADG792A_RESETB BIT(1)
+#define ADG792A_DISABLE(mux)   (0x50 | (mux))
+#define ADG792A_DISABLE_ALL(0x5f)
+#define ADG792A_MUX(mux, state)(0xc0 | (((mux) + 1) << 2) | (state))
+#define ADG792A_MUX_ALL(state) (0xc0 | (state))
+
+static int adg792a_write_cmd(struct i2c_client *i2c, u8 cmd, int reset)
+{
+   u8 data = ADG792A_RESETB | ADG792A_LDSW;
+
+   /* ADG792A_RESETB is active low, the chip resets when it is zero. */
+   if (reset)
+   data &= ~ADG792A_RESETB;
+
+   return i2c_smbus_write_byte_data(i2c, cmd, data);
+}
+
+static int adg792a_set(struct mux_control *mux, int state)
+{
+   struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+   u8 cmd;
+
+   if (mux->chip->controllers == 1) {
+   /* parallel mux controller operation */
+   if (state == MUX_IDLE_DISCONNECT)
+   cmd = ADG792A_DISABLE_ALL;
+   else
+   cmd = ADG792A_MUX_ALL(state);
+   } else {
+   unsigned int controller = mux_control_get_index(mux);
+
+   if (state == MUX_IDLE_DISCONNECT)
+   cmd = ADG792A_DISABLE(controller);
+   else
+   cmd = ADG792A_MUX(controller, state);
+   }
+
+   return adg792a_write_cmd(i2c, cmd, 0);
+}
+
+static const struct mux_control_ops adg792a_ops = {
+   .set = adg792a_set,
+};
+
+static int adg792a_probe(struct i2c_client *i2c,
+const struct i2c_device_id *id)
+{
+   struct device *dev = >dev;
+   struct mux_chip *mux_chip;
+   s32 idle_state[3];
+   u32 cells;
+   int ret;
+   int i;
+
+   if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+   return -ENODEV;
+
+   ret = device_property_read_u32(dev, "#mux-control-cells", );
+   if (ret < 0)
+   return ret;
+   if (cells >= 2)
+   return -EINVAL;
+
+   mux_chip = devm_mux_chip_alloc(dev, cells ? 3 : 1, 0);
+   if (IS_ERR(mux_chip))
+   return PTR_ERR(mux_chip);
+
+   mux_chip->ops = _ops;
+
+   ret = adg792a_write_cmd(i2c, ADG792A_DISABLE_ALL, 1);
+   if (ret < 0)
+   return ret;
+
+   ret = device_property_read_u32_array(dev, "idle-state",
+(u32 *)idle_state,
+mux_chip->controllers);
+   if (ret < 0) {
+   idle_state[0] = MUX_IDLE_AS_IS;
+   idle_state[1] = MUX_IDLE_AS_IS;
+   idle_state[2] = MUX_IDLE_AS_IS;
+   }
+
+   for (i = 0; i < mux_chip->controllers; ++i) {
+   struct mux_control *mux = _chip->mux[i];
+
+   mux->states = 4;
+
+ 

[PATCH v14 08/11] dt-bindings: i2c: i2c-mux: document general purpose i2c-mux bindings

2017-04-24 Thread Peter Rosin
Describe how a general purpose multiplexer controller is used to mux an
i2c bus.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Reviewed-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../devicetree/bindings/i2c/i2c-mux-gpmux.txt  | 99 ++
 1 file changed, 99 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt 
b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt
new file mode 100644
index ..2907dab56298
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt
@@ -0,0 +1,99 @@
+General Purpose I2C Bus Mux
+
+This binding describes an I2C bus multiplexer that uses a mux controller
+from the mux subsystem to route the I2C signals.
+
+  .-.  .-.
+  | dev |  | dev |
+..'-'  '-'
+| SoC|   ||
+||  .+'
+|   .--. |  .--+child bus A, on MUX value set to 0
+|   | I2C  |-|--| Mux  |
+|   '--' |  '--+---+child bus B, on MUX value set to 1
+|   .--. | |'--++.
+|   | MUX- | | |   |||
+|   | Ctrl |-|-+.-.  .-.  .-.
+|   '--' |  | dev |  | dev |  | dev |
+''  '-'  '-'  '-'
+
+Required properties:
+- compatible: i2c-mux
+- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
+  port is connected to.
+- mux-controls: The phandle of the mux controller to use for operating the
+  mux.
+* Standard I2C mux properties. See i2c-mux.txt in this directory.
+* I2C child bus nodes. See i2c-mux.txt in this directory. The sub-bus number
+  is also the mux-controller state described in ../mux/mux-controller.txt
+
+Optional properties:
+- mux-locked: If present, explicitly allow unrelated I2C transactions on the
+  parent I2C adapter at these times:
+   + during setup of the multiplexer
+   + between setup of the multiplexer and the child bus I2C transaction
+   + between the child bus I2C transaction and releasing of the multiplexer
+   + during releasing of the multiplexer
+  However, I2C transactions to devices behind all I2C multiplexers connected
+  to the same parent adapter that this multiplexer is connected to are blocked
+  for the full duration of the complete multiplexed I2C transaction (i.e.
+  including the times covered by the above list).
+  If mux-locked is not present, the multiplexer is assumed to be parent-locked.
+  This means that no unrelated I2C transactions are allowed on the parent I2C
+  adapter for the complete multiplexed I2C transaction.
+  The properties of mux-locked and parent-locked multiplexers are discussed
+  in more detail in Documentation/i2c/i2c-topology.
+
+For each i2c child node, an I2C child bus will be created. They will
+be numbered based on their order in the device tree.
+
+Whenever an access is made to a device on a child bus, the value set
+in the relevant node's reg property will be set as the state in the
+mux controller.
+
+Example:
+   mux: mux-controller {
+   compatible = "gpio-mux";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   i2c-mux {
+   compatible = "i2c-mux";
+   mux-locked;
+   i2c-parent = <>;
+
+   mux-controls = <>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   i2c@1 {
+   reg = <1>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   ssd1307: oled@3c {
+   compatible = "solomon,ssd1307fb-i2c";
+   reg = <0x3c>;
+   pwms = < 4 3000>;
+   reset-gpios = < 7 1>;
+   reset-active-low;
+   };
+   };
+
+   i2c@3 {
+   reg = <3>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   pca9555: pca9555@20 {
+   compatible = "nxp,pca9555";
+   gpio-controller;
+   #gpio-cells = <2>;
+   reg = <0x20>;
+   };
+   };
+   };
-- 
2.1.4



[PATCH v14 06/11] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings

2017-04-24 Thread Peter Rosin
Describe how a multiplexer can be used to select which signal is fed to
an io-channel.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../bindings/iio/multiplexer/io-channel-mux.txt| 39 ++
 MAINTAINERS|  6 
 2 files changed, 45 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt

diff --git 
a/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt 
b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
new file mode 100644
index ..c82794002595
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
@@ -0,0 +1,39 @@
+I/O channel multiplexer bindings
+
+If a multiplexer is used to select which hardware signal is fed to
+e.g. an ADC channel, these bindings describe that situation.
+
+Required properties:
+- compatible : "io-channel-mux"
+- io-channels : Channel node of the parent channel that has multiplexed
+   input.
+- io-channel-names : Should be "parent".
+- #address-cells = <1>;
+- #size-cells = <0>;
+- mux-controls : Mux controller node to use for operating the mux
+- channels : List of strings, labeling the mux controller states.
+
+For each non-empty string in the channels property, an io-channel will
+be created. The number of this io-channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state. The mux controller state is described in
+../mux/mux-controller.txt
+
+Example:
+   mux: mux-controller {
+   compatible = "mux-gpio";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync", "in", "system-regulator";
+   };
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cfa080878e2..1cde195bba25 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6360,6 +6360,12 @@ F:   
Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
 F: Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
 F: drivers/iio/adc/envelope-detector.c
 
+IIO MULTIPLEXER
+M: Peter Rosin <p...@axentia.se>
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+
 IIO SUBSYSTEM AND DRIVERS
 M: Jonathan Cameron <ji...@kernel.org>
 R: Hartmut Knaack <knaac...@gmx.de>
-- 
2.1.4



[PATCH v14 01/11] devres: trivial whitespace fix

2017-04-24 Thread Peter Rosin
Everything else is indented with two spaces, so fix the odd one out.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/driver-model/devres.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/driver-model/devres.txt 
b/Documentation/driver-model/devres.txt
index bf34d5b3a733..efb8200819d6 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -335,7 +335,7 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
 
 PER-CPU MEM
   devm_alloc_percpu()
-- 
2.1.4



[PATCH v14 00/11] mux controller abstraction and iio/i2c muxes

2017-04-24 Thread Peter Rosin
ux state, it was possible
  to drop the state member from the mux_child struct.
- cleanup dt bindings for i2c-mux-simple, it had some of copy-paste
  problems from ots origin (i2c-mux-gpio).
- select the mux control subsystem in config for the i2c-mux-simple driver.
- add entries to MAINTAINERS and my sign-off, I'm now satisfied and know
  nothing in this to be ashamed of.

v1 -> v2 changes:  https://lkml.org/lkml/2016/11/17/918
- fixup export of mux_control_put reported by kbuild
- drop devicetree iio-ext-info property as noted by Lars-Peter,
  and replace the functionality by exposing all ext_info
  attributes of the parent channel for each of the muxed
  channels. A cache on top of that and each muxed channel
  gets its own view of the ext_info of the parent channel.
- implement idle-state for muxes
- clear out the cache on failure in order to force a mux
  update on the following use
- cleanup the probe of i2c-mux-simple driver
- fix a bug in the i2c-mux-simple driver, where failure in
  the selection of the mux caused a deadlock when the mux
  was later unconditionally deselected.

v1:  https://lkml.org/lkml/2016/11/16/812

Cheers,
peda

Peter Rosin (11):
  devres: trivial whitespace fix
  dt-bindings: document devicetree bindings for mux-controllers and
gpio-mux
  mux: minimal mux subsystem
  mux: gpio: add mux controller driver for gpio based multiplexers
  iio: inkern: api for manipulating ext_info of iio channels
  dt-bindings: iio: io-channel-mux: document io-channel-mux bindings
  iio: multiplexer: new iio category and iio-mux driver
  dt-bindings: i2c: i2c-mux: document general purpose i2c-mux bindings
  i2c: i2c-mux-gpmux: new driver
  dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G
mux
  mux: adg792a: add mux controller driver for ADG792A/G

 Documentation/ABI/testing/sysfs-class-mux  |  16 +
 .../devicetree/bindings/i2c/i2c-mux-gpmux.txt  |  99 
 .../bindings/iio/multiplexer/io-channel-mux.txt|  39 ++
 .../devicetree/bindings/mux/adi,adg792a.txt|  75 +++
 Documentation/devicetree/bindings/mux/gpio-mux.txt |  69 +++
 .../devicetree/bindings/mux/mux-controller.txt | 157 ++
 Documentation/driver-model/devres.txt  |  10 +-
 MAINTAINERS|  16 +
 drivers/Kconfig|   2 +
 drivers/Makefile   |   1 +
 drivers/i2c/muxes/Kconfig  |  13 +
 drivers/i2c/muxes/Makefile |   1 +
 drivers/i2c/muxes/i2c-mux-gpmux.c  | 173 ++
 drivers/iio/Kconfig|   1 +
 drivers/iio/Makefile   |   1 +
 drivers/iio/inkern.c   |  60 +++
 drivers/iio/multiplexer/Kconfig|  18 +
 drivers/iio/multiplexer/Makefile   |   6 +
 drivers/iio/multiplexer/iio-mux.c  | 459 
 drivers/mux/Kconfig|  46 ++
 drivers/mux/Makefile   |   7 +
 drivers/mux/mux-adg792a.c  | 157 ++
 drivers/mux/mux-core.c | 593 +
 drivers/mux/mux-gpio.c | 114 
 include/dt-bindings/mux/mux.h  |  16 +
 include/linux/iio/consumer.h   |  37 ++
 include/linux/mux/consumer.h   |  33 ++
 include/linux/mux/driver.h | 111 
 28 files changed, 2329 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-mux
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt
 create mode 100644 
Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/adi,adg792a.txt
 create mode 100644 Documentation/devicetree/bindings/mux/gpio-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
 create mode 100644 drivers/i2c/muxes/i2c-mux-gpmux.c
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-adg792a.c
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 drivers/mux/mux-gpio.c
 create mode 100644 include/dt-bindings/mux/mux.h
 create mode 100644 include/linux/mux/consumer.h
 create mode 100644 include/linux/mux/driver.h

-- 
2.1.4



Re: [PATCH] iio: inkern: fix a static checker error

2017-04-24 Thread Peter Rosin
On 2017-04-20 23:13, Peter Rosin wrote:
> On 2017-04-20 23:12, Lars-Peter Clausen wrote:
>> On 04/20/2017 11:01 PM, Peter Rosin wrote:
>>> Avoid this smatch error:
>>> drivers/iio/inkern.c:751 iio_read_avail_channel_raw() error: double unlock 
>>> 'mutex:>indio_dev->info_exist_lock'
>>
>> Looks good, but it's not just the smatch error, this is a real issue. This
>> even seems to be a endless loop, always jumping back to err_unlock.
> 
> Yes, it should probably go to stable too...

Nope, not an endless loop, but I of course only noticed after sending
a v2 [1] which falsely stated just that. Ignore that v2 patch and take
this one instead, for the reasons stated in my followup [2] to that
message.

Involving stable is probably not needed either...

Cheers,
peda

[1] https://lkml.org/lkml/2017/4/24/179
[2] https://lkml.org/lkml/2017/4/24/221

>>>
>>> Fixes: 00c5f80c2fad ("iio: inkern: add helpers to query available values 
>>> from channels")
>>> Signed-off-by: Peter Rosin <p...@axentia.se>
>>
>>> ---
>>>  drivers/iio/inkern.c | 4 +---
>>>  1 file changed, 1 insertion(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
>>> index 7a13535dc3e9..a3941bade6a7 100644
>>> --- a/drivers/iio/inkern.c
>>> +++ b/drivers/iio/inkern.c
>>> @@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel 
>>> *chan,
>>>  err_unlock:
>>> mutex_unlock(>indio_dev->info_exist_lock);
>>>  
>>> -   if (ret >= 0 && type != IIO_VAL_INT) {
>>> +   if (ret >= 0 && type != IIO_VAL_INT)
>>> /* raw values are assumed to be IIO_VAL_INT */
>>> ret = -EINVAL;
>>> -   goto err_unlock;
>>> -   }
>>>  
>>> return ret;
>>>  }
>>>
>>
> 



Re: [RFC v2 2/2] mux: mmio-based syscon mux controller

2017-04-24 Thread Peter Rosin
On 2017-04-24 18:12, Philipp Zabel wrote:
> This adds a driver for mmio-based syscon multiplexers controlled by a
> single bitfield in a syscon register range.

Single bitfield?

> 
> Signed-off-by: Philipp Zabel 
> ---
> Changes since v1:
>  - Renamed MUX_SYSCON to MUX_MMIO. Instead of obtaining the regmap via syscon,
>this could just as well map its own MMIO register range if a reg property
>was added.
>  - Replaced reg, bit-mask, and bit-shift properties with mux-reg-masks array
>to allow defining multiple mux bit-fields per mmio-mux instance.
>  - Changed mux-control-cells value to <1>, the cell value is an index into
>the mux-reg-masks array.
>  - Replaced idle-state with idle-states array.
>  - Stopped clobbering mux->cached_state, that is internal to the mux core.
> ---
>  drivers/mux/Kconfig|  13 
>  drivers/mux/Makefile   |   1 +
>  drivers/mux/mux-mmio.c | 162 
> +
>  3 files changed, 176 insertions(+)
>  create mode 100644 drivers/mux/mux-mmio.c
> 
> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
> index 34b8284d6d29e..e2bee25a1586e 100644
> --- a/drivers/mux/Kconfig
> +++ b/drivers/mux/Kconfig
> @@ -43,4 +43,17 @@ config MUX_GPIO
> To compile the driver as a module, choose M here: the module will
> be called mux-gpio.
>  
> +config MUX_MMIO
> + tristate "MMIO register bitfield-controlled Multiplexer"
> + depends on OF && MFD_SYSCON
> + help
> +   MMIO register bitfield-controlled Multiplexer controller.
> +
> +   The driver builds a single multiplexer controller using a bitfield
> +   in a syscon register. For N bit wide bitfields, there will be 2^N
> +   possible multiplexer states.

Multiple multiplexer controllers

> +
> +   To compile the driver as a module, choose M here: the module will
> +   be called mux-mmio.
> +
>  endif
> diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
> index b00a7d37d2fbe..6bac5b0fea137 100644
> --- a/drivers/mux/Makefile
> +++ b/drivers/mux/Makefile
> @@ -5,3 +5,4 @@
>  obj-$(CONFIG_MULTIPLEXER)+= mux-core.o
>  obj-$(CONFIG_MUX_ADG792A)+= mux-adg792a.o
>  obj-$(CONFIG_MUX_GPIO)   += mux-gpio.o
> +obj-$(CONFIG_MUX_MMIO)   += mux-mmio.o
> diff --git a/drivers/mux/mux-mmio.c b/drivers/mux/mux-mmio.c
> new file mode 100644
> index 0..0b011fb59f99b
> --- /dev/null
> +++ b/drivers/mux/mux-mmio.c
> @@ -0,0 +1,162 @@
> +/*
> + * MMIO register bitfield-controlled multiplexer driver
> + *
> + * Copyright (C) 2017 Pengutronix, Philipp Zabel 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +static int mux_mmio_set(struct mux_control *mux, int state)
> +{
> + struct regmap_field **fields = mux_chip_priv(mux->chip);
> + int index = mux - mux->chip->mux;

mux_control_get_index(mux) does exactly this.

> +
> + return regmap_field_write(fields[index], state);
> +}
> +
> +static const struct mux_control_ops mux_mmio_ops = {
> + .set = mux_mmio_set,
> +};
> +
> +static const struct of_device_id mux_mmio_dt_ids[] = {
> + { .compatible = "mmio-mux", },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids);
> +
> +static int mux_mmio_probe(struct platform_device *pdev)
> +{
> + struct device *dev = >dev;
> + struct device_node *np = dev->of_node;
> + struct regmap_field **fields;
> + struct mux_chip *mux_chip;
> + struct regmap *regmap;
> + s32 *idle_states;
> + u32 *reg_masks;
> + int num_fields;
> + int ret;
> + int i;
> +
> + regmap = syscon_node_to_regmap(np->parent);
> + if (IS_ERR(regmap)) {
> + ret = PTR_ERR(regmap);
> + dev_err(dev, "failed to get syscon regmap: %d\n", ret);
> + return ret;
> + }
> +
> + ret = of_property_count_u32_elems(np, "mux-reg-masks");
> + if (ret == 0 || ret % 2)
> + ret = -EINVAL;
> + if (ret > 0) {
> + num_fields = ret / 2;
> +
> + reg_masks = devm_kmalloc(dev, ret * sizeof(u32), GFP_KERNEL);
> + if (!reg_masks)
> + return -ENOMEM;
> +
> + ret = of_property_read_u32_array(np, "mux-reg-masks",
> +  reg_masks, ret);
> + }
> + if (ret < 0) {
> + dev_err(dev, "mux-reg-masks property missing or invalid: %d\n",
> + ret);
> + return ret;
> + }
> +
> + mux_chip = devm_mux_chip_alloc(dev, num_fields, num_fields *
> +sizeof(*fields));
> + if (IS_ERR(mux_chip))
> + return 

Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes

2017-04-24 Thread Peter Rosin
On 2017-04-24 12:52, Philipp Zabel wrote:
> On Mon, 2017-04-24 at 10:36 +0200, Peter Rosin wrote:
>> Hi!
>>
>> The big change since v13 is that the mux state is now locked with a mutex
>> instead of an rwsem. Other that that, it is mostly restructuring and doc
>> changes. There are a few other "real" changes as well, but those changes
>> feel kind of minor. I guess what I'm trying to say is that although the
>> list of changes for v14 is longish, it's still basically the same as last
>> time.
> 
> I have hooked this up to the video-multiplexer and now I trigger
> the lockdep debug_check_no_locks_held error message when selecting the
> mux input from userspace:
> 
> $ media-ctl --links "'imx6-mipi-csi2':1->'ipu1_csi0_mux':0[1]"
> [   66.258368] 
> [   66.259919] =
> [   66.265369] [ BUG: media-ctl/258 still has locks held! ]
> [   66.270810] 4.11.0-rc8-20170424-1+ #1305 Not tainted
> [   66.275863] -
> [   66.282158] 1 lock held by media-ctl/258:
> [   66.286464]  #0:  (>lock){+.+.+.}, at: [<8074a6c0>] 
> mux_control_select+0x24/0x50
> [   66.294424] 
> [   66.294424] stack backtrace:
> [   66.298980] CPU: 0 PID: 258 Comm: media-ctl Not tainted 4.11.0-rc8+ #1305
> [   66.306771] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> [   66.313334] Backtrace: 
> [   66.315858] [<8010e5a4>] (dump_backtrace) from [<8010e8ac>] 
> (show_stack+0x20/0x24)
> [   66.323473]  r7:80e518d0 r6:80e518d0 r5:600d0013 r4:
> [   66.329190] [<8010e88c>] (show_stack) from [<80496cf4>] 
> (dump_stack+0xb0/0xdc)
> [   66.336470] [<80496c44>] (dump_stack) from [<8017e404>] 
> (debug_check_no_locks_held+0xb8/0xbc)
> [   66.345043]  r9:ae8566b8 r8:ad88dc84 r7:ad88df58 r6:ad88dc84 r5:ad88df58 
> r4:ae856400
> [   66.352837] [<8017e34c>] (debug_check_no_locks_held) from [<8012b258>] 
> (do_exit+0x79c/0xcc8)
> [   66.361321] [<8012aabc>] (do_exit) from [<8012d25c>] 
> (do_group_exit+0x4c/0xcc)
> [   66.368581]  r7:00f8
> [   66.371161] [<8012d210>] (do_group_exit) from [<8012d2fc>] 
> (__wake_up_parent+0x0/0x30)
> [   66.379120]  r7:00f8 r6:76f71798 r5: r4:0001
> [   66.384837] [<8012d2dc>] (SyS_exit_group) from [<80109380>] 
> (ret_fast_syscall+0x0/0x1c)
> 
> That correctly warns that the media-ctl process caused the mux->lock to
> be locked and still held when the process exited. Do we need a usage
> counter based mechanism for muxes that are (indirectly) controlled from
> userspace?

Ok, so the difference is probably that the rwsem locking primitive
don't have any lockdep checking hooked up. Because the rwsem was
definitely held in the same way in v13 as the mutex is now held in
v14, so there's no fundamental difference.

So, yes, we can use some kind of refcount scheme to not hold an actual
mutex for the duration of the mux select/deselect, but that doesn't
really change anything. Userspace is still locking something, and that
seems dangerous. How do you make sure that mux_control_deselect is
called as it should?

What I don't like about abandoning the lock is that there is still a
need to support the multi-consumer case and then you need some way
of keeping track of waiters. A lock does this, and any attempt to open
code that will get messy.

What might be better is to support some kind of exclusive mux, i.e. a
mux that only allows one consumer per mux controller. Then the mux core
could trust that exclusive consumer to not fuck things up for itself and
thus have no lock at all for select/deselect for the exclusive case. Or
perhaps keep a refcount (as you suggested) for the exclusive case so
that mux_control_try_select still makes sense, because you still want
that, right? 

The question then becomes how to best tell the mux core that you want
an exclusive mux. I see two options. Either you declare a mux controller
as exclusive up front somehow (in the device tree presumably), or you
add a mux_control_get_exclusive call that makes further calls to
mux_control_get{,_exclusive} fail with -EBUSY. I think I like the
latter better, if that can be made to work...

Cheers,
peda


Re: [RFC v2 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings

2017-04-24 Thread Peter Rosin
On 2017-04-24 18:12, Philipp Zabel wrote:
> This adds device tree binding documentation for mmio-based syscon
> multiplexers controlled by a single bitfield in a syscon register
> range.

Single bitfield?

> 
> Signed-off-by: Philipp Zabel 
> ---
> Changes since v1:
>  - Replaced reg, bit-mask, and bit-shift properties with mux-reg-masks array
>to allow defining multiple mux bit-fields per mmio-mux instance.
>  - Changed mux-control-cells value to <1>, the cell value is an index into
>the mux-reg-masks array.
>  - Replaced idle-state with idle-states array.
> ---
>  Documentation/devicetree/bindings/mux/mmio-mux.txt | 60 
> ++
>  1 file changed, 60 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> 
> diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt 
> b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> new file mode 100644
> index 0..99282fa761c55
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> @@ -0,0 +1,60 @@
> +MMIO register bitfield-based multiplexer controller bindings
> +
> +Define register bitfields to be used to control multiplexers. The parent
> +device tree node must be a syscon node to provide register access.
> +
> +Required properties:
> +- compatible : "mmio-mux"
> +- #mux-control-cells : <1>
> +- mux-reg-masks : an array of register offset and pre-shifted bitfield mask
> +  pairs, each describing a single mux control.
> +* Standard mux-controller bindings as decribed in mux-controller.txt
> +
> +Optional properties:
> +- idle-states : if present, the state the muxes will have when idle. The
> + special state MUX_IDLE_AS_IS is the default.
> +
> +The multiplexer state is defined as the value of the bitfield described
> +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> +syscon.

This paragraph needs updating.

> +
> +Example:
> +
> + syscon {
> + compatible = "syscon";
> +
> + mux: mux-controller@3 {

You shouldn't do ...@3 if you don't have a reg property.

Cheers,
peda

> + compatible = "mmio-mux";
> + #mux-control-cells = <1>;
> +
> + mux-reg-masks = <0x3 0x30>, /* 0: reg 0x3, bits 5:4 */
> + <0x3 0x40>, /* 1: reg 0x3, bit 6 */
> + idle-states = , <0>;
> + };
> + };
> +
> + video-mux {
> + compatible = "video-mux";
> + mux-controls = < 0>;
> +
> + ports {
> + /* inputs 0..3 */
> + port@0 {
> + reg = <0>;
> + };
> + port@1 {
> + reg = <1>;
> + };
> + port@2 {
> + reg = <2>;
> + };
> + port@3 {
> + reg = <3>;
> + };
> +
> + /* output */
> + port@4 {
> + reg = <4>;
> + };
> + };
> + };
> 



Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes

2017-04-24 Thread Peter Rosin
On 2017-04-24 16:10, Philipp Zabel wrote:
> On Mon, 2017-04-24 at 13:37 +0200, Peter Rosin wrote:
>> On 2017-04-24 12:52, Philipp Zabel wrote:
>>> On Mon, 2017-04-24 at 10:36 +0200, Peter Rosin wrote:
>>>> Hi!
>>>>
>>>> The big change since v13 is that the mux state is now locked with a mutex
>>>> instead of an rwsem. Other that that, it is mostly restructuring and doc
>>>> changes. There are a few other "real" changes as well, but those changes
>>>> feel kind of minor. I guess what I'm trying to say is that although the
>>>> list of changes for v14 is longish, it's still basically the same as last
>>>> time.
>>>
>>> I have hooked this up to the video-multiplexer and now I trigger
>>> the lockdep debug_check_no_locks_held error message when selecting the
>>> mux input from userspace:
>>>
>>> $ media-ctl --links "'imx6-mipi-csi2':1->'ipu1_csi0_mux':0[1]"
>>> [   66.258368] 
>>> [   66.259919] =
>>> [   66.265369] [ BUG: media-ctl/258 still has locks held! ]
>>> [   66.270810] 4.11.0-rc8-20170424-1+ #1305 Not tainted
>>> [   66.275863] -
>>> [   66.282158] 1 lock held by media-ctl/258:
>>> [   66.286464]  #0:  (>lock){+.+.+.}, at: [<8074a6c0>] 
>>> mux_control_select+0x24/0x50
>>> [   66.294424] 
>>> [   66.294424] stack backtrace:
>>> [   66.298980] CPU: 0 PID: 258 Comm: media-ctl Not tainted 4.11.0-rc8+ #1305
>>> [   66.306771] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
>>> [   66.313334] Backtrace: 
>>> [   66.315858] [<8010e5a4>] (dump_backtrace) from [<8010e8ac>] 
>>> (show_stack+0x20/0x24)
>>> [   66.323473]  r7:80e518d0 r6:80e518d0 r5:600d0013 r4:
>>> [   66.329190] [<8010e88c>] (show_stack) from [<80496cf4>] 
>>> (dump_stack+0xb0/0xdc)
>>> [   66.336470] [<80496c44>] (dump_stack) from [<8017e404>] 
>>> (debug_check_no_locks_held+0xb8/0xbc)
>>> [   66.345043]  r9:ae8566b8 r8:ad88dc84 r7:ad88df58 r6:ad88dc84 r5:ad88df58 
>>> r4:ae856400
>>> [   66.352837] [<8017e34c>] (debug_check_no_locks_held) from [<8012b258>] 
>>> (do_exit+0x79c/0xcc8)
>>> [   66.361321] [<8012aabc>] (do_exit) from [<8012d25c>] 
>>> (do_group_exit+0x4c/0xcc)
>>> [   66.368581]  r7:00f8
>>> [   66.371161] [<8012d210>] (do_group_exit) from [<8012d2fc>] 
>>> (__wake_up_parent+0x0/0x30)
>>> [   66.379120]  r7:00f8 r6:76f71798 r5: r4:0001
>>> [   66.384837] [<8012d2dc>] (SyS_exit_group) from [<80109380>] 
>>> (ret_fast_syscall+0x0/0x1c)
>>>
>>> That correctly warns that the media-ctl process caused the mux->lock to
>>> be locked and still held when the process exited. Do we need a usage
>>> counter based mechanism for muxes that are (indirectly) controlled from
>>> userspace?
> [...]
>> The question then becomes how to best tell the mux core that you want
>> an exclusive mux. I see two options. Either you declare a mux controller
>> as exclusive up front somehow (in the device tree presumably), or you
>> add a mux_control_get_exclusive call that makes further calls to
>> mux_control_get{,_exclusive} fail with -EBUSY. I think I like the
>> latter better, if that can be made to work...
> 
> How about an atomic use_count on the mux_control, a bool shared that is
> only set by the first consumer, and controls whether selecting locks?

That has the drawback that it is hard to restore the mux-control in a safe
way so that exclusive consumers are allowed after the last shared consumer
puts the mux away. Agreed, it's a corner case, but I had this very similar
patch going through the compiler when I got this mail. Does it work as well
as what you suggested?

Cheers,
peda

diff --git a/Documentation/driver-model/devres.txt 
b/Documentation/driver-model/devres.txt
index e2343d9cbec7..5a7352a83124 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -342,7 +342,8 @@ MUX
   devm_mux_chip_free()
   devm_mux_chip_register()
   devm_mux_chip_unregister()
-  devm_mux_control_get()
+  devm_mux_control_get_shared()
+  devm_mux_control_get_exclusive()
   devm_mux_control_put()
 
 PER-CPU MEM
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c 
b/drivers/i2c/muxes/i2c-mux-gpmux.c
index 92cf5f48afe6..135d6baaebe5 100644
--- a/drivers/i2c/muxes/i2c-mux-gpmux.c
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -87,7 +87,7

Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes

2017-04-25 Thread Peter Rosin
On 2017-04-24 16:59, Philipp Zabel wrote:
> On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
> [...]
>>> How about an atomic use_count on the mux_control, a bool shared that is
>>> only set by the first consumer, and controls whether selecting locks?
>>
>> That has the drawback that it is hard to restore the mux-control in a safe
>> way so that exclusive consumers are allowed after the last shared consumer
>> puts the mux away.
> 
> True.
> 
>> Agreed, it's a corner case, but I had this very similar
>> patch going through the compiler when I got this mail. Does it work as well
>> as what you suggested?
> 
> Yes, this patch works just as well.

Right, as expected :-) However, I don't like it much. It divides the mux
consumers into two camps in a way that makes it difficult to select which
camp a consumer should be in.

E.g. consider the iio-mux. The current implementation only supports quick
accesses that fit the mux_control_get_shared case. But if that mux in the
future needs to grow continuous buffered accesses, I think there will be
pressure to switch it over to the exclusive mode. Because that is a lot
closer to what you are doing with the video-mux. And then what? It will be
impossible to predict if the end user is going to use buffered accesses or
not...

So, I think the best approach is to skip the distinction between shared
and exclusive consumers and instead implement the locking with an ordinary
semaphore (instead of the old rwsem or the current mutex). Semaphores don't
have the property that the same task should down/up them (mutexes require
that for lock/unlock, and is also the reason for the lockdep complaint) and
thus fits better for long-time use such as yours or the above iio-mux with
buffered accesses. It should also hopefully be cheaper that an rwsem, and
not have any downgrade_write calls thus possibly keeping Greg sufficiently
happy...

Sure, consumers can still dig themselves into a hole by not calling deselect
as they should, but at least I think it can be made to work w/o dividing the
consumers...

Cheers,
peda



Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes

2017-04-25 Thread Peter Rosin
On 2017-04-25 16:16, Peter Rosin wrote:
> On 2017-04-24 16:59, Philipp Zabel wrote:
>> On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
>> [...]
>>>> How about an atomic use_count on the mux_control, a bool shared that is
>>>> only set by the first consumer, and controls whether selecting locks?
>>>
>>> That has the drawback that it is hard to restore the mux-control in a safe
>>> way so that exclusive consumers are allowed after the last shared consumer
>>> puts the mux away.
>>
>> True.
>>
>>> Agreed, it's a corner case, but I had this very similar
>>> patch going through the compiler when I got this mail. Does it work as well
>>> as what you suggested?
>>
>> Yes, this patch works just as well.
> 
> Right, as expected :-) However, I don't like it much. It divides the mux
> consumers into two camps in a way that makes it difficult to select which
> camp a consumer should be in.
> 
> E.g. consider the iio-mux. The current implementation only supports quick
> accesses that fit the mux_control_get_shared case. But if that mux in the
> future needs to grow continuous buffered accesses, I think there will be
> pressure to switch it over to the exclusive mode. Because that is a lot
> closer to what you are doing with the video-mux. And then what? It will be
> impossible to predict if the end user is going to use buffered accesses or
> not...
> 
> So, I think the best approach is to skip the distinction between shared
> and exclusive consumers and instead implement the locking with an ordinary
> semaphore (instead of the old rwsem or the current mutex). Semaphores don't
> have the property that the same task should down/up them (mutexes require
> that for lock/unlock, and is also the reason for the lockdep complaint) and
> thus fits better for long-time use such as yours or the above iio-mux with
> buffered accesses. It should also hopefully be cheaper that an rwsem, and
> not have any downgrade_write calls thus possibly keeping Greg sufficiently
> happy...
> 
> Sure, consumers can still dig themselves into a hole by not calling deselect
> as they should, but at least I think it can be made to work w/o dividing the
> consumers...

Like this (only compile-tested). Philipp, it should work the same as with
the rwsem in v13 and earlier. At least for your case...

Cheers,
peda

diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index c02fa4dd2d09..f99b70d4e319 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -116,7 +116,7 @@ struct mux_chip *mux_chip_alloc(struct device *dev,
struct mux_control *mux = _chip->mux[i];

mux->chip = mux_chip;
-   mutex_init(>lock);
+   sema_init(>lock, 1);
mux->cached_state = MUX_CACHE_UNKNOWN;
mux->idle_state = MUX_IDLE_AS_IS;
}
@@ -372,12 +372,14 @@ int mux_control_select(struct mux_control *mux, unsigned 
int state)
 {
int ret;

-   mutex_lock(>lock);
+   ret = down_killable(>lock);
+   if (ret < 0)
+   return ret;

ret = __mux_control_select(mux, state);

if (ret < 0)
-   mutex_unlock(>lock);
+   up(>lock);

return ret;
 }
@@ -399,13 +401,13 @@ int mux_control_try_select(struct mux_control *mux, 
unsigned int state)
 {
int ret;

-   if (!mutex_trylock(>lock))
+   if (down_trylock(>lock))
return -EBUSY;

ret = __mux_control_select(mux, state);

if (ret < 0)
-   mutex_unlock(>lock);
+   up(>lock);

return ret;
 }
@@ -427,7 +429,7 @@ int mux_control_deselect(struct mux_control *mux)
mux->idle_state != mux->cached_state)
ret = mux_control_set(mux, mux->idle_state);

-   mutex_unlock(>lock);
+   up(>lock);

return ret;
 }
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 95269f40670a..43f65f80c275 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -15,7 +15,6 @@

 #include 
 #include 
-#include 
 #include 

 struct mux_chip;
@@ -44,7 +43,7 @@ struct mux_control_ops {
  * mux drivers.
  */
 struct mux_control {
-   struct mutex lock; /* protects the state of the mux */
+   struct semaphore lock; /* protects the state of the mux */

struct mux_chip *chip;
int cached_state;




Re: [RFC 2/5] i3c: Add core I3C infrastructure

2017-07-31 Thread Peter Rosin
On 2017-07-31 23:15, Boris Brezillon wrote:
> [1]https://www.mipi.org/MIPI_I3C_device_characteristics_register

Stupid non-programmers...

This part

65 41 0101  Accelerometer
66 42 0110  Gyroscope
67 43 0111  Magnetometer
68 44 01000100  Accel/Gyro Combo
69 45 01000101  Accel/Mag Combo
70 46 01000110  Accel/Gyro/Mag Combo

should *obviously* have been something like

65 41 0101  Accelerometer
66 42 0110  Gyroscope
67 43 0111  Accel/Gyro Combo
68 44 01000100  Magnetometer
69 45 01000101  Accel/Mag Combo
71 47 01000111  Accel/Gyro/Mag Combo

Cheers,
peda


Re: [PATCH v2 2/3] usb: chipidea: Hook into mux framework to toggle usb switch

2017-08-08 Thread Peter Rosin
On 2017-08-08 03:51, Stephen Boyd wrote:
> Quoting Peter Rosin (2017-07-31 03:33:22)
>> On 2017-07-14 23:40, Stephen Boyd wrote:
>>> @@ -1964,16 +1965,26 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
>>>  
>>>  static int udc_id_switch_for_device(struct ci_hdrc *ci)
>>>  {
>>> + int ret = 0;
>>> +
>>>   if (ci->is_otg)
>>>   /* Clear and enable BSV irq */
>>>   hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
>>>   OTGSC_BSVIS | OTGSC_BSVIE);
>>>  
>>> - return 0;
>>> + if (!ci_otg_is_fsm_mode(ci))
>>> + ret = mux_control_select(ci->platdata->usb_switch, 0);
>>> +
>>> + if (ci->is_otg && ret)
>>> + hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
>>> +
>>> + return ret;
>>>  }
>>>  
>>>  static void udc_id_switch_for_host(struct ci_hdrc *ci)
>>>  {
>>> + mux_control_deselect(ci->platdata->usb_switch);
>>> +
>>
>> This looks broken. You conditionally lock the mux and you unconditionally
>> unlock it. Quoting the mux_control_deselect doc:
>>
>>  * It is required that a single call is made to mux_control_deselect() for
>>  * each and every successful call made to either of mux_control_select() or
>>  * mux_control_try_select().
>>
>> Think of the mux as a semaphore with a max count of one. If you lock it,
>> you have to unlock it when you're done. If you didn't lock it, you have
>> zero business unlocking it. If you try to lock it but fail, you also have
>> no business unlocking it. Just like a semaphore.
> 
> Good catch. I've added a if (!ci_otg_is_fsm_mode()) check here.
> 
>>
>> Another point: I do not know if udc_id_switch_for_host is *only* called
>> when there has been a prior call to udc_id_switch_for_device that
>> succeeded or how this works exactly. But this all looks fragile. Using
>> mux_control_select and mux_control_deselect *must* be done in pairs.
>> If you want a mux to be locked for "a while", such as in this case, you
>> have to make sure you stay within the rules. There is no room for half
>> measures, or you will likely cause a deadlock when something unexpected
>> happens.
>>
> 
> Can you elaborate? Is it bad that we keep it "locked" while we're in
> host or device mode?

No no, that's good. You do not want some other consumer of the same mux
controller to clobber your state (in case it's shared), so you absolutely
want to have the mux locked when you want it to remain in a specific
position.

>  It looked like we paired the start/stop ops with
> each other so that the mux is properly managed across these ops.

Yes, it *looks* ok...

>  My
> testing hasn't shown a problem, but maybe there's some corner case
> you're thinking of? I'll double check the code.

...but since I do not know the usb code, I can't tell. What I worry about
is the usb core calling udc_id_switch_for_host or udc_id_switch_for_device
more than once without any call to the other in between. Maybe that is a
guarantee that the usb core makes? Or maybe it isn't? If e.g. there is a
third mode (or if one is added in the future), then the calls to
mux_control_select and mux_control_deselect would not be paired correctly.
Ok, sure, a third mode probably doesn't exist and will probably not be
added, but but but...

Also, what happens if udc_id_switch_for_device fails? Is it certain that
it will be called again before udc_id_switch_for_host is called, or is
the failure simply logged? If the latter, you might have a call to
mux_control_deselect without a preceding (and successful) call to
mux_control_select. That's fatal.

I have similar worries for host_start/host_stop, but for that case
host_stop is not allowed to fail, and it seems like a safe bet that
host_stop will only be called if host_start succeeds. So, I'm not as
worried there.

In other words, the question is if the usb core is designed to allow
this kind of "raw" resource administration in udc_id_switch_for_host and
udc_id_switch_for_device, or if you need to keep a local record of the
state so that you do not do double resource acquisition or attempt to
free resources you don't have?

I think I would feel better if the muxing for the device mode could
be done in a start/stop pair of function just like the host mode is
doing. Again, I don't know the usb code and don't know if such hooks
exist or not?

Cheers,
Peter


Re: [RESEND PATCH] staging: vboxvideo: remove dead gamma lut code

2017-08-08 Thread Peter Rosin
On 2017-08-07 11:21, Daniel Vetter wrote:
> On Fri, Aug 04, 2017 at 12:45:06PM +0200, Peter Rosin wrote:
>> The redundant fb helpers .load_lut, .gamma_set and .gamma_get are
>> no longer used. Remove the dead code that was not doing anything
>> sensible anyway.
>>
>> Signed-off-by: Peter Rosin <p...@axentia.se>
>> ---
>>  drivers/staging/vboxvideo/vbox_fb.c   | 15 ---
>>  drivers/staging/vboxvideo/vbox_mode.c |  5 -
>>  2 files changed, 20 deletions(-)
>>
>> [This time with an improved Cc list, sorry for the noise. For new
>>  people, please refer to https://lkml.org/lkml/2017/7/13/593 for
>>  context]
>>
>> Hi Daniel,
>>
>> Here it goes, but do you really need me to resend v5 14/14?
> 
> Well it's not yet on dri-devel, but our pre-merge CI bots can't read such
> instructions. They expect a clean new series that applies cleanly, as a
> top-post, when resending stuff.

Ok, noted for the next time. These things seem to vary from subsystem to
subsystem, so it's not trivial to get it right w/o investing serious time
looking things up. Anyway, sorry about the trouble.

> Anyway, applied.

Thanks!

Cheers,
Peter


Re: [PATCH 3/3] [media] cx231xx: only unregister successfully registered i2c adapters

2017-08-09 Thread Peter Rosin
On 2017-08-09 16:27, Mauro Carvalho Chehab wrote:
> Em Mon, 31 Jul 2017 15:38:52 +0200
> Peter Rosin <p...@axentia.se> escreveu:
> 
>> This prevents potentially scary debug messages from the i2c core.
>>
>> Signed-off-by: Peter Rosin <p...@axentia.se>
>> ---
>>  drivers/media/usb/cx231xx/cx231xx-core.c | 3 +++
>>  drivers/media/usb/cx231xx/cx231xx-i2c.c  | 3 ++-
>>  2 files changed, 5 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c 
>> b/drivers/media/usb/cx231xx/cx231xx-core.c
>> index 46646ecd2dbc..f372ad3917a8 100644
>> --- a/drivers/media/usb/cx231xx/cx231xx-core.c
>> +++ b/drivers/media/usb/cx231xx/cx231xx-core.c
>> @@ -1311,6 +1311,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
>>  dev->i2c_bus[0].i2c_period = I2C_SPEED_100K;/* 100 KHz */
>>  dev->i2c_bus[0].i2c_nostop = 0;
>>  dev->i2c_bus[0].i2c_reserve = 0;
>> +dev->i2c_bus[0].i2c_rc = -ENODEV;
>>  
>>  /* External Master 2 Bus */
>>  dev->i2c_bus[1].nr = 1;
>> @@ -1318,6 +1319,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
>>  dev->i2c_bus[1].i2c_period = I2C_SPEED_100K;/* 100 KHz */
>>  dev->i2c_bus[1].i2c_nostop = 0;
>>  dev->i2c_bus[1].i2c_reserve = 0;
>> +dev->i2c_bus[1].i2c_rc = -ENODEV;
>>  
>>  /* Internal Master 3 Bus */
>>  dev->i2c_bus[2].nr = 2;
>> @@ -1325,6 +1327,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
>>  dev->i2c_bus[2].i2c_period = I2C_SPEED_100K;/* 100kHz */
>>  dev->i2c_bus[2].i2c_nostop = 0;
>>  dev->i2c_bus[2].i2c_reserve = 0;
>> +dev->i2c_bus[2].i2c_rc = -ENODEV;
>>  
>>  /* register I2C buses */
>>  errCode = cx231xx_i2c_register(>i2c_bus[0]);
>> diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c 
>> b/drivers/media/usb/cx231xx/cx231xx-i2c.c
>> index 3e49517cb5e0..8ce6b815d16d 100644
>> --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
>> +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
>> @@ -553,7 +553,8 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
>>   */
>>  void cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
>>  {
>> -i2c_del_adapter(>i2c_adap);
>> +if (!bus->i2c_rc)
>> +i2c_del_adapter(>i2c_adap);
> 
> That doesn't sound right. what happens if i2c_rc is 1 or 2?
> 
> IMHO, the right would would be, instead:
> 
>   if (bus->i2c_rc >= 0)
>   i2c_del_adapter(>i2c_adap);

In theory, yes. But in practice i2c_add_adapter never returns >0, and is
also documented so.

Let me know if you still want an update. In that case I'll also fix the
precedent present in the context of patch 1/3, i.e.

if (0 != bus->i2c_rc)
...

Cheers,
peda


Re: [PATCH v3 0/5] iio: srf08: add support for similar devices and triggered buffers

2017-08-16 Thread Peter Rosin
On 2017-08-16 21:32, Andreas Klinger wrote:
> This patch series adds support for:
> - triggered buffer
> - ultrasonic devices srf02 and srf10
> 
> Thanks for the review of Peter and Wolfram.
> 
> @Wolfram: please let me know, if you want a separate patch for [PATCH 1/5]

I think what you should do is rebase to something fresher, such as the
togreg branch in the iio repo. As you have discovered, master branch is
lagging behind in that repo.

And I think Jonathan would like that as well, but perhaps it doesn't
make a difference for him?

Cheers,
peda


[PATCH v15 02/13] dt-bindings: document devicetree bindings for mux-controllers and gpio-mux

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Allow specifying that a single multiplexer controller can be used to
control several parallel multiplexers, thus enabling sharing of the
multiplexer controller by different consumers.

Add a binding for a first mux controller in the form of a GPIO based mux
controller.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/devicetree/bindings/mux/gpio-mux.txt |  69 +
 .../devicetree/bindings/mux/mux-controller.txt | 157 +
 MAINTAINERS|   6 +
 include/dt-bindings/mux/mux.h  |  16 +++
 4 files changed, 248 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/gpio-mux.txt
 create mode 100644 Documentation/devicetree/bindings/mux/mux-controller.txt
 create mode 100644 include/dt-bindings/mux/mux.h

diff --git a/Documentation/devicetree/bindings/mux/gpio-mux.txt 
b/Documentation/devicetree/bindings/mux/gpio-mux.txt
new file mode 100644
index ..b8f746344d80
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/gpio-mux.txt
@@ -0,0 +1,69 @@
+GPIO-based multiplexer controller bindings
+
+Define what GPIO pins are used to control a multiplexer. Or several
+multiplexers, if the same pins control more than one multiplexer.
+
+Required properties:
+- compatible : "gpio-mux"
+- mux-gpios : list of gpios used to control the multiplexer, least
+ significant bit first.
+- #mux-control-cells : <0>
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-state : if present, the state the mux will have when idle. The
+  special state MUX_IDLE_AS_IS is the default.
+
+The multiplexer state is defined as the number represented by the
+multiplexer GPIO pins, where the first pin is the least significant
+bit. An active pin is a binary 1, an inactive pin is a binary 0.
+
+Example:
+
+   mux: mux-controller {
+   compatible = "gpio-mux";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync-1", "in", "out", "sync-2";
+   };
+
+   i2c-mux {
+   compatible = "i2c-mux";
+   i2c-parent = <>;
+
+   mux-controls = <>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   i2c@0 {
+   reg = <0>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   ssd1307: oled@3c {
+   /* ... */
+   };
+   };
+
+   i2c@3 {
+   reg = <3>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   pca9555: pca9555@20 {
+   /* ... */
+   };
+   };
+   };
diff --git a/Documentation/devicetree/bindings/mux/mux-controller.txt 
b/Documentation/devicetree/bindings/mux/mux-controller.txt
new file mode 100644
index ..4f47e4bd2fa0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/mux-controller.txt
@@ -0,0 +1,157 @@
+Common multiplexer controller bindings
+==
+
+A multiplexer (or mux) controller will have one, or several, consumer devices
+that uses the mux controller. Thus, a mux controller can possibly control
+several parallel multiplexers. Presumably there will be at least one
+multiplexer needed by each consumer, but a single mux controller can of course
+control several multiplexers for a single consumer.
+
+A mux controller provides a number of states to its consumers, and the state
+space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer,
+0-7 for an 8-way multiplexer, etc.
+
+
+Consumers
+-
+
+Mux controller consumers should specify a list of mux controllers that they
+want to use with a property containing a 'mux-ctrl-list':
+
+   mux-ctrl-list ::=  [mux-ctrl-list]
+   single-mux-ctrl ::=  [mux-ctrl-specifier]
+   mux-ctrl-phandle : phandle to mux controller node
+   mux-ctrl-specifier : array of #mux-control-cells specifying the
+given mux controller (controller specific)
+
+Mux controller properties should be named "mux-controls". The exact meaning of
+each mux controller property must 

[PATCH v15 07/13] iio: multiplexer: new iio category and iio-mux driver

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

When a multiplexer changes how an iio device behaves (for example
by feeding different signals to an ADC), this driver can be used
to create one virtual iio channel for each multiplexer state.

Depends on the generic multiplexer subsystem.

Cache any ext_info values from the parent iio channel, creating a private
copy of the ext_info attributes for each multiplexer state/channel.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 MAINTAINERS   |   1 +
 drivers/iio/Kconfig   |   1 +
 drivers/iio/Makefile  |   1 +
 drivers/iio/multiplexer/Kconfig   |  18 ++
 drivers/iio/multiplexer/Makefile  |   6 +
 drivers/iio/multiplexer/iio-mux.c | 459 ++
 6 files changed, 486 insertions(+)
 create mode 100644 drivers/iio/multiplexer/Kconfig
 create mode 100644 drivers/iio/multiplexer/Makefile
 create mode 100644 drivers/iio/multiplexer/iio-mux.c

diff --git a/MAINTAINERS b/MAINTAINERS
index eea8432b2df1..c89d70c29089 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6479,6 +6479,7 @@ M:    Peter Rosin <p...@axentia.se>
 L: linux-...@vger.kernel.org
 S: Maintained
 F: Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+F: drivers/iio/multiplexer/iio-mux.c
 
 IIO SUBSYSTEM AND DRIVERS
 M: Jonathan Cameron <ji...@kernel.org>
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index a918270d6f54..b3c8c6ef0dff 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -83,6 +83,7 @@ source "drivers/iio/humidity/Kconfig"
 source "drivers/iio/imu/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/magnetometer/Kconfig"
+source "drivers/iio/multiplexer/Kconfig"
 source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 33fa4026f92c..93c769cd99bf 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -28,6 +28,7 @@ obj-y += humidity/
 obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
+obj-y += multiplexer/
 obj-y += orientation/
 obj-y += potentiometer/
 obj-y += potentiostat/
diff --git a/drivers/iio/multiplexer/Kconfig b/drivers/iio/multiplexer/Kconfig
new file mode 100644
index ..735a7b0e6fd8
--- /dev/null
+++ b/drivers/iio/multiplexer/Kconfig
@@ -0,0 +1,18 @@
+#
+# Multiplexer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Multiplexers"
+
+config IIO_MUX
+   tristate "IIO multiplexer driver"
+   select MULTIPLEXER
+   depends on OF || COMPILE_TEST
+   help
+ Say yes here to build support for the IIO multiplexer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-mux.
+
+endmenu
diff --git a/drivers/iio/multiplexer/Makefile b/drivers/iio/multiplexer/Makefile
new file mode 100644
index ..68be3c4abd07
--- /dev/null
+++ b/drivers/iio/multiplexer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O multiplexer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_MUX) += iio-mux.o
diff --git a/drivers/iio/multiplexer/iio-mux.c 
b/drivers/iio/multiplexer/iio-mux.c
new file mode 100644
index ..37ba007f8dca
--- /dev/null
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -0,0 +1,459 @@
+/*
+ * IIO multiplexer driver
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux_ext_info_cache {
+   char *data;
+   ssize_t size;
+};
+
+struct mux_child {
+   struct mux_ext_info_cache *ext_info_cache;
+};
+
+struct mux {
+   int cached_state;
+   struct mux_control *control;
+   struct iio_channel *parent;
+   struct iio_dev *indio_dev;
+   struct iio_chan_spec *chan;
+   struct iio_chan_spec_ext_info *ext_info;
+   struct mux_child *child;
+};
+
+static int iio_mux_select(struct mux *mux, int idx)
+{
+   struct mux_child *child = >child[idx];
+   struct iio_chan_spec const *chan = >chan[idx];
+   int ret;
+   int i;
+
+   ret = mux_control_select(mux->control, chan->channel);
+   if (ret < 0) {
+   mux->cached_state = -1;
+   return ret;
+   }
+
+   if (mux->cached_state == chan->channel)
+   return 0;
+
+   if (chan->ext_info) {
+   for (i = 0; chan->ext_info[i].name; ++i) {
+   

[PATCH v15 13/13] mux: mmio-based syscon mux controller

2017-05-14 Thread Peter Rosin
From: Philipp Zabel <p.za...@pengutronix.de>

This adds a driver for mmio-based syscon multiplexers controlled by
bitfields in a syscon register range.

Signed-off-by: Philipp Zabel <p.za...@pengutronix.de>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig|  13 +
 drivers/mux/Makefile   |   1 +
 drivers/mux/mux-mmio.c | 141 +
 3 files changed, 155 insertions(+)
 create mode 100644 drivers/mux/mux-mmio.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index c4d050645605..e8f1df74644c 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -43,4 +43,17 @@ config MUX_GPIO
  To compile the driver as a module, choose M here: the module will
  be called mux-gpio.
 
+config MUX_MMIO
+   tristate "MMIO register bitfield-controlled Multiplexer"
+   depends on (OF && MFD_SYSCON) || COMPILE_TEST
+   help
+ MMIO register bitfield-controlled Multiplexer controller.
+
+ The driver builds multiplexer controllers for bitfields in a syscon
+ register. For N bit wide bitfields, there will be 2^N possible
+ multiplexer states.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-mmio.
+
 endif
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index b00a7d37d2fb..6bac5b0fea13 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_MULTIPLEXER)  += mux-core.o
 obj-$(CONFIG_MUX_ADG792A)  += mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
+obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
diff --git a/drivers/mux/mux-mmio.c b/drivers/mux/mux-mmio.c
new file mode 100644
index ..37c1de359a70
--- /dev/null
+++ b/drivers/mux/mux-mmio.c
@@ -0,0 +1,141 @@
+/*
+ * MMIO register bitfield-controlled multiplexer driver
+ *
+ * Copyright (C) 2017 Pengutronix, Philipp Zabel <ker...@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int mux_mmio_set(struct mux_control *mux, int state)
+{
+   struct regmap_field **fields = mux_chip_priv(mux->chip);
+
+   return regmap_field_write(fields[mux_control_get_index(mux)], state);
+}
+
+static const struct mux_control_ops mux_mmio_ops = {
+   .set = mux_mmio_set,
+};
+
+static const struct of_device_id mux_mmio_dt_ids[] = {
+   { .compatible = "mmio-mux", },
+   { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids);
+
+static int mux_mmio_probe(struct platform_device *pdev)
+{
+   struct device *dev = >dev;
+   struct device_node *np = dev->of_node;
+   struct regmap_field **fields;
+   struct mux_chip *mux_chip;
+   struct regmap *regmap;
+   int num_fields;
+   int ret;
+   int i;
+
+   regmap = syscon_node_to_regmap(np->parent);
+   if (IS_ERR(regmap)) {
+   ret = PTR_ERR(regmap);
+   dev_err(dev, "failed to get regmap: %d\n", ret);
+   return ret;
+   }
+
+   ret = of_property_count_u32_elems(np, "mux-reg-masks");
+   if (ret == 0 || ret % 2)
+   ret = -EINVAL;
+   if (ret < 0) {
+   dev_err(dev, "mux-reg-masks property missing or invalid: %d\n",
+   ret);
+   return ret;
+   }
+   num_fields = ret / 2;
+
+   mux_chip = devm_mux_chip_alloc(dev, num_fields, num_fields *
+  sizeof(*fields));
+   if (IS_ERR(mux_chip))
+   return PTR_ERR(mux_chip);
+
+   fields = mux_chip_priv(mux_chip);
+
+   for (i = 0; i < num_fields; i++) {
+   struct mux_control *mux = _chip->mux[i];
+   struct reg_field field;
+   s32 idle_state = MUX_IDLE_AS_IS;
+   u32 reg, mask;
+   int bits;
+
+   ret = of_property_read_u32_index(np, "mux-reg-masks",
+2 * i, );
+   if (!ret)
+   ret = of_property_read_u32_index(np, "mux-reg-masks",
+2 * i + 1, );
+   if (ret < 0) {
+   dev_err(dev, "bitfield %d: failed to read mux-reg-masks 
property: %d\n",
+   i, ret);
+   return ret;
+   }
+
+   field.reg = reg;
+   field.msb = fls(mask) - 1;
+   field.lsb = ffs(mask) - 1;
+
+   if (mask != GENMASK(field.msb, field.lsb)) {
+   dev_err(dev, "bitfield %d: inval

[PATCH v15 09/13] i2c: i2c-mux-gpmux: new driver

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

This is a general purpose i2c mux that uses a multiplexer controlled by
the multiplexer subsystem to do the muxing.

The user can select if the mux is to be mux-locked and parent-locked
as described in Documentation/i2c/i2c-topology.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Wolfram Sang <w...@the-dreams.de>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/i2c/muxes/Kconfig |  13 +++
 drivers/i2c/muxes/Makefile|   1 +
 drivers/i2c/muxes/i2c-mux-gpmux.c | 173 ++
 3 files changed, 187 insertions(+)
 create mode 100644 drivers/i2c/muxes/i2c-mux-gpmux.c

diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index 1e160fc37ecc..2c64d0e0740f 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -30,6 +30,19 @@ config I2C_MUX_GPIO
  This driver can also be built as a module.  If so, the module
  will be called i2c-mux-gpio.
 
+config I2C_MUX_GPMUX
+   tristate "General Purpose I2C multiplexer"
+   select MULTIPLEXER
+   depends on OF || COMPILE_TEST
+   help
+ If you say yes to this option, support will be included for a
+ general purpose I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which in turn is controlled
+ by a MUX-controller from the MUX subsystem.
+
+ This driver can also be built as a module.  If so, the module
+ will be called i2c-mux-gpmux.
+
 config I2C_MUX_LTC4306
tristate "LTC LTC4306/5 I2C multiplexer"
select GPIOLIB
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index ff7618cd5312..4a67d3199877 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE)+= 
i2c-arb-gpio-challenge.o
 obj-$(CONFIG_I2C_DEMUX_PINCTRL)+= i2c-demux-pinctrl.o
 
 obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
+obj-$(CONFIG_I2C_MUX_GPMUX)+= i2c-mux-gpmux.o
 obj-$(CONFIG_I2C_MUX_LTC4306)  += i2c-mux-ltc4306.o
 obj-$(CONFIG_I2C_MUX_MLXCPLD)  += i2c-mux-mlxcpld.o
 obj-$(CONFIG_I2C_MUX_PCA9541)  += i2c-mux-pca9541.o
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c 
b/drivers/i2c/muxes/i2c-mux-gpmux.c
new file mode 100644
index ..92cf5f48afe6
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -0,0 +1,173 @@
+/*
+ * General Purpose I2C multiplexer
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux {
+   struct mux_control *control;
+
+   bool do_not_deselect;
+};
+
+static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
+{
+   struct mux *mux = i2c_mux_priv(muxc);
+   int ret;
+
+   ret = mux_control_select(mux->control, chan);
+   mux->do_not_deselect = ret < 0;
+
+   return ret;
+}
+
+static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+   struct mux *mux = i2c_mux_priv(muxc);
+
+   if (mux->do_not_deselect)
+   return 0;
+
+   return mux_control_deselect(mux->control);
+}
+
+static struct i2c_adapter *mux_parent_adapter(struct device *dev)
+{
+   struct device_node *np = dev->of_node;
+   struct device_node *parent_np;
+   struct i2c_adapter *parent;
+
+   parent_np = of_parse_phandle(np, "i2c-parent", 0);
+   if (!parent_np) {
+   dev_err(dev, "Cannot parse i2c-parent\n");
+   return ERR_PTR(-ENODEV);
+   }
+   parent = of_find_i2c_adapter_by_node(parent_np);
+   of_node_put(parent_np);
+   if (!parent)
+   return ERR_PTR(-EPROBE_DEFER);
+
+   return parent;
+}
+
+static const struct of_device_id i2c_mux_of_match[] = {
+   { .compatible = "i2c-mux", },
+   {},
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_of_match);
+
+static int i2c_mux_probe(struct platform_device *pdev)
+{
+   struct device *dev = >dev;
+   struct device_node *np = dev->of_node;
+   struct device_node *child;
+   struct i2c_mux_core *muxc;
+   struct mux *mux;
+   struct i2c_adapter *parent;
+   int children;
+   int ret;
+
+   if (!np)
+   return -ENODEV;
+
+   mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+   if (!mux)
+   return -ENOMEM;
+
+   mux->control = devm_mux_control_get(dev, NULL);
+   if (IS_ERR(mux->control)) {
+   if (PTR_ERR(mux->control) != -EPROBE_DEFER)
+   dev_err(dev, "failed to get control-mux\n");
+ 

[PATCH v15 05/13] iio: inkern: api for manipulating ext_info of iio channels

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Extend the inkern api with functions for reading and writing ext_info
of iio channels.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/iio/inkern.c | 60 
 include/linux/iio/consumer.h | 37 +++
 2 files changed, 97 insertions(+)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 7a13535dc3e9..8292ad4435ea 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -869,3 +869,63 @@ int iio_write_channel_raw(struct iio_channel *chan, int 
val)
return ret;
 }
 EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+   unsigned int i = 0;
+
+   if (!chan->channel->ext_info)
+   return i;
+
+   for (ext_info = chan->channel->ext_info; ext_info->name; ext_info++)
+   ++i;
+
+   return i;
+}
+EXPORT_SYMBOL_GPL(iio_get_channel_ext_info_count);
+
+static const struct iio_chan_spec_ext_info *iio_lookup_ext_info(
+   const struct iio_channel *chan,
+   const char *attr)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   if (!chan->channel->ext_info)
+   return NULL;
+
+   for (ext_info = chan->channel->ext_info; ext_info->name; ++ext_info) {
+   if (!strcmp(attr, ext_info->name))
+   return ext_info;
+   }
+
+   return NULL;
+}
+
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   ext_info = iio_lookup_ext_info(chan, attr);
+   if (!ext_info)
+   return -EINVAL;
+
+   return ext_info->read(chan->indio_dev, ext_info->private,
+ chan->channel, buf);
+}
+EXPORT_SYMBOL_GPL(iio_read_channel_ext_info);
+
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+  const char *buf, size_t len)
+{
+   const struct iio_chan_spec_ext_info *ext_info;
+
+   ext_info = iio_lookup_ext_info(chan, attr);
+   if (!ext_info)
+   return -EINVAL;
+
+   return ext_info->write(chan->indio_dev, ext_info->private,
+  chan->channel, buf, len);
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_ext_info);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 47eeec3218b5..5e347a9805fd 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -312,4 +312,41 @@ int iio_read_channel_scale(struct iio_channel *chan, int 
*val,
 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale);
 
+/**
+ * iio_get_channel_ext_info_count() - get number of ext_info attributes
+ *   connected to the channel.
+ * @chan:  The channel being queried
+ *
+ * Returns the number of ext_info attributes
+ */
+unsigned int iio_get_channel_ext_info_count(struct iio_channel *chan);
+
+/**
+ * iio_read_channel_ext_info() - read ext_info attribute from a given channel
+ * @chan:  The channel being queried.
+ * @attr:  The ext_info attribute to read.
+ * @buf:   Where to store the attribute value. Assumed to hold
+ * at least PAGE_SIZE bytes.
+ *
+ * Returns the number of bytes written to buf (perhaps w/o zero termination;
+ * it need not even be a string), or an error code.
+ */
+ssize_t iio_read_channel_ext_info(struct iio_channel *chan,
+ const char *attr, char *buf);
+
+/**
+ * iio_write_channel_ext_info() - write ext_info attribute from a given channel
+ * @chan:  The channel being queried.
+ * @attr:  The ext_info attribute to read.
+ * @buf:   The new attribute value. Strings needs to be zero-
+ * terminated, but the terminator should not be included
+ * in the below len.
+ * @len:   The size of the new attribute value.
+ *
+ * Returns the number of accepted bytes, which should be the same as len.
+ * An error code can also be returned.
+ */
+ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
+  const char *buf, size_t len);
+
 #endif
-- 
2.1.4



[PATCH v15 08/13] dt-bindings: i2c: i2c-mux: document general purpose i2c-mux bindings

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Describe how a general purpose multiplexer controller is used to mux an
i2c bus.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Reviewed-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../devicetree/bindings/i2c/i2c-mux-gpmux.txt  | 99 ++
 1 file changed, 99 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt 
b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt
new file mode 100644
index ..2907dab56298
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpmux.txt
@@ -0,0 +1,99 @@
+General Purpose I2C Bus Mux
+
+This binding describes an I2C bus multiplexer that uses a mux controller
+from the mux subsystem to route the I2C signals.
+
+  .-.  .-.
+  | dev |  | dev |
+..'-'  '-'
+| SoC|   ||
+||  .+'
+|   .--. |  .--+child bus A, on MUX value set to 0
+|   | I2C  |-|--| Mux  |
+|   '--' |  '--+---+child bus B, on MUX value set to 1
+|   .--. | |'--++.
+|   | MUX- | | |   |||
+|   | Ctrl |-|-+.-.  .-.  .-.
+|   '--' |  | dev |  | dev |  | dev |
+''  '-'  '-'  '-'
+
+Required properties:
+- compatible: i2c-mux
+- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
+  port is connected to.
+- mux-controls: The phandle of the mux controller to use for operating the
+  mux.
+* Standard I2C mux properties. See i2c-mux.txt in this directory.
+* I2C child bus nodes. See i2c-mux.txt in this directory. The sub-bus number
+  is also the mux-controller state described in ../mux/mux-controller.txt
+
+Optional properties:
+- mux-locked: If present, explicitly allow unrelated I2C transactions on the
+  parent I2C adapter at these times:
+   + during setup of the multiplexer
+   + between setup of the multiplexer and the child bus I2C transaction
+   + between the child bus I2C transaction and releasing of the multiplexer
+   + during releasing of the multiplexer
+  However, I2C transactions to devices behind all I2C multiplexers connected
+  to the same parent adapter that this multiplexer is connected to are blocked
+  for the full duration of the complete multiplexed I2C transaction (i.e.
+  including the times covered by the above list).
+  If mux-locked is not present, the multiplexer is assumed to be parent-locked.
+  This means that no unrelated I2C transactions are allowed on the parent I2C
+  adapter for the complete multiplexed I2C transaction.
+  The properties of mux-locked and parent-locked multiplexers are discussed
+  in more detail in Documentation/i2c/i2c-topology.
+
+For each i2c child node, an I2C child bus will be created. They will
+be numbered based on their order in the device tree.
+
+Whenever an access is made to a device on a child bus, the value set
+in the relevant node's reg property will be set as the state in the
+mux controller.
+
+Example:
+   mux: mux-controller {
+   compatible = "gpio-mux";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   i2c-mux {
+   compatible = "i2c-mux";
+   mux-locked;
+   i2c-parent = <>;
+
+   mux-controls = <>;
+
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   i2c@1 {
+   reg = <1>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   ssd1307: oled@3c {
+   compatible = "solomon,ssd1307fb-i2c";
+   reg = <0x3c>;
+   pwms = < 4 3000>;
+   reset-gpios = < 7 1>;
+   reset-active-low;
+   };
+   };
+
+   i2c@3 {
+   reg = <3>;
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   pca9555: pca9555@20 {
+   compatible = "nxp,pca9555";
+   gpio-controller;
+   #gpio-cells = <2>;
+   reg = <0x20>;
+   };
+   };
+   };
-- 
2.1.4



[PATCH v15 12/13] dt-bindings: add mmio-based syscon mux controller DT bindings

2017-05-14 Thread Peter Rosin
From: Philipp Zabel <p.za...@pengutronix.de>

This adds device tree binding documentation for mmio-based syscon
multiplexers controlled by a bitfields in a syscon register range.

Signed-off-by: Philipp Zabel <p.za...@pengutronix.de>
Acked-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/devicetree/bindings/mux/mmio-mux.txt | 60 ++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt

diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt 
b/Documentation/devicetree/bindings/mux/mmio-mux.txt
new file mode 100644
index ..a9bfb4d8b6ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
@@ -0,0 +1,60 @@
+MMIO register bitfield-based multiplexer controller bindings
+
+Define register bitfields to be used to control multiplexers. The parent
+device tree node must be a syscon node to provide register access.
+
+Required properties:
+- compatible : "mmio-mux"
+- #mux-control-cells : <1>
+- mux-reg-masks : an array of register offset and pre-shifted bitfield mask
+  pairs, each describing a single mux control.
+* Standard mux-controller bindings as decribed in mux-controller.txt
+
+Optional properties:
+- idle-states : if present, the state the muxes will have when idle. The
+   special state MUX_IDLE_AS_IS is the default.
+
+The multiplexer state of each multiplexer is defined as the value of the
+bitfield described by the corresponding register offset and bitfield mask pair
+in the mux-reg-masks array, accessed through the parent syscon.
+
+Example:
+
+   syscon {
+   compatible = "syscon";
+
+   mux: mux-controller {
+   compatible = "mmio-mux";
+   #mux-control-cells = <1>;
+
+   mux-reg-masks = <0x3 0x30>, /* 0: reg 0x3, bits 5:4 */
+   <0x3 0x40>, /* 1: reg 0x3, bit 6 */
+   idle-states = , <0>;
+   };
+   };
+
+   video-mux {
+   compatible = "video-mux";
+   mux-controls = < 0>;
+
+   ports {
+   /* inputs 0..3 */
+   port@0 {
+   reg = <0>;
+   };
+   port@1 {
+   reg = <1>;
+   };
+   port@2 {
+   reg = <2>;
+   };
+   port@3 {
+   reg = <3>;
+   };
+
+   /* output */
+   port@4 {
+   reg = <4>;
+   };
+   };
+   };
-- 
2.1.4



[PATCH v15 00/13] mux controller abstraction and iio/i2c muxes

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Hi Greg,

Philipp found problems in v14 with using a mutex for locking that was
the outcome of the review for v13, so I'm now using a semaphore instead
of the rwsem that was in v13. That at least got rid of the scary call
to downgrade_write. However, I'm still unsure about what you actually
meant with your comment about lack of sparse markings [1]. I did add
__must_check to the funcs that selects the mux, but I've got this
feeling that this is not what you meant?

Anyway, I have acted on all your comments from the v13 review, at
least I think I did. So, please apply.

[1] https://lkml.org/lkml/2017/4/21/794


v14 -> v15 changes
- Rebased onto v4.12-rc1
- Add the mmio-mux driver from Philipp Zabel to the end of the series.
- Using a mutex to lock the mux state did not work out for Philipp Zabel
  and his video-mux, which is locking the mux over long periods of time.
  So, switch to a semaphore (where different tasks can call down/up).
- Remove unused devm_mux_chip_free, devm_mux_chip_unregister and
  devm_mux_control_put. Those are currently unused and can be added when
  someone needs them.
- Add more words in the kernel-doc comments for mux_control_select,
  mux_control_try_select and mux_control_deselect on the calling rules.
- Add "|| COMPILE_TEST" to the Kconfig depends for all new drivers.

[older changes follow below]


This adds a new mux controller subsystem with an interface for accessing
mux controllers, along with three drivers providing the interface (gpio,
mmio and adg792) and two consumers (iio and i2c). This is done in a way
that several consumers can independently access the same mux controller
if one controller controls several multiplexers, thus allowing sharing.
But sharing is by no means required, of course. It is perfectly fine to
have a single consumer of a dedicated mux controller controlling only
one mux for said consumer.

The prediction is that the typical use case will be for gpio-based muxing
(which is also what drove the development), where the below schematics
show the flexibility with one gpio-based mux controller being shared by
the iio-mux and i2c-mux-gpmux drivers.

..
|GPO0|--.
|GPO1|. |
||| |
|| .---.
|| |dg4052a|
|| |   |
|ADC0|-|XX0| signal X0
|| | X1| signal X1
|| | X2| signal X2
|| | X3| signal X3
|| |   |
|SDA0|-|YY0| i2c segment Y0
|SCL0|--.  | Y1| i2c segment Y1
''  |  | Y2| i2c segment Y2
|  | Y3| i2c segment Y3
|  '---'
|0 1 2 3   (feed SCL0 to each of
|| | | |the 4 muxed segments)
'+-+-+-'

GPO0 and GPO1 may also be fed to further parallel muxers, which is perhaps
desired in a real application to minimize digital noise from the I2C Y
channel leaking into the analog X channel. I.e. it might be a good idea
to separate the analog and digital signals...

And the below hypothetical schematics indicate something similar but using
the I2C-based adg792a multiplexer instead.

..
|SDA0|--.
|SCL0|. |
||| |
|| .---.
|| |adg792a|
|| |   |
|ADC0|-|D1  S1A| signal S1A
|| |S1B| signal S1B
|| |S1C| signal S1C
|| |S1D| signal S1D
|| |   |
|SDA1|---+-|D2  S2A| i2c segment S2A
|SCL1|-. | |S2B| i2c segment S2B
'' | | |S2C| i2c segment S2C
   | | |S2D| i2c segment S2D
   | | |   |
   | '-|D3  S3A| i2c segment S3A
   |   |S3B| i2c segment S3B
   |   |S3C| i2c segment S3C
   |   |S3D| i2c segment S3D
   |   '---'
   | A B C D   A B C D  (feed SCL1 to each of
   | | | | |   | | | |   the 8 muxed segments)
   '-+-+-+-+---+-+-+-'


Background:

I have a piece of hardware that is using the same 3 GPIO pins
to control four 8-way muxes. Three of them control ADC lines
to an ADS1015 chip with an iio driver, and the last one
controls the SDA line of an i2c bus. We have some deployed
code to handle this, but you do not want to see it or ever
hear about it. I'm not sure why I even mention it. Anyway,
the situation has nagged me to no end for quite some time.

So, after first getting more intimate with the i2c muxing code
and later discovering the drivers/iio/inkern.c file and
writing a couple of drivers making use of it, I came up with
what I think is an acceptable solution; add a generic mux
controller driver (and subsystem) that is shared between all
instances, and combine that with an iio mux driver and a new

[PATCH v15 10/13] dt-bindings: mux-adg792a: document devicetree bindings for ADG792A/G mux

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Analog Devices ADG792A/G is a triple 4:1 mux.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Reviewed-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../devicetree/bindings/mux/adi,adg792a.txt| 75 ++
 1 file changed, 75 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mux/adi,adg792a.txt

diff --git a/Documentation/devicetree/bindings/mux/adi,adg792a.txt 
b/Documentation/devicetree/bindings/mux/adi,adg792a.txt
new file mode 100644
index ..96b787a69f50
--- /dev/null
+++ b/Documentation/devicetree/bindings/mux/adi,adg792a.txt
@@ -0,0 +1,75 @@
+Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers
+
+Required properties:
+- compatible : "adi,adg792a" or "adi,adg792g"
+- #mux-control-cells : <0> if parallel (the three muxes are bound together
+  with a single mux controller controlling all three muxes), or <1> if
+  not (one mux controller for each mux).
+* Standard mux-controller bindings as described in mux-controller.txt
+
+Optional properties for ADG792G:
+- gpio-controller : if present, #gpio-cells below is required.
+- #gpio-cells : should be <2>
+ - First cell is the GPO line number, i.e. 0 or 1
+ - Second cell is used to specify active high (0)
+   or active low (1)
+
+Optional properties:
+- idle-state : if present, array of states that the mux controllers will have
+  when idle. The special state MUX_IDLE_AS_IS is the default and
+  MUX_IDLE_DISCONNECT is also supported.
+
+States 0 through 3 correspond to signals A through D in the datasheet.
+
+Example:
+
+   /*
+* Three independent mux controllers (of which one is used).
+* Mux 0 is disconnected when idle, mux 1 idles in the previously
+* selected state and mux 2 idles with signal B.
+*/
+{
+   mux: mux-controller@50 {
+   compatible = "adi,adg792a";
+   reg = <0x50>;
+   #mux-control-cells = <1>;
+
+   idle-state = ;
+   };
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = < 2>;
+
+   channels = "sync-1", "", "out";
+   };
+
+
+   /*
+* Three parallel muxes with one mux controller, useful e.g. if
+* the adc is differential, thus needing two signals to be muxed
+* simultaneously for correct operation.
+*/
+{
+   pmux: mux-controller@50 {
+   compatible = "adi,adg792a";
+   reg = <0x50>;
+   #mux-control-cells = <0>;
+
+   idle-state = <1>;
+   };
+   };
+
+   diff-adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync-1", "", "out";
+   };
-- 
2.1.4



[PATCH v15 01/13] devres: trivial whitespace fix

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Everything else is indented with two spaces, so fix the odd one out.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/driver-model/devres.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/driver-model/devres.txt 
b/Documentation/driver-model/devres.txt
index e72587fe477d..af08b4cd7968 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -335,7 +335,7 @@ MEM
   devm_kzalloc()
 
 MFD
- devm_mfd_add_devices()
+  devm_mfd_add_devices()
 
 PER-CPU MEM
   devm_alloc_percpu()
-- 
2.1.4



[PATCH v15 03/13] mux: minimal mux subsystem

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Add a new minimalistic subsystem that handles multiplexer controllers.
When multiplexers are used in various places in the kernel, and the
same multiplexer controller can be used for several independent things,
there should be one place to implement support for said multiplexer
controller.

A single multiplexer controller can also be used to control several
parallel multiplexers, that are in turn used by different subsystems
in the kernel, leading to a need to coordinate multiplexer accesses.
The multiplexer subsystem handles this coordination.

Thanks go out to Lars-Peter Clausen, Jonathan Cameron, Rob Herring,
Wolfram Sang, Paul Gortmaker, Dan Carpenter, Colin Ian King, Greg
Kroah-Hartman and last but certainly not least to Philipp Zabel for
helpful comments, reviews, patches and general encouragement!

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 Documentation/ABI/testing/sysfs-class-mux |  16 +
 Documentation/driver-model/devres.txt |   5 +
 MAINTAINERS   |   3 +
 drivers/Kconfig   |   2 +
 drivers/Makefile  |   1 +
 drivers/mux/Kconfig   |  16 +
 drivers/mux/Makefile  |   5 +
 drivers/mux/mux-core.c| 547 ++
 include/linux/mux/consumer.h  |  32 ++
 include/linux/mux/driver.h| 108 ++
 10 files changed, 735 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-mux
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-core.c
 create mode 100644 include/linux/mux/consumer.h
 create mode 100644 include/linux/mux/driver.h

diff --git a/Documentation/ABI/testing/sysfs-class-mux 
b/Documentation/ABI/testing/sysfs-class-mux
new file mode 100644
index ..8715f9c7bd4f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-mux
@@ -0,0 +1,16 @@
+What:  /sys/class/mux/
+Date:  April 2017
+KernelVersion: 4.13
+Contact:   Peter Rosin <p...@axentia.se>
+Description:
+   The mux/ class sub-directory belongs to the Generic MUX
+   Framework and provides a sysfs interface for using MUX
+   controllers.
+
+What:  /sys/class/mux/muxchipN/
+Date:  April 2017
+KernelVersion: 4.13
+Contact:   Peter Rosin <p...@axentia.se>
+Description:
+   A /sys/class/mux/muxchipN directory is created for each
+   probed MUX chip where N is a simple enumeration.
diff --git a/Documentation/driver-model/devres.txt 
b/Documentation/driver-model/devres.txt
index af08b4cd7968..40e4787c399c 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -337,6 +337,11 @@ MEM
 MFD
   devm_mfd_add_devices()
 
+MUX
+  devm_mux_chip_alloc()
+  devm_mux_chip_register()
+  devm_mux_control_get()
+
 PER-CPU MEM
   devm_alloc_percpu()
   devm_free_percpu()
diff --git a/MAINTAINERS b/MAINTAINERS
index e17dd0bf2c9f..a0cce325b08e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8712,8 +8712,11 @@ F:   include/linux/spi/mmc_spi.h
 MULTIPLEXER SUBSYSTEM
 M: Peter Rosin <p...@axentia.se>
 S: Maintained
+F: Documentation/ABI/testing/mux/sysfs-class-mux*
 F: Documentation/devicetree/bindings/mux/
 F: include/linux/dt-bindings/mux/
+F: include/linux/mux/
+F: drivers/mux/
 
 MULTISOUND SOUND DRIVER
 M: Andrew Veliath <andre...@usa.net>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index ba2901e76769..505c676fa9c7 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -206,4 +206,6 @@ source "drivers/fsi/Kconfig"
 
 source "drivers/tee/Kconfig"
 
+source "drivers/mux/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index cfabd141dba2..dfdcda00bfe3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -181,3 +181,4 @@ obj-$(CONFIG_NVMEM) += nvmem/
 obj-$(CONFIG_FPGA) += fpga/
 obj-$(CONFIG_FSI)  += fsi/
 obj-$(CONFIG_TEE)  += tee/
+obj-$(CONFIG_MULTIPLEXER)  += mux/
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
new file mode 100644
index ..23ab2cde83b1
--- /dev/null
+++ b/drivers/mux/Kconfig
@@ -0,0 +1,16 @@
+#
+# Multiplexer devices
+#
+
+menuconfig MULTIPLEXER
+   tristate "Multiplexer subsystem"
+   help
+ Multiplexer controller subsystem. Multiplexers are used in a
+ variety of settings, and this subsystem abstracts their use
+ so that the rest of the kernel sees a common interface. When
+ multiple parallel multiplexers are controlled by one single
+ multiplexer controller, this subsystem also coordinates the
+ multiplexer accesses.
+
+ To compile the subsystem as a module, choose M her

[PATCH v15 04/13] mux: gpio: add mux controller driver for gpio based multiplexers

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

The driver builds a single multiplexer controller using a number
of gpio pins. For N pins, there will be 2^N possible multiplexer
states. The GPIO pins can be connected (by the hardware) to several
multiplexers, which in that case will be operated in parallel.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig|  18 
 drivers/mux/Makefile   |   1 +
 drivers/mux/mux-gpio.c | 114 +
 3 files changed, 133 insertions(+)
 create mode 100644 drivers/mux/mux-gpio.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 23ab2cde83b1..738670aaecb7 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -14,3 +14,21 @@ menuconfig MULTIPLEXER
 
  To compile the subsystem as a module, choose M here: the module will
  be called mux-core.
+
+if MULTIPLEXER
+
+config MUX_GPIO
+   tristate "GPIO-controlled Multiplexer"
+   depends on GPIOLIB || COMPILE_TEST
+   help
+ GPIO-controlled Multiplexer controller.
+
+ The driver builds a single multiplexer controller using a number
+ of gpio pins. For N pins, there will be 2^N possible multiplexer
+ states. The GPIO pins can be connected (by the hardware) to several
+ multiplexers, which in that case will be operated in parallel.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-gpio.
+
+endif
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 09f0299e109d..bb16953f6290 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)  += mux-core.o
+obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
diff --git a/drivers/mux/mux-gpio.c b/drivers/mux/mux-gpio.c
new file mode 100644
index ..468bf1709606
--- /dev/null
+++ b/drivers/mux/mux-gpio.c
@@ -0,0 +1,114 @@
+/*
+ * GPIO-controlled multiplexer driver
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct mux_gpio {
+   struct gpio_descs *gpios;
+   int *val;
+};
+
+static int mux_gpio_set(struct mux_control *mux, int state)
+{
+   struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
+   int i;
+
+   for (i = 0; i < mux_gpio->gpios->ndescs; i++)
+   mux_gpio->val[i] = (state >> i) & 1;
+
+   gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
+  mux_gpio->gpios->desc,
+  mux_gpio->val);
+
+   return 0;
+}
+
+static const struct mux_control_ops mux_gpio_ops = {
+   .set = mux_gpio_set,
+};
+
+static const struct of_device_id mux_gpio_dt_ids[] = {
+   { .compatible = "gpio-mux", },
+   { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
+
+static int mux_gpio_probe(struct platform_device *pdev)
+{
+   struct device *dev = >dev;
+   struct mux_chip *mux_chip;
+   struct mux_gpio *mux_gpio;
+   int pins;
+   s32 idle_state;
+   int ret;
+
+   pins = gpiod_count(dev, "mux");
+   if (pins < 0)
+   return pins;
+
+   mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
+  pins * sizeof(*mux_gpio->val));
+   if (IS_ERR(mux_chip))
+   return PTR_ERR(mux_chip);
+
+   mux_gpio = mux_chip_priv(mux_chip);
+   mux_gpio->val = (int *)(mux_gpio + 1);
+   mux_chip->ops = _gpio_ops;
+
+   mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
+   if (IS_ERR(mux_gpio->gpios)) {
+   ret = PTR_ERR(mux_gpio->gpios);
+   if (ret != -EPROBE_DEFER)
+   dev_err(dev, "failed to get gpios\n");
+   return ret;
+   }
+   WARN_ON(pins != mux_gpio->gpios->ndescs);
+   mux_chip->mux->states = 1 << pins;
+
+   ret = device_property_read_u32(dev, "idle-state", (u32 *)_state);
+   if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) {
+   if (idle_state < 0 || idle_state >= mux_chip->mux->states) {
+   dev_err(dev, "invalid idle-state %u\n", idle_state);
+   return -EINVAL;
+   }
+
+   mux_chip->mux->idle_state = idle_state;
+   }
+
+   ret = devm_mux_chip_register(dev, mux_chip);
+   if (ret < 0)
+   return ret;
+
+   dev_info(dev, 

[PATCH v15 11/13] mux: adg792a: add mux controller driver for ADG792A/G

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Analog Devices ADG792A/G is a triple 4:1 mux.

Reviewed-by: Jonathan Cameron <ji...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/mux/Kconfig   |  12 
 drivers/mux/Makefile  |   1 +
 drivers/mux/mux-adg792a.c | 157 ++
 3 files changed, 170 insertions(+)
 create mode 100644 drivers/mux/mux-adg792a.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index 738670aaecb7..c4d050645605 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -17,6 +17,18 @@ menuconfig MULTIPLEXER
 
 if MULTIPLEXER
 
+config MUX_ADG792A
+   tristate "Analog Devices ADG792A/ADG792G Multiplexers"
+   depends on I2C || COMPILE_TEST
+   help
+ ADG792A and ADG792G Wide Bandwidth Triple 4:1 Multiplexers
+
+ The driver supports both operating the three multiplexers in
+ parallel and operating them independently.
+
+ To compile the driver as a module, choose M here: the module will
+ be called mux-adg792a.
+
 config MUX_GPIO
tristate "GPIO-controlled Multiplexer"
depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index bb16953f6290..b00a7d37d2fb 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_MULTIPLEXER)  += mux-core.o
+obj-$(CONFIG_MUX_ADG792A)  += mux-adg792a.o
 obj-$(CONFIG_MUX_GPIO) += mux-gpio.o
diff --git a/drivers/mux/mux-adg792a.c b/drivers/mux/mux-adg792a.c
new file mode 100644
index ..12aa221ab90d
--- /dev/null
+++ b/drivers/mux/mux-adg792a.c
@@ -0,0 +1,157 @@
+/*
+ * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ *
+ * Author: Peter Rosin <p...@axentia.se>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define ADG792A_LDSW   BIT(0)
+#define ADG792A_RESETB BIT(1)
+#define ADG792A_DISABLE(mux)   (0x50 | (mux))
+#define ADG792A_DISABLE_ALL(0x5f)
+#define ADG792A_MUX(mux, state)(0xc0 | (((mux) + 1) << 2) | (state))
+#define ADG792A_MUX_ALL(state) (0xc0 | (state))
+
+static int adg792a_write_cmd(struct i2c_client *i2c, u8 cmd, int reset)
+{
+   u8 data = ADG792A_RESETB | ADG792A_LDSW;
+
+   /* ADG792A_RESETB is active low, the chip resets when it is zero. */
+   if (reset)
+   data &= ~ADG792A_RESETB;
+
+   return i2c_smbus_write_byte_data(i2c, cmd, data);
+}
+
+static int adg792a_set(struct mux_control *mux, int state)
+{
+   struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
+   u8 cmd;
+
+   if (mux->chip->controllers == 1) {
+   /* parallel mux controller operation */
+   if (state == MUX_IDLE_DISCONNECT)
+   cmd = ADG792A_DISABLE_ALL;
+   else
+   cmd = ADG792A_MUX_ALL(state);
+   } else {
+   unsigned int controller = mux_control_get_index(mux);
+
+   if (state == MUX_IDLE_DISCONNECT)
+   cmd = ADG792A_DISABLE(controller);
+   else
+   cmd = ADG792A_MUX(controller, state);
+   }
+
+   return adg792a_write_cmd(i2c, cmd, 0);
+}
+
+static const struct mux_control_ops adg792a_ops = {
+   .set = adg792a_set,
+};
+
+static int adg792a_probe(struct i2c_client *i2c,
+const struct i2c_device_id *id)
+{
+   struct device *dev = >dev;
+   struct mux_chip *mux_chip;
+   s32 idle_state[3];
+   u32 cells;
+   int ret;
+   int i;
+
+   if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+   return -ENODEV;
+
+   ret = device_property_read_u32(dev, "#mux-control-cells", );
+   if (ret < 0)
+   return ret;
+   if (cells >= 2)
+   return -EINVAL;
+
+   mux_chip = devm_mux_chip_alloc(dev, cells ? 3 : 1, 0);
+   if (IS_ERR(mux_chip))
+   return PTR_ERR(mux_chip);
+
+   mux_chip->ops = _ops;
+
+   ret = adg792a_write_cmd(i2c, ADG792A_DISABLE_ALL, 1);
+   if (ret < 0)
+   return ret;
+
+   ret = device_property_read_u32_array(dev, "idle-state",
+(u32 *)idle_state,
+mux_chip->controllers);
+   if (ret < 0) {
+   idle_state[0] = MUX_IDLE_AS_IS;
+   idle_state[1] = MUX_IDLE_AS_IS;
+   idle_state[2] = MUX_IDLE_AS_IS;
+   }
+
+   for (i = 0; i < mux_chip->controllers; ++i) {
+   struct mux_control *mux

[PATCH v15 06/13] dt-bindings: iio: io-channel-mux: document io-channel-mux bindings

2017-05-14 Thread Peter Rosin
From: Peter Rosin <p...@axentia.se>

Describe how a multiplexer can be used to select which signal is fed to
an io-channel.

Acked-by: Jonathan Cameron <ji...@kernel.org>
Acked-by: Rob Herring <r...@kernel.org>
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 .../bindings/iio/multiplexer/io-channel-mux.txt| 39 ++
 MAINTAINERS|  6 
 2 files changed, 45 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt

diff --git 
a/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt 
b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
new file mode 100644
index ..c82794002595
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
@@ -0,0 +1,39 @@
+I/O channel multiplexer bindings
+
+If a multiplexer is used to select which hardware signal is fed to
+e.g. an ADC channel, these bindings describe that situation.
+
+Required properties:
+- compatible : "io-channel-mux"
+- io-channels : Channel node of the parent channel that has multiplexed
+   input.
+- io-channel-names : Should be "parent".
+- #address-cells = <1>;
+- #size-cells = <0>;
+- mux-controls : Mux controller node to use for operating the mux
+- channels : List of strings, labeling the mux controller states.
+
+For each non-empty string in the channels property, an io-channel will
+be created. The number of this io-channel is the same as the index into
+the list of strings in the channels property, and also matches the mux
+controller state. The mux controller state is described in
+../mux/mux-controller.txt
+
+Example:
+   mux: mux-controller {
+   compatible = "mux-gpio";
+   #mux-control-cells = <0>;
+
+   mux-gpios = < 0 GPIO_ACTIVE_HIGH>,
+   < 1 GPIO_ACTIVE_HIGH>;
+   };
+
+   adc-mux {
+   compatible = "io-channel-mux";
+   io-channels = < 0>;
+   io-channel-names = "parent";
+
+   mux-controls = <>;
+
+   channels = "sync", "in", "system-regulator";
+   };
diff --git a/MAINTAINERS b/MAINTAINERS
index a0cce325b08e..eea8432b2df1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6474,6 +6474,12 @@ F:   
Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
 F: Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
 F: drivers/iio/adc/envelope-detector.c
 
+IIO MULTIPLEXER
+M: Peter Rosin <p...@axentia.se>
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+
 IIO SUBSYSTEM AND DRIVERS
 M: Jonathan Cameron <ji...@kernel.org>
 R: Hartmut Knaack <knaac...@gmx.de>
-- 
2.1.4



[PATCH] i2c: mux: only print failure message on error

2017-05-14 Thread Peter Rosin
As is, a failure message is printed unconditionally, which is confusing.
And noisy.

Fixes: 8d4d159f25a7 ("i2c: mux: provide more info on failure in 
i2c_mux_add_adapter")
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/i2c/i2c-mux.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 26f7237558ba..ccf2ce1836c8 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -395,18 +395,22 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(>adap);
-   dev_err(>dev,
-   "failed to add mux-adapter %u as bus %u (error=%d)\n",
-   chan_id, force_nr, ret);
+   if (ret < 0) {
+   dev_err(>dev,
+   "failed to add mux-adapter %u as bus %u 
(error=%d)\n",
+   chan_id, force_nr, ret);
+   kfree(priv);
+   return ret;
+   }
} else {
ret = i2c_add_adapter(>adap);
-   dev_err(>dev,
-   "failed to add mux-adapter %u (error=%d)\n",
-   chan_id, ret);
-   }
-   if (ret < 0) {
-   kfree(priv);
-   return ret;
+   if (ret < 0) {
+   dev_err(>dev,
+   "failed to add mux-adapter %u (error=%d)\n",
+   chan_id, ret);
+   kfree(priv);
+   return ret;
+   }
}
 
WARN(sysfs_create_link(>adap.dev.kobj, >dev->kobj,
-- 
2.1.4



[PATCH v2] i2c: mux: only print failure message on error

2017-05-15 Thread Peter Rosin
As is, a failure message is printed unconditionally, which is confusing.
And noisy.

Fixes: 8d4d159f25a7 ("i2c: mux: provide more info on failure in 
i2c_mux_add_adapter")
Signed-off-by: Peter Rosin <p...@axentia.se>
---
 drivers/i2c/i2c-mux.c | 26 --
 1 file changed, 16 insertions(+), 10 deletions(-)

Wolfram, you can take this one directly if you wish. You can also
take [1] (and optionally [2]) directly if you wish. Or just holler
and I'll send you a pull request with [1] and this patch for-current.

[1] i2c: mux: reg: put away the parent i2c adapter on probe failure
https://patchwork.ozlabs.org/patch/759487/

[2] i2c: mux: reg: rename label to indicate what it does
https://patchwork.ozlabs.org/patch/759486/

Changes since v1:
- Use goto instead of having two kfree, as pointed out by Leon Romanovsky.

Cheers,
peda

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 26f7237558ba..9669ca4937b8 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -395,18 +395,20 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(>adap);
-   dev_err(>dev,
-   "failed to add mux-adapter %u as bus %u (error=%d)\n",
-   chan_id, force_nr, ret);
+   if (ret < 0) {
+   dev_err(>dev,
+   "failed to add mux-adapter %u as bus %u 
(error=%d)\n",
+   chan_id, force_nr, ret);
+   goto err_free_priv;
+   }
} else {
ret = i2c_add_adapter(>adap);
-   dev_err(>dev,
-   "failed to add mux-adapter %u (error=%d)\n",
-   chan_id, ret);
-   }
-   if (ret < 0) {
-   kfree(priv);
-   return ret;
+   if (ret < 0) {
+   dev_err(>dev,
+   "failed to add mux-adapter %u (error=%d)\n",
+   chan_id, ret);
+   goto err_free_priv;
+   }
}
 
WARN(sysfs_create_link(>adap.dev.kobj, >dev->kobj,
@@ -422,6 +424,10 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
 
muxc->adapter[muxc->num_adapters++] = >adap;
return 0;
+
+err_free_priv:
+   kfree(priv);
+   return ret;
 }
 EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
 
-- 
2.1.4



Re: [PATCH] i2c: mux: only print failure message on error

2017-05-15 Thread Peter Rosin
On 2017-05-15 06:53, Leon Romanovsky wrote:
> On Sun, May 14, 2017 at 06:41:13PM +0200, Peter Rosin wrote:
>> As is, a failure message is printed unconditionally, which is confusing.
>> And noisy.
>>
>> Fixes: 8d4d159f25a7 ("i2c: mux: provide more info on failure in 
>> i2c_mux_add_adapter")
>> Signed-off-by: Peter Rosin <p...@axentia.se>
>> ---
>>  drivers/i2c/i2c-mux.c | 24 ++--
>>  1 file changed, 14 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
>> index 26f7237558ba..ccf2ce1836c8 100644
>> --- a/drivers/i2c/i2c-mux.c
>> +++ b/drivers/i2c/i2c-mux.c
>> @@ -395,18 +395,22 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
>>  if (force_nr) {
>>  priv->adap.nr = force_nr;
>>  ret = i2c_add_numbered_adapter(>adap);
>> -dev_err(>dev,
>> -"failed to add mux-adapter %u as bus %u (error=%d)\n",
>> -chan_id, force_nr, ret);
>> +if (ret < 0) {
>> +dev_err(>dev,
>> +"failed to add mux-adapter %u as bus %u 
>> (error=%d)\n",
>> +chan_id, force_nr, ret);
>> +kfree(priv);
>> +return ret;
>> +}
>>  } else {
>>  ret = i2c_add_adapter(>adap);
>> -dev_err(>dev,
>> -"failed to add mux-adapter %u (error=%d)\n",
>> -chan_id, ret);
>> -}
>> -if (ret < 0) {
>> -kfree(priv);
>> -return ret;
>> +if (ret < 0) {
>> +dev_err(>dev,
>> +"failed to add mux-adapter %u (error=%d)\n",
>> +chan_id, ret);
>> +kfree(priv);
>> +return ret;
> 
> It is better to add goto label, this will give one place for kfree->return 
> code.

I guess that can be argued, but it's going to end up being more lines. Whatever,
I'll just repaint the shed. v2 coming up.

Cheers,
peda



Re: [PATCH v2 2/3] iio: adc: at91-sama5d2_adc: add hw trigger and buffer support

2017-05-17 Thread Peter Rosin
On 2017-05-16 20:03, Jonathan Cameron wrote:
>  As we are only left with one area of questions.
>>>
>>> +static const struct at91_adc_trigger at91_adc_trigger_list[] = {
>>> +{
>>> +.name = "external-rising",
>>> +.trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_RISE,
>>> +},
>>> +{
>>> +.name = "external-falling",
>>> +.trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL,
>>> +},
>>> +{
>>> +.name = "external-any",
>>> +.trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY,
>>> +},
>> Hmm. Should this be a userspace configurable option?  Feels rather like
>> it is an element of the hardware - reflecting the characteristics of
>> some
>> hardware device sat on the pin.
> The user can choose from sysfs which trigger
> is best suited for the use case, since all
> three triggers are provided and can be connected to the buffer.
> It reflects more the triggering capability of the ADC rather than
> any different hardware device sitting on the pin

 I am also in favour of a userspace configurable option. For sure it's
 hardware related but on our board we only provide a trigger pin, we
 don't know which hardware the customer will put on this pin.
>>> hmm. OK I'm persuaded I think.
>>>
>>> Could do this with devicetree overlays or similar.
>>>
>>> So follow up question is whether this is the right interface.
>>> Can all 3 run at once sensibly?  If not are we not looking at a control
>>> parameter for a single trigger?
>>
>> There is a single trigger hardware pin, but can work in one of the three
>> modes. Do you suggest I should change it to a single trigger, but then
>> we need some kind of sysfs entry to control it ?
>>
>> Or perhaps change the trigger to be exclusive to the device/buffer, in
>> which case just one trigger can be used anyway with the current_trigger
>> option in buffer.
>>
>> If somehow more than one trigger would be enabled in the same time,
>> only the last enabled one will work, since I write the corresponding
>> trigger edge configuration value in the ADC register. So in fact these three 
>> triggers are mutually exclusive, as enabling one disables the
>> other, however, it's not transparent to the user.
> Ah that definitely suggests to me it should be a sysfs attribute associated
> with the trigger rather than 3 separate triggers.  The interpretation
> of those triggers would require userspace to have some knowledge of what
> is going on, so I don't think we have any problems by requiring it instead
> to know about a sysfs attribute.
>>
>> These kind of different edge triggers used to be in device tree in
>> older at91 driver.
>> I have given it thought and decided to let just the driver know about
>> them. Since they are bound to the ADC IP block and not related to any
>> hardware description of the board or the special connectivity that
>> the driver might be interested about. I mean the driver knows the
>> trigger works this way because it's part of the block, and device tree
>> cannot change this, so the portability of the driver is not affected
>> and related to SoC design only.
> Sort of (I think..)  As I understand it we are still talking about an
> external pin?  A possible usecase for this sort of thing would be
> combining with an external sequencer with an analog mux.  In that
> case only one of the options will make any sense. (this is the
> hardware equivalent of what Peter Rosin's mux subsystem puts
> under software control)
> 
> We might be in one of those interesting cases where a devicetree
> binding should exist for the fixed case, but with the flexibility
> to allow userspace to specify it if and only if it is not specified
> in the device tree.  So if the devicetree in some sense describes
> downstream hardware it is fixed as appropriate.  If it doesn't and
> we are looking at an 'edge of known world' situation then we let
> userspace have control?  Does that make sense?
> 
> I don't suppose we have any idea what this is actually used for
> on real world boards?
> 
> I've pulled in Peter, Mark and Rob as CCs to see if they want to
> comment.

>From what I can tell, this touches the mux code [1] for cases where
you have (some hypothetical) hardware of this style:

..
|a5d2|
||
|GPO0|--.
|GPO1|. |
||| |
|| .---.
|| |dg4052a|
|| |   |
| ADC|-|XX0| signal X0
|TRGR|--.  | X1| signal X1
||  |  | X2| signal X2
||  |  | X3| signal X3
||  |  |   |
||  '--|YY0| trigger Y0
|| | Y1| trigger Y1
'' | Y2| trigger Y2
   | Y3| trigger Y3
   '---'

Where signal X0 (when it's selected but the mux) should be sampled as
trigger Y0 is rising and 

Re: [PATCH v10 1/6] i2c: designware: Cleaning and comment style fixes.

2017-06-08 Thread Peter Rosin
On 2017-06-08 19:36, Luis Oliveira wrote:
> complicated to review. The work here won't bring any additional work to
> backported fixes because is just style and reordering.

I challenge that. If there is an old bug that existed before this patch
that is fixed in the future after this patch has been applied, it might
very well be hard_er_ to backport that fix to a point before this patch
has been applied. So, what do you mean?

> @@ -984,12 +984,12 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
>   }
>  
>   i2c_dw_disable_int(dev);
> - r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
> + ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
>dev_name(dev->dev), dev);

Two extra spaces needed to align with the opening bracket.

Cheers,
peda


Re: [PATCH v10 1/6] i2c: designware: Cleaning and comment style fixes.

2017-06-09 Thread Peter Rosin
On 2017-06-09 10:38, Andy Shevchenko wrote:
> On Fri, 2017-06-09 at 07:12 +0200, Peter Rosin wrote:
>> On 2017-06-08 19:36, Luis Oliveira wrote:
>>> @@ -984,12 +984,12 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
>>> }
>>>  
>>> i2c_dw_disable_int(dev);
>>> -   r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
>>> irq_flags,
>>> +   ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
>>> irq_flags,
>>>  dev_name(dev->dev), dev);
>>
> 
>> Two extra spaces needed to align with the opening bracket.
> 
> It's a bikeshedding, though it looks like v11 is needed anyway (see
> kbuild bot complains), thus it might be addressed as well.
> 

Bikeshedding or not, checkpatch.pl --strict notifies about the issue
with:

CHECK: Alignment should match open parenthesis

Cheers,
peda


Re: [PATCH] mux: adg792a: always require I2C support

2017-06-09 Thread Peter Rosin
On 2017-06-09 12:22, Arnd Bergmann wrote:
> COMPILE_TEST makes no sense when I2C is disabled, as the driver cannot compile
> in that configuration:

Ouch, thanks for catching!

Reviewed-by: Peter Rosin <p...@axentia.se>

Greg, I assume you will you be taking this?

Cheers,
peda


<    5   6   7   8   9   10   11   12   13   14   >