Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 4/6] clk: tegra20: init NDFLASH clock to sensible rate
From: Peter De Schrijver @ 2018-05-30  7:42 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Stefan Agner, boris.brezillon, dwmw2, computersforpeace,
	marek.vasut, robh+dt, mark.rutland, thierry.reding, mturquette,
	sboyd, dev, miquel.raynal, richard, marcel, krzk,
	benjamin.lindqvist, jonathanh, pgaikwad, mirza.krak, linux-mtd,
	linux-tegra, devicetree, linux-kernel, linux-clk
In-Reply-To: <04cdfdf5-33c5-b569-9cd7-dda1b9ea0baf@gmail.com>

On Tue, May 29, 2018 at 03:19:47PM +0300, Dmitry Osipenko wrote:
> On 29.05.2018 15:12, Stefan Agner wrote:
> > On 29.05.2018 09:48, Peter De Schrijver wrote:
> >> On Mon, May 28, 2018 at 05:53:08PM +0200, Stefan Agner wrote:
> >>> On 28.05.2018 09:55, Peter De Schrijver wrote:
> >>>> On Sun, May 27, 2018 at 11:54:40PM +0200, Stefan Agner wrote:
> >>>>> From: Lucas Stach <dev@lynxeye.de>
> >>>>>
> >>>>> Set up the NAND Flash controller clock to run at 150MHz
> >>>>> instead of the rate set by the bootloader. This is a
> >>>>> conservative rate which also yields good performance.
> >>>>>
> >>>>> Signed-off-by: Lucas Stach <dev@lynxeye.de>
> >>>>> Signed-off-by: Stefan Agner <stefan@agner.ch>
> >>>>> ---
> >>>>>  drivers/clk/tegra/clk-tegra20.c | 1 +
> >>>>>  1 file changed, 1 insertion(+)
> >>>>>
> >>>>> diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
> >>>>> index 0ee56dd04cec..dff8c425cd28 100644
> >>>>> --- a/drivers/clk/tegra/clk-tegra20.c
> >>>>> +++ b/drivers/clk/tegra/clk-tegra20.c
> >>>>> @@ -1049,6 +1049,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
> >>>>>  	{ TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >>>>>  	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >>>>>  	{ TEGRA20_CLK_VDE, TEGRA20_CLK_CLK_MAX, 300000000, 0 },
> >>>>> +	{ TEGRA20_CLK_NDFLASH, TEGRA20_CLK_PLL_P, 150000000, 0 },
> >>>>>  	/* must be the last entry */
> >>>>>  	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> >>>>>  };
> >>>>> --
> >>>>> 2.17.0
> >>>>>
> >>>>
> >>>> Maybe better to specify this in the Tegra20 dtsi? See
> >>>> "Assigned clock parents and rates" in
> >>>> Documentation/devicetree/bindings/clock/clock-bindings.txt
> >>>
> >>> assigned-clocks indeed works just fine for this case. Thanks for
> >>> bringing this up, will drop this patch and add the device tree
> >>> properties in v3.
> >>>
> >>> Hm, interesting that none of the Tegra device tree make use of the
> >>> feature so far. I guess there would be other cases where this would be
> >>> useful as well (the one just above, VDE?).
> >>>
> >>
> >> Yes, historically this feature wasn't available, so we used these init tables.
> >> Unfortunately it's not easy to get rid of them for parent and rate
> >> configuration, because new kernels should also work with existing DTBs, so we
> >> can't just add assigned-clock properties and remove the existing table
> >> entries. What we could do is use the CLK_IS_CRITICAL flag for all clocks which
> >> are only enabled by the init table. For not yet merged blocks, this is
> >> ofcourse not a concern.
> > 
> > Sure I understand.
> > 
> > Was just somewhat surprised that it isn't used at all yet (grep -r -e
> > assigned-clock arch/arm/boot/dts/tegra* returns nothing). After all,
> > assigned clocks bindings have been merged in 2014 :-)
> > 
> > At least "clk: tegra: Specify VDE clock rate" merged earlier this year
> > would have been a candidate already.
> 
> I wasn't even aware of existence of the assigned-clock properties, probably just
> like others.

This feature seems to be little used indeed. Not sure why.

Peter.

^ permalink raw reply

* Re: [PATCH 08/12] drm/bridge: tc358764: Add DSI to LVDS bridge driver
From: kbuild test robot @ 2018-05-30  7:45 UTC (permalink / raw)
  To: Maciej Purski
  Cc: kbuild-all, linux-kernel, linux-arm-kernel, linux-samsung-soc,
	devicetree, dri-devel, David Airlie, Rob Herring, Mark Rutland,
	Thierry Reding, Kukjin Kim, Krzysztof Kozlowski, Archit Taneja,
	Andrzej Hajda, Laurent Pinchart, Inki Dae, Joonyoung Shim,
	Seung-Woo Kim, Kyungmin Park, Marek Szyprowski, Bartlomiej
In-Reply-To: <1527500833-16005-9-git-send-email-m.purski@samsung.com>

Hi Maciej,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20180517]
[cannot apply to drm-exynos/exynos-drm/for-next robh/for-next drm/drm-next v4.17-rc6 v4.17-rc5 v4.17-rc4 v4.17-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Maciej-Purski/Add-TOSHIBA-TC358764-DSI-LVDS-bridge-driver/20180530-011258
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> drivers/gpu/drm/bridge/tc358764.c:193:14: sparse: incorrect type in assignment (different base types) @@    expected unsigned short [unsigned] [addressable] [usertype] addr @@    got ed] [addressable] [usertype] addr @@
   drivers/gpu/drm/bridge/tc358764.c:193:14:    expected unsigned short [unsigned] [addressable] [usertype] addr
   drivers/gpu/drm/bridge/tc358764.c:193:14:    got restricted __le16 [usertype] <noident>
>> drivers/gpu/drm/bridge/tc358764.c:197:24: sparse: cast to restricted __le32
>> drivers/gpu/drm/bridge/tc358764.c:175:5: sparse: symbol 'tc358764_read' was not declared. Should it be static?
>> drivers/gpu/drm/bridge/tc358764.c:204:5: sparse: symbol 'tc358764_write' was not declared. Should it be static?

vim +193 drivers/gpu/drm/bridge/tc358764.c

   174	
 > 175	int tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val)
   176	{
   177		struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
   178		const struct mipi_dsi_host_ops *ops = dsi->host->ops;
   179		struct mipi_dsi_msg msg = {
   180			.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM,
   181			.channel = dsi->channel,
   182			.flags = MIPI_DSI_MSG_USE_LPM,
   183			.tx_buf = &addr,
   184			.tx_len = 2,
   185			.rx_buf = val,
   186			.rx_len = 4
   187		};
   188		ssize_t ret;
   189	
   190		if (!ops || !ops->transfer)
   191			return -EINVAL;
   192	
 > 193		addr = cpu_to_le16(addr);
   194	
   195		ret = ops->transfer(dsi->host, &msg);
   196		if (ret >= 0)
 > 197			*val = le32_to_cpu(*val);
   198	
   199		dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
   200	
   201		return ret;
   202	}
   203	
 > 204	int tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)
   205	{
   206		struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
   207		const struct mipi_dsi_host_ops *ops = dsi->host->ops;
   208		u8 data[6];
   209		int ret;
   210		struct mipi_dsi_msg msg = {
   211			.type = MIPI_DSI_GENERIC_LONG_WRITE,
   212			.channel = dsi->channel,
   213			.flags = MIPI_DSI_MSG_USE_LPM | MIPI_DSI_MSG_REQ_ACK,
   214			.tx_buf = data,
   215			.tx_len = 6
   216		};
   217	
   218		if (!ops || !ops->transfer)
   219			return -EINVAL;
   220	
   221		data[0] = addr;
   222		data[1] = addr >> 8;
   223		data[2] = val;
   224		data[3] = val >> 8;
   225		data[4] = val >> 16;
   226		data[5] = val >> 24;
   227	
   228		ret = ops->transfer(dsi->host, &msg);
   229	
   230		return ret;
   231	}
   232	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [PATCH 02/11] PM / devfreq: Fix handling of min/max_freq == 0
From: Chanwoo Choi @ 2018-05-30  8:04 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Arnd Bergmann, Greg Kroah-Hartman,
	Rob Herring, Mark Rutland, linux-pm, devicetree, linux-kernel,
	Brian Norris, Douglas Anderson, Ørjan Eide,
	John Einar Reitan
In-Reply-To: <20180529185758.GG168650@google.com>

Hi,

On 2018년 05월 30일 03:57, Matthias Kaehlcke wrote:
> On Mon, May 28, 2018 at 03:37:47PM +0900, Chanwoo Choi wrote:
>> Hi,
>>
>> On 2018년 05월 26일 05:30, Matthias Kaehlcke wrote:
>>> Commit ab8f58ad72c4 ("PM / devfreq: Set min/max_freq when adding the
>>> devfreq device") initializes df->min/max_freq with the min/max OPP when
>>> the device is added. Later commit f1d981eaecf8 ("PM / devfreq: Use the
>>> available min/max frequency") adds df->scaling_min/max_freq and the
>>> following to the frequency adjustment code:
>>>
>>>   max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
>>>
>>> With the current handling of min/max_freq this is incorrect:
>>>
>>> Even though df->max_freq is now initialized to a value != 0 user space
>>> can still set it to 0, in this case max_freq would be 0 instead of
>>> df->scaling_max_freq as intended. In consequence the frequency adjustment
>>> is not performed:
>>>
>>>   if (max_freq && freq > max_freq) {
>>> 	freq = max_freq;
>>>
>>> To fix this set df->min/max freq to the min/max OPP in max/max_freq_store,
>>> when the user passes a value of 0. This also prevents df->max_freq from
>>> being set below the min OPP when df->min_freq is 0, and similar for
>>> min_freq. Since it is now guaranteed that df->min/max_freq can't be 0 the
>>> checks for this case can be removed.
>>>
>>> Fixes: f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency")
>>> Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>  drivers/devfreq/devfreq.c | 30 ++++++++++++++++++------------
>>>  1 file changed, 18 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>> index 0057ef5b0a98..67da4e7b486b 100644
>>> --- a/drivers/devfreq/devfreq.c
>>> +++ b/drivers/devfreq/devfreq.c
>>> @@ -283,11 +283,11 @@ int update_devfreq(struct devfreq *devfreq)
>>>  	max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
>>>  	min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq);
>>>  
>>> -	if (min_freq && freq < min_freq) {
>>> +	if (freq < min_freq) {
>>>  		freq = min_freq;
>>>  		flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
>>>  	}
>>> -	if (max_freq && freq > max_freq) {
>>> +	if (freq > max_freq) {
>>>  		freq = max_freq;
>>>  		flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
>>>  	}
>>> @@ -1123,17 +1123,20 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>  	struct devfreq *df = to_devfreq(dev);
>>>  	unsigned long value;
>>>  	int ret;
>>> -	unsigned long max;
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>>  	mutex_lock(&df->lock);
>>> -	max = df->max_freq;
>>> -	if (value && max && value > max) {
>>> -		ret = -EINVAL;
>>> -		goto unlock;
>>> +
>>> +	if (value) {
>>> +		if (value > df->max_freq) {
>>> +			ret = -EINVAL;
>>> +			goto unlock;
>>> +		}
>>> +	} else {
>>> +		value = df->profile->freq_table[df->profile->max_state - 1];
>>>  	}
>>
>> If you want to prevent that df->min_freq is zero, 
>> you should reinitialize 'value' as following.
>> Because freq_table must be in ascending order.
>> 	value = df->profile->freq_table[0];
> 
> Thanks for pointing this out!
> 
> The devfreq device I tested with (a Mali GPU) uses descending order
> for some reason, and I assumed that's the usual order.
> 
> https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-4.4/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c#208
> 
> It seems the ordering doesn't have any impact beyond this patch. If
> the order isn't mandatory for drivers that set up their own freq_table
> we should probably support both cases to be safe.

Prior to that 'freq_table' is optional. So, patch[1] initialize the 'freq_table'
by using OPP interface if 'freq_table' is NULL.
[1] commit 0ec09ac2cebe ("PM / devfreq: Set the freq_table of devfreq device")

Current devfreq recommend the ascending order for 'freq_table'.
But, as you know, it might be not enough to support them.

I agree that we should support the both cases (ascending or descending order).

Maybe, it might be not proper to access the freq_table[] directly
because we don't know the ordering style of 'freq_table'
if 'freq_table' is made by devfreq user instead of devfreq core.


> 
>>> @@ -1158,17 +1161,20 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>  	struct devfreq *df = to_devfreq(dev);
>>>  	unsigned long value;
>>>  	int ret;
>>> -	unsigned long min;
>>>  
>>>  	ret = sscanf(buf, "%lu", &value);
>>>  	if (ret != 1)
>>>  		return -EINVAL;
>>>  
>>>  	mutex_lock(&df->lock);
>>> -	min = df->min_freq;
>>> -	if (value && min && value < min) {
>>> -		ret = -EINVAL;
>>> -		goto unlock;
>>> +
>>> +	if (!value) {
>>> +		value = df->profile->freq_table[0];
>>
>> ditto.
>> 	value = df->profile->freq_table[df->profile->max_state - 1];
>>
>>> +	} else {
>>> +		if (value < df->min_freq) {
>>> +			ret = -EINVAL;
>>> +			goto unlock;
>>> +		}
>>>  	}
>>>  
>>>  	df->max_freq = value;
>>>
>>
>> Actually, min_freq_store() and max_freq_store() are very similar.
>> But, this patch changed the order of conditional statement as following:
>> If there is no special reason, you better to keep the same format
>> for the readability.
>>
>>
>> min_freq_store()
>> 	if (value) {
>> 		...
>> 	} else {
>> 		value = df->profile->freq_table[df->profile->max_state - 1];
>> 	}
>>
>>
>> max_freq_store()
>> 	if (!value) {
>> 		value = df->profile->freq_table[0];
>> 	} else {
>> 		...
>>
> 
> Agreed, better use the same format, I'll update it in the next revision.
> 
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* Re: [PATCH 01/13] dt-bindings: net: bluetooth: add support for Realtek Bluetooth chips
From: Hans de Goede @ 2018-05-30  8:04 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Johan Hedberg, Martin Blumenstingl, Rob Herring, Jeremy Cline,
	linux-bluetooth, linux-serial, linux-acpi, devicetree
In-Reply-To: <7A22F14E-9F45-4779-B7E5-CEB330A5601E@holtmann.org>

Hi,

On 30-05-18 08:42, Marcel Holtmann wrote:
> Hi Hans,
> 
>> This adds the documentation for Bluetooth functionality of the Realtek
>> RTL8723BS and RTL8723DS.
>> Both are SDIO wifi chips with an additional Bluetooth module which is
>> connected via UART to the host.
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> Signed-off-by: Jeremy Cline <jeremy@jcline.org>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> .../bindings/net/realtek-bluetooth.txt        | 41 +++++++++++++++++++
>> 1 file changed, 41 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/net/realtek-bluetooth.txt
>>
>> diff --git a/Documentation/devicetree/bindings/net/realtek-bluetooth.txt b/Documentation/devicetree/bindings/net/realtek-bluetooth.txt
>> new file mode 100644
>> index 000000000000..1491329c4cd1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/realtek-bluetooth.txt
>> @@ -0,0 +1,41 @@
>> +Realtek Bluetooth Chips
>> +-----------------------
>> +
>> +This documents the binding structure and common properties for serial
>> +attached Realtek devices.
>> +
>> +Serial attached Realtek devices shall be a child node of the host UART
>> +device the slave device is attached to. See ../serial/slave-device.txt
>> +for more information
>> +
>> +Required properties:
>> +- compatible: should contain one of the following:
>> +    * "realtek,rtl8723bs-bluetooth"
>> +    * "realtek,rtl8723ds-bluetooth"
>> +
>> +Optional properties:
>> +- realtek,config-data: Bluetooth chipset configuration data which is
>> +			needed for communication (it typically contains
>> +			board specific settings like the baudrate and
>> +			whether flow-control is used).
>> +			This is an array of u8 values.
>> +- enable-gpios: GPIO specifier, used to enable/disable the BT module
>> +- reset-gpios: GPIO specifier, used to reset the BT module
>> +
>> +
>> +Example:
>> +
>> +&uart {
>> +	...
>> +
>> +	bluetooth {
>> +		compatible = "realtek,rtl8723bs-bluetooth";
>> +		enable-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>;
>> +		reset-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
>> +		realtek,config-data = /bits/ 8 <
>> +			0x55 0xab 0x23 0x87 0x29 0x00 0xf4 0x00 0x01 0x01 0xf6 0x00
>> +			0x02 0x81 0x00 0xfa 0x00 0x02 0x12 0x80 0x0c 0x00 0x10 0x02
>> +			0x80 0x92 0x04 0x50 0xc5 0xea 0x19 0xe1 0x1b 0xfd 0xaf 0x5f
>> +			0x01 0xa4 0x0b 0xd9 0x00 0x01 0x0f 0xe4 0x00 0x01 0x08>;
>> +	};
>> +};
> 
> we actually need to agree on this config-data. As I wrote in an earlier email some time ago, the actual config-data files are just memory portions that will overload the default config area. I wrote tools/rtlfw.c to parse these.
> 
> So now I wonder if we can just read the current configuration and run with that when no extra blob is provided. That way it would always work and we might just give the config-data filename here. Mostly this is the for PCM and UART settings anyway.

I've been thinking about this too and 2 different solutions come to mind.

Note this is all x86 specific, I think it best to solve this for x86 first
and then we can apply the lessons learned there to ARM/devicetree when
someone comes along who wants to hook-up things on ARM.

My first idea was to stick with a config blob using the firmware_load
mechanism, but to add a postfix to the filename based on the ACPI
HID (hardware-id) of the serdev device, so in practice this means
we would try to load:

/lib/firmware/rtl_bt/rtl8723bs_config-OBDA8723.bin

On most x86 devices, so far all my testing on a bunch of different
devices has shown that the same config works for all x86 devices
(I took the config from a Chuwi Vi8 tablet which uses 3000000bps
+ hardware flowcontrol).

This way we can put the config in linux-firmware, without it
getting loaded on ARM boards where it might very well be wrong.


My second idea is to include a default config inside the driver,
which can be optionally overridden by a file in
/lib/firmware/rtl_bt and/or dt. Combined with module-options to
override the baudrate and flowcontrol setting (and patch the
builtin config accordingly).


Your idea to read back the config from the device is also
interesting, but I don't think that will gain us anything because
AFAIK the whole purpose of the board specific config file
bits is that the chip lack eeprom space to store this info,
so we will just always get some generic defaults.


I've run your rtlfw tool on a bunch of different config files and
there are a lot of unknown fields, and even of the known fields
I don't think we understand all the bits. So all in all the
config file is a bit of a black box and as such I believe it
would be best to just treat it as such and I personally
prefer my first idea, which is to add a postfix to the
firmware filename request, so on x86 load:

/lib/firmware/rtl_bt/rtl8723bs_config-OBDA8723.bin

And on devicetree we could postfix things with the machine
model string (as returned by  of_flat_dt_get_machine_name())


So Marcel, which direction do you think we should go?

Regards,

Hans

^ permalink raw reply

* Re: [PATCH 09/11] misc: throttler: Add core support for non-thermal throttling
From: Chanwoo Choi @ 2018-05-30  8:08 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: MyungJoo Ham, Kyungmin Park, Arnd Bergmann, Greg Kroah-Hartman,
	Rob Herring, Mark Rutland, linux-pm, devicetree, linux-kernel,
	Brian Norris, Douglas Anderson
In-Reply-To: <20180529205748.GJ168650@google.com>

Hi,

On 2018년 05월 30일 05:57, Matthias Kaehlcke wrote:
> On Mon, May 28, 2018 at 04:32:37PM +0900, Chanwoo Choi wrote:
> 
>> IMHO, you better to split out the devfreq patches from
>> 'throttler' patch set. Because I'm not sure throttler is either
>> necessary or not.
>>
>> After finishing the review of 'throttler' patches without devfreq handling,
>> it would be better for you to send devfreq patches separately.
> 
> I could certainly try to get 'throttler' with only cpufreq support
> merged, but that would kind of defeat the purpose.
> 
> I first sent a RFC patch for the devfreq policy notifiers
> (https://patchwork.kernel.org/patch/10401999/) to get an idea if this
> is a reasonable path to pursue. In response you asked about "real code
> and patches" and here it is :)
> 
> For my use case throttler is not really useful without devfreq
> support. In this sense I prefer to know 'early' if there are any
> blocking issues, rather then making the effort to get a limited
> version of the driver merged, and then learn that I wasted my own and
> the reviewers time because it is a dead end.

I'm never force to you. Just my opinion is how to make the patches
including the new concept. Thanks for your explanation why you send
the patch set with devfreq. 

> 
>> On 2018년 05월 26일 05:30, Matthias Kaehlcke wrote:
>>> The purpose of the throttler is to provide support for non-thermal
>>> throttling. Throttling is triggered by external event, e.g. the
>>> detection of a high battery discharge current, close to the OCP limit
>>> of the battery. The throttler is only in charge of the throttling, not
>>> the monitoring, which is done by another (possibly platform specific)
>>> driver.
>>>
>>> Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
>>> ---
>>>  drivers/misc/Kconfig            |   1 +
>>>  drivers/misc/Makefile           |   1 +
>>>  drivers/misc/throttler/Kconfig  |  13 ++
>>>  drivers/misc/throttler/Makefile |   1 +
>>>  drivers/misc/throttler/core.c   | 373 ++++++++++++++++++++++++++++++++
>>>  include/linux/throttler.h       |  10 +
>>>  6 files changed, 399 insertions(+)
>>>  create mode 100644 drivers/misc/throttler/Kconfig
>>>  create mode 100644 drivers/misc/throttler/Makefile
>>>  create mode 100644 drivers/misc/throttler/core.c
>>>  create mode 100644 include/linux/throttler.h
>>>
>>> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
>>> index 5d713008749b..691d9625d83c 100644
>>> --- a/drivers/misc/Kconfig
>>> +++ b/drivers/misc/Kconfig
>>> @@ -513,4 +513,5 @@ source "drivers/misc/echo/Kconfig"
>>>  source "drivers/misc/cxl/Kconfig"
>>>  source "drivers/misc/ocxl/Kconfig"
>>>  source "drivers/misc/cardreader/Kconfig"
>>> +source "drivers/misc/throttler/Kconfig"
>>>  endmenu
>>> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
>>> index 20be70c3f118..01a1714dd2ad 100644
>>> --- a/drivers/misc/Makefile
>>> +++ b/drivers/misc/Makefile
>>> @@ -57,3 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
>>>  obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
>>>  obj-$(CONFIG_OCXL)		+= ocxl/
>>>  obj-$(CONFIG_MISC_RTSX)		+= cardreader/
>>> +obj-y				+= throttler/
>>> diff --git a/drivers/misc/throttler/Kconfig b/drivers/misc/throttler/Kconfig
>>> new file mode 100644
>>> index 000000000000..ef8388f6bc0a
>>> --- /dev/null
>>> +++ b/drivers/misc/throttler/Kconfig
>>> @@ -0,0 +1,13 @@
>>> +menuconfig THROTTLER
>>> +	bool "Throttler support"
>>> +	default n
>>> +	depends on OF
>>> +	select CPU_FREQ
>>> +	select PM_DEVFREQ
>>> +	help
>>> +	  This option enables core support for non-thermal throttling of CPUs
>>> +	  and devfreq devices.
>>> +
>>> +	  Note that you also need a event monitor module usually called
>>> +	  *_throttler.
>>> +
>>> diff --git a/drivers/misc/throttler/Makefile b/drivers/misc/throttler/Makefile
>>> new file mode 100644
>>> index 000000000000..c8d920cee315
>>> --- /dev/null
>>> +++ b/drivers/misc/throttler/Makefile
>>> @@ -0,0 +1 @@
>>> +obj-$(CONFIG_THROTTLER)		+= core.o
>>> diff --git a/drivers/misc/throttler/core.c b/drivers/misc/throttler/core.c
>>> new file mode 100644
>>> index 000000000000..c058d03212b8
>>> --- /dev/null
>>> +++ b/drivers/misc/throttler/core.c
>>> @@ -0,0 +1,373 @@
>>> +/*
>>> + * Core code for non-thermal throttling
>>> + *
>>> + * Copyright (C) 2018 Google, Inc.
>>> + *
>>> + * This software is licensed under the terms of the GNU General Public
>>> + * License version 2, as published by the Free Software Foundation, and
>>> + * may be copied, distributed, and modified under those terms.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + */
>>> +
>>> +#include <linux/cpufreq.h>
>>> +#include <linux/devfreq.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/notifier.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/platform_device.h>
>>> +
>>> +/*
>>> + * Non-thermal throttling: throttling of system components in response to
>>> + * external events (e.g. high battery discharge current).
>>> + *
>>> + * The throttler supports throttling through cpufreq and devfreq. Multiple
>>> + * levels of throttling can be configured. At level 0 no throttling is
>>> + * active on behalf of the throttler, for values > 0 throttling is typically
>>> + * configured to be increasingly aggressive with each level.
>>> + * The number of throttling levels is not limited by the throttler (though
>>> + * it is likely limited by the throttling devices). It is not necessary to
>>> + * configure the same number of levels for all throttling devices. If the
>>> + * requested throttling level for a device is higher than the maximum level
>>> + * of the device the throttler will sleect the maximum throttling level of
>>> + * the device.
>>> + *
>>> + * Non-thermal throttling is split in two parts:
>>> + *
>>> + * - throttler core
>>> + *   - parses the thermal policy
>>> + *   - applies throttling settings for a requested level of throttling
>>> + *
>>> + * - event monitor driver
>>> + *   - monitors the events that trigger throttling
>>> + *   - determines the throttling level (often limited to on/off)
>>> + *   - requests throttler core to apply throttling settings
>>> + *
>>> + * It is possible for a system to have more than one throttler and the
>>> + * throttlers may make use of the same throttling devices, in case of
>>> + * conflicting settings for a device the more aggressive values will be
>>> + * applied.
>>> + *
>>> + */
>>> +
>>> +struct thrcfg {
>>> +	uint32_t *freqs;
>>> +	int num_levels;
>>> +};
>>> +
>>> +struct cpufreq_thrdev {
>>> +	uint32_t cpu;
>>> +	struct thrcfg cfg;
>>> +};
>>> +
>>> +struct devfreq_thrdev {
>>> +	struct devfreq *devfreq;
>>> +	struct thrcfg cfg;
>>> +	struct throttler *thr;
>>> +	struct notifier_block nb;
>>> +};
>>> +
>>> +struct __thr_cpufreq {
>>> +	struct cpufreq_thrdev *devs;
>>> +	int ndevs;
>>> +	struct notifier_block nb;
>>> +};
>>> +
>>> +struct __thr_devfreq {
>>> +	struct devfreq_thrdev *devs;
>>> +	int ndevs;
>>> +};
>>> +
>>> +struct throttler {
>>> +	struct device *dev;
>>> +	int level;
>>> +	struct __thr_cpufreq cpufreq;
>>> +	struct __thr_devfreq devfreq;
>>> +};
>>> +
>>> +static unsigned long thr_get_throttling_freq(struct thrcfg *cfg, int level)
>>> +{
>>> +	if (level == 0 ) {
>>> +		WARN(true, "level == 0");
>>> +		return 0;
>>> +	}
>>> +
>>> +	if (level <= cfg->num_levels)
>>> +		return cfg->freqs[level - 1];
>>> +	else
>>> +		return cfg->freqs[cfg->num_levels - 1];
>>> +}
>>> +
>>> +static int thr_cpufreq_event(struct notifier_block *nb,
>>> +				    unsigned long event, void *data)
>>> +{
>>> +	struct throttler *thr =
>>> +                container_of(nb, struct throttler, cpufreq.nb);
>>> +        struct cpufreq_policy *policy = data;
>>> +	struct cpufreq_thrdev *ctd;
>>> +	int i;
>>> +
>>> +	if ((event != CPUFREQ_ADJUST) || (thr->level == 0))
>>> +                return NOTIFY_DONE;
>>> +
>>> +	for (i = 0; i < thr->cpufreq.ndevs; i++) {
>>> +		ctd = &thr->cpufreq.devs[i];
>>> +
>>> +		if (ctd->cpu == policy->cpu) {
>>> +			unsigned long clamp_freq =
>>> +				thr_get_throttling_freq(&ctd->cfg, thr->level);
>>> +			if (clamp_freq < policy->max) {
>>> +				cpufreq_verify_within_limits(policy, 0, clamp_freq);
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	return NOTIFY_DONE;
>>> +}
>>> +
>>> +static int thr_devfreq_event(struct notifier_block *nb,
>>> +				    unsigned long event, void *data)
>>> +{
>>> +	struct devfreq_thrdev *dtd =
>>> +		container_of(nb, struct devfreq_thrdev, nb);
>>> +	struct throttler *thr = dtd->thr;
>>> +	struct devfreq_policy *policy = data;
>>> +	unsigned long clamp_freq;
>>> +
>>> +	if ((event != DEVFREQ_ADJUST) || (thr->level == 0))
>>> +                return NOTIFY_DONE;
>>> +
>>> +	clamp_freq = thr_get_throttling_freq(&dtd->cfg, thr->level);
>>> +	if (clamp_freq < policy->max)
>>> +		devfreq_verify_within_limits(policy, 0, clamp_freq);
>>> +
>>> +	return NOTIFY_DONE;
>>> +}
>>> +
>>> +static void thr_cpufreq_update_policy(struct throttler *thr)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < thr->cpufreq.ndevs; i++) {
>>> +		struct cpufreq_thrdev *ctd = &thr->cpufreq.devs[i];
>>> +		struct cpufreq_policy *policy = cpufreq_cpu_get(ctd->cpu);
>>> +
>>> +		if (!policy) {
>>> +			dev_warn(thr->dev, "CPU%d does have no cpufreq policy!\n", ctd->cpu);
>>> +			continue;
>>> +		}
>>> +
>>> +		cpufreq_update_policy(ctd->cpu);
>>> +		cpufreq_cpu_put(policy);
>>> +	}
>>> +}
>>> +
>>> +static int thr_parse_thrcfg(struct throttler *thr,
>>> +		struct device_node *np, struct thrcfg *cfg) {
>>> +	int err;
>>> +
>>> +	cfg->num_levels =
>>> +		of_property_count_u32_elems(np, "throttling-frequencies");
>>> +	if (cfg->num_levels < 0) {
>>> +		pr_err("%s: failed to determine number of throttling frequencies\n",
>>> +		       np->full_name);
>>> +		return cfg->num_levels;
>>> +	}
>>> +
>>> +	cfg->freqs = devm_kzalloc(thr->dev,
>>> +		cfg->num_levels * sizeof(u32), GFP_KERNEL);
>>> +	if (!cfg->freqs)
>>> +		return -ENOMEM;
>>> +
>>> +	err = of_property_read_u32_array(np, "throttling-frequencies",
>>> +		 cfg->freqs, cfg->num_levels);
>>> +	if (err) {
>>> +		pr_err("%s: failed to read throttling frequencies\n", np->full_name);
>>> +		return err;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct devfreq *thr_find_devfreq_dev(struct throttler *thr,
>>> +		struct device_node *np_df) {
>>> +	struct device_node *node;
>>> +	struct platform_device *pdev;
>>> +
>>> +	node = of_parse_phandle(np_df, "device", 0);
>>> +	if (!node) {
>>> +		pr_err("%s: failed to get devfreq parent device\n",
>>> +		       np_df->full_name);
>>> +		return ERR_PTR(-EINVAL);
>>> +	}
>>> +
>>> +	pdev = of_find_device_by_node(node);
>>> +	if (!pdev) {
>>> +		pr_err("%s: could not find devfreq parent device\n",
>>> +		       node->full_name);
>>> +		return ERR_PTR(-EINVAL);
>>> +	}
>>> +
>>> +	return dev_to_devfreq(&pdev->dev);
>>> +}
>>> +
>>> +static int thr_parse_dt(struct throttler *thr, struct device_node *np)
>>> +{
>>> +	struct device_node *node, *child;
>>> +	int err, i;
>>> +
>>> +	node = of_get_child_by_name(np, "cpufreq");
>>> +	if (node) {
>>> +		thr->cpufreq.ndevs = of_get_child_count(node);
>>> +		thr->cpufreq.devs = devm_kzalloc(thr->dev,
>>> +			sizeof(*thr->cpufreq.devs) * thr->cpufreq.ndevs,
>>> +			GFP_KERNEL);
>>> +
>>> +		i = 0;
>>> +		for_each_child_of_node(node, child) {
>>> +			struct cpufreq_thrdev *ctd = &thr->cpufreq.devs[i];
>>> +
>>> +			err = of_property_read_u32(child, "cpu", &ctd->cpu);
>>> +			if (err) {
>>> +				pr_err("%s: failed to read CPU id\n", child->full_name);
>>> +				return err;
>>> +			}
>>> +
>>> +			err = thr_parse_thrcfg(thr, child, &ctd->cfg);
>>> +			if (err)
>>> +				return err;
>>> +
>>> +			i++;
>>> +		}
>>> +	}
>>> +
>>> +	node = of_get_child_by_name(np, "devfreq");
>>> +	if (node) {
>>> +		thr->devfreq.ndevs = of_get_child_count(node);
>>> +		thr->devfreq.devs = devm_kzalloc(thr->dev,
>>> +			sizeof(*thr->devfreq.devs) * thr->devfreq.ndevs,
>>> +			GFP_KERNEL);
>>> +
>>> +		i = 0;
>>> +		for_each_child_of_node(node, child) {
>>> +			struct devfreq_thrdev *dtd = &thr->devfreq.devs[i];
>>> +
>>> +			dtd->thr = thr;
>>> +
>>> +			dtd->devfreq = thr_find_devfreq_dev(thr, child);
>>> +			if (IS_ERR(dtd->devfreq))
>>> +				return PTR_ERR(dtd->devfreq);
>>> +
>>> +			err = thr_parse_thrcfg(thr, child, &dtd->cfg);
>>> +			if (err)
>>> +				return err;
>>> +
>>> +			i++;
>>> +		}
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void thr_update_devfreq(struct devfreq *devfreq)
>>> +{
>>> +	mutex_lock(&devfreq->lock);
>>> +	update_devfreq(devfreq);
>>> +	mutex_unlock(&devfreq->lock);
>>> +}
>>> +
>>> +void throttler_set_level(struct throttler *thr, int level)
>>> +{
>>> +	int i;
>>> +
>>> +	if (level == thr->level)
>>> +		return;
>>> +
>>> +	dev_dbg(thr->dev, "throttling level: %d\n", level);
>>> +	thr->level = level;
>>> +
>>> +	if (thr->cpufreq.ndevs > 0)
>>> +		thr_cpufreq_update_policy(thr);
>>> +
>>> +	if (thr->devfreq.ndevs > 0)
>>> +		for (i = 0; i < thr->devfreq.ndevs; i++)
>>> +			thr_update_devfreq(thr->devfreq.devs[i].devfreq);
>>> +}
>>> +EXPORT_SYMBOL_GPL(throttler_set_level);
>>> +
>>> +struct throttler *throttler_setup(struct device *dev)
>>> +{
>>> +	struct throttler *thr;
>>> +	struct device_node *np = dev->of_node;
>>> +	int err, i;
>>> +
>>> +	if (!np)
>>> +		/* should never happen */
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	thr = devm_kzalloc(dev, sizeof(*thr), GFP_KERNEL);
>>> +	if (!thr)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	thr->dev = dev;
>>> +
>>> +	err = thr_parse_dt(thr, np);
>>> +	if (err)
>>> +		return ERR_PTR(err);
>>> +
>>> +	if (thr->cpufreq.ndevs > 0) {
>>> +		thr->cpufreq.nb.notifier_call = thr_cpufreq_event;
>>> +		err = cpufreq_register_notifier(&thr->cpufreq.nb,
>>> +						CPUFREQ_POLICY_NOTIFIER);
>>> +		if (err < 0) {
>>> +			dev_err(dev, "failed to register cpufreq notifier\n");
>>> +			return ERR_PTR(err);
>>> +		}
>>> +	}
>>> +
>>> +	for (i = 0; i < thr->devfreq.ndevs; i++) {
>>> +		struct devfreq_thrdev *dtd = &thr->devfreq.devs[i];
>>> +
>>> +		dtd->nb.notifier_call = thr_devfreq_event;
>>> +		err = devm_devfreq_register_notifier(dev, dtd->devfreq,
>>> +						     &dtd->nb, DEVFREQ_POLICY_NOTIFIER);
>>> +		if (err < 0) {
>>> +			dev_err(dev, "failed to register devfreq notifier\n");
>>> +			goto err_cpufreq_unregister;
>>> +		}
>>> +	}
>>> +
>>> +	return thr;
>>> +
>>> +err_cpufreq_unregister:
>>> +	if (thr->cpufreq.ndevs > 0)
>>> +		cpufreq_unregister_notifier(&thr->cpufreq.nb,
>>> +					    CPUFREQ_POLICY_NOTIFIER);
>>> +
>>> +	return ERR_PTR(err);
>>> +}
>>> +EXPORT_SYMBOL_GPL(throttler_setup);
>>> +
>>> +void throttler_teardown(struct throttler *thr)
>>> +{
>>> +	int i;
>>> +
>>> +	thr->level = 0;
>>> +
>>> +	if (thr->cpufreq.ndevs > 0) {
>>> +		thr_cpufreq_update_policy(thr);
>>> +
>>> +		cpufreq_unregister_notifier(&thr->cpufreq.nb,
>>> +					    CPUFREQ_POLICY_NOTIFIER);
>>> +	}
>>> +
>>> +	if (thr->devfreq.ndevs > 0)
>>> +		for (i = 0; i < thr->devfreq.ndevs; i++)
>>> +			thr_update_devfreq(thr->devfreq.devs[i].devfreq);
>>> +}
>>> +EXPORT_SYMBOL_GPL(throttler_teardown);
>>> diff --git a/include/linux/throttler.h b/include/linux/throttler.h
>>> new file mode 100644
>>> index 000000000000..cab8c466da4b
>>> --- /dev/null
>>> +++ b/include/linux/throttler.h
>>> @@ -0,0 +1,10 @@
>>> +#ifndef __LINUX_THROTTLER_H__
>>> +#define __LINUX_THROTTLER_H__
>>> +
>>> +struct throttler;
>>> +
>>> +extern struct throttler *throttler_setup(struct device *dev);
>>> +extern void throttler_teardown(struct throttler *thr);
>>> +extern void throttler_set_level(struct throttler *thr, int level);
>>> +
>>> +#endif /* __LINUX_THROTTLER_H__ */
>>>
> 
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* Re: [PATCH v14 0/2] Kryo CPU scaling driver
From: Rafael J. Wysocki @ 2018-05-30  8:08 UTC (permalink / raw)
  To: Ilia Lin
  Cc: Viresh Kumar, Nishanth Menon, Stephen Boyd, Rob Herring,
	Mark Rutland, Rafael J. Wysocki, Linux PM,
	devicetree@vger.kernel.org, Linux Kernel Mailing List
In-Reply-To: <1527250067-1256-1-git-send-email-ilialin@codeaurora.org>

On Fri, May 25, 2018 at 2:07 PM, Ilia Lin <ilialin@codeaurora.org> wrote:
> [v14]
>  * Addressed comment from Sudeep about DT compatible
>  * Added MAINTAINERS entry

This causes a build issue to occur in my bleeding-edge branch.

Does it depend on anything new in arm-soc?

Thanks,
Rafael

^ permalink raw reply

* RE: [PATCH v3 2/3] arm: shmobile: Add the R9A06G032 SMP enabler driver
From: Michel Pollet @ 2018-05-30  8:19 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Linux-Renesas, Simon Horman, Michel Pollet, Mark Rutland,
	Phil Edworthy, Florian Fainelli, Rajendra Nayak, Juri Lelli,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Greg Kroah-Hartman, Stefan Wahren, Magnus Damm, Russell King,
	Linux Kernel Mailing List, Chen-Yu Tsai, Rob Herring,
	Carlo Caione, Kevin Hilman <khilma>
In-Reply-To: <CAMuHMdWv2ZRbX=k5+H_WfAeoQ4QsyQLU9iQ9TJ9OQ0fmwg0GOQ@mail.gmail.com>


On 25 May 2018 10:49, Geert wrote:
> Subject: Re: [PATCH v3 2/3] arm: shmobile: Add the R9A06G032 SMP enabler
> driver
>
> Hi Michel,

Hi Geert,

>
> On Thu, May 24, 2018 at 12:30 PM, Michel Pollet
> <michel.pollet@bp.renesas.com> wrote:
> > The Renesas R9A06G032 second CA7 is parked in a ROM pen at boot time,
> > it requires a special enable method to get it started.
> >
> > Signed-off-by: Michel Pollet <michel.pollet@bp.renesas.com>
>
> Thanks for your patch!
>
> >  arch/arm/mach-shmobile/smp-r9a06g032.c | 85
> > ++++++++++++++++++++++++++++++++++
>
> I think you can safely call this driver smp-rzn1d.c, or smp-rzn1.c.
> Source files are not covered by the stable DT ABI, and can be reordered later
> at will.
>
> I expect you will just add more CPU_METHOD_OF_DECLARE() lines later
> (perhaps with a little bit of extra code to handle deviations).

Now I am completely confused -- you had me remove the mention of rzn1
from everywhere it mattered to handle 'family' cases, and now you are
telling me that in *this* case where there is not a single chance of that file
covering another part and there's a clear cut case for it to be part specific
.... I should call it rzn1?!?

I even already renamed the symbols on my tree to match the
rest for v4...

I'd like consistency -- I *thought* I had a consistent naming scheme before,
now I've moved to your part specific one (under duress), I'd rather stick to
something that is consistent and keep everything as r9a06g032 now.

>
> > --- /dev/null
> > +++ b/arch/arm/mach-shmobile/smp-r9a06g032.c
> > @@ -0,0 +1,85 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * RZ/N1D Second CA7 enabler.
> > + *
> > + * Copyright (C) 2018 Renesas Electronics Europe Limited
> > + *
> > + * Michel Pollet <michel.pollet@bp.renesas.com>,
> <buserror@gmail.com>
> > + * Derived from action,s500-smp
> > + */
> > +
> > +#include <linux/delay.h>
>
> Do you need this?

Fixed all the other remarks, thanks for that!

Michel




Renesas Electronics Europe Ltd, Dukes Meadow, Millboard Road, Bourne End, Buckinghamshire, SL8 5FH, UK. Registered in England & Wales under Registered No. 04586709.

^ permalink raw reply

* Re: [PATCH 08/12] drm/bridge: tc358764: Add DSI to LVDS bridge driver
From: Andrzej Hajda @ 2018-05-30  8:27 UTC (permalink / raw)
  To: kbuild test robot, Maciej Purski
  Cc: kbuild-all, linux-kernel, linux-arm-kernel, linux-samsung-soc,
	devicetree, dri-devel, David Airlie, Rob Herring, Mark Rutland,
	Thierry Reding, Kukjin Kim, Krzysztof Kozlowski, Archit Taneja,
	Laurent Pinchart, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
	Kyungmin Park, Marek Szyprowski, Bartlomiej Zolnierkiewicz
In-Reply-To: <201805301553.AcTypuC4%fengguang.wu@intel.com>

Hi Maciej,


On 30.05.2018 09:45, kbuild test robot wrote:
> Hi Maciej,
>
> Thank you for the patch! Perhaps something to improve:
>
> [auto build test WARNING on next-20180517]
> [cannot apply to drm-exynos/exynos-drm/for-next robh/for-next drm/drm-next v4.17-rc6 v4.17-rc5 v4.17-rc4 v4.17-rc7]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url:    https://github.com/0day-ci/linux/commits/Maciej-Purski/Add-TOSHIBA-TC358764-DSI-LVDS-bridge-driver/20180530-011258
> reproduce:
>         # apt-get install sparse
>         make ARCH=x86_64 allmodconfig
>         make C=1 CF=-D__CHECK_ENDIAN__
>
>
> sparse warnings: (new ones prefixed by >>)
>
>>> drivers/gpu/drm/bridge/tc358764.c:193:14: sparse: incorrect type in assignment (different base types) @@    expected unsigned short [unsigned] [addressable] [usertype] addr @@    got ed] [addressable] [usertype] addr @@
>    drivers/gpu/drm/bridge/tc358764.c:193:14:    expected unsigned short [unsigned] [addressable] [usertype] addr
>    drivers/gpu/drm/bridge/tc358764.c:193:14:    got restricted __le16 [usertype] <noident>
>>> drivers/gpu/drm/bridge/tc358764.c:197:24: sparse: cast to restricted __le32
>>> drivers/gpu/drm/bridge/tc358764.c:175:5: sparse: symbol 'tc358764_read' was not declared. Should it be static?
>>> drivers/gpu/drm/bridge/tc358764.c:204:5: sparse: symbol 'tc358764_write' was not declared. Should it be static?
> vim +193 drivers/gpu/drm/bridge/tc358764.c
>
>    174	
>  > 175	int tc358764_read(struct tc358764 *ctx, u16 addr, u32 *val)

add static

>    176	{
>    177		struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
>    178		const struct mipi_dsi_host_ops *ops = dsi->host->ops;
>    179		struct mipi_dsi_msg msg = {
>    180			.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM,
>    181			.channel = dsi->channel,
>    182			.flags = MIPI_DSI_MSG_USE_LPM,
>    183			.tx_buf = &addr,
>    184			.tx_len = 2,
>    185			.rx_buf = val,
>    186			.rx_len = 4
>    187		};
>    188		ssize_t ret;
>    189	
>    190		if (!ops || !ops->transfer)
>    191			return -EINVAL;
>    192	
>  > 193		addr = cpu_to_le16(addr);

It should be changed to:

cpu_to_le16s(&addr);

>    194	
>    195		ret = ops->transfer(dsi->host, &msg);
>    196		if (ret >= 0)
>  > 197			*val = le32_to_cpu(*val);

le32_to_cpus(val);

>    198	
>    199		dev_dbg(ctx->dev, "read: %d, addr: %d\n", addr, *val);
>    200	
>    201		return ret;
>    202	}
>    203	
>  > 204	int tc358764_write(struct tc358764 *ctx, u16 addr, u32 val)

add static


Regards
Andrzej

>    205	{
>    206		struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
>    207		const struct mipi_dsi_host_ops *ops = dsi->host->ops;
>    208		u8 data[6];
>    209		int ret;
>    210		struct mipi_dsi_msg msg = {
>    211			.type = MIPI_DSI_GENERIC_LONG_WRITE,
>    212			.channel = dsi->channel,
>    213			.flags = MIPI_DSI_MSG_USE_LPM | MIPI_DSI_MSG_REQ_ACK,
>    214			.tx_buf = data,
>    215			.tx_len = 6
>    216		};
>    217	
>    218		if (!ops || !ops->transfer)
>    219			return -EINVAL;
>    220	
>    221		data[0] = addr;
>    222		data[1] = addr >> 8;
>    223		data[2] = val;
>    224		data[3] = val >> 8;
>    225		data[4] = val >> 16;
>    226		data[5] = val >> 24;
>    227	
>    228		ret = ops->transfer(dsi->host, &msg);
>    229	
>    230		return ret;
>    231	}
>    232	
>
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
>
>
>

^ permalink raw reply

* [PATCH v4 0/6] mfd/regulator/clk: bd71837: ROHM BD71837 PMIC driver
From: Matti Vaittinen @ 2018-05-30  8:41 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola

Patch series adding support for ROHM BD71837 PMIC.

BD71837 is a programmable Power Management IC for powering single-core,
dual-core, and quad-core SoC’s such as NXP-i.MX 8M. It is optimized for
low BOM cost and compact solution footprint. It integrates 8 buck
regulators and 7 LDO’s to provide all the power rails required by the
SoC and the commonly used peripherals.

The driver aims to not limit the usage of PMIC. Thus the buck and LDO
naming is generic and not tied to any specific purposes. However there
is following limitations which make it mostly suitable for use cases
where the processor where PMIC driver is running is powered by the PMIC:

- The PMIC is not re-initialized if it resets. PMIC may reset as a
  result of voltage monitoring (over/under voltage) or due to reset
  request. Driver is only initializing PMIC at probe. This is not
  problem as long as processor controlling PMIC is powered by PMIC.

- The PMIC internal state machine is ignored by driver. Driver assumes
  the PMIC is wired so that it is always in "run" state when controlled
  by the driver.

Changelog v4
- remove mutex from regulator state check as core prevents simultaneous
  accesses
- allow voltage change for bucks 1 to 4 when regulator is enabled
- fix indentiation problems
- properly correct SPDX comments

Changelog v3
- kill unused variable
- kill unused definitions
- use REGMAP_IRQ_REG

Changelog v2
Based on feedback from Mark Brown
- Squashed code and buildfile changes to same patch
- Fixed some styling issues
- Changed SPDX comments to CPP style
- Error out if voltage is changed when regulator is enabled instead of
  Disabling the regulator for duration of change
- Use devm_regulator_register
- Remove compatible usage from regulators - use parent dev for config
- Add a note about using regulator-boot-on for BUCK6 and 7
- fixed warnings from kbuild test robot

patch 1: 
        MFD driver and definitions bringing interrupt support and
        enabling clk and regulator subsystems.
Patches 2, 3 and 4:
        device tree binding documents.
Patch 5:
        clock subsystem and support for gated clock.
Patch 6:
        regulator driver supporting 8 bucks and 7 LDOs.

This patch series is based on for-mfd-next

---

Matti Vaittinen (6):
  mfd: bd71837: mfd driver for ROHM BD71837 PMIC
  mfd: bd71837: Devicetree bindings for ROHM BD71837 PMIC
  regulator: bd71837: Devicetree bindings for BD71837 regulators
  clk: bd71837: Devicetree bindings for ROHM BD71837 PMIC
  clk: bd71837: Add driver for BD71837 PMIC clock
  regulator: bd71837: BD71837 PMIC regulator driver

 .../bindings/clock/rohm,bd71837-clock.txt          |  37 ++
 .../devicetree/bindings/mfd/rohm,bd71837-pmic.txt  |  52 ++
 .../bindings/regulator/rohm,bd71837-regulator.txt  | 126 ++++
 drivers/clk/Kconfig                                |   9 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-bd71837.c                          | 151 +++++
 drivers/mfd/Kconfig                                |  13 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/bd71837.c                              | 222 +++++++
 drivers/regulator/Kconfig                          |  11 +
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/bd71837-regulator.c              | 640 +++++++++++++++++++++
 include/linux/mfd/bd71837.h                        | 288 ++++++++++
 13 files changed, 1552 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rohm,bd71837-clock.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt
 create mode 100644 drivers/clk/clk-bd71837.c
 create mode 100644 drivers/mfd/bd71837.c
 create mode 100644 drivers/regulator/bd71837-regulator.c
 create mode 100644 include/linux/mfd/bd71837.h

-- 
2.14.3

^ permalink raw reply

* [PATCH v4 1/6] mfd: bd71837: mfd driver for ROHM BD71837 PMIC
From: Matti Vaittinen @ 2018-05-30  8:41 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

ROHM BD71837 PMIC MFD driver providing interrupts and support
for two subsystems:
- clk
- Regulators

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 drivers/mfd/Kconfig         |  13 ++
 drivers/mfd/Makefile        |   1 +
 drivers/mfd/bd71837.c       | 222 ++++++++++++++++++++++++++++++++++
 include/linux/mfd/bd71837.h | 288 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 524 insertions(+)
 create mode 100644 drivers/mfd/bd71837.c
 create mode 100644 include/linux/mfd/bd71837.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b860eb5aa194..7aa05fc9ed8e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1787,6 +1787,19 @@ config MFD_STW481X
 	  in various ST Microelectronics and ST-Ericsson embedded
 	  Nomadik series.
 
+config MFD_BD71837
+	bool "BD71837 Power Management chip"
+	depends on I2C=y
+	depends on OF
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	select MFD_CORE
+	help
+	  Select this option to get support for the ROHM BD71837
+	  Power Management chips. BD71837 is designed to power processors like
+	  NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring
+	  and emergency shut down as well as 32,768KHz clock output.
+
 config MFD_STM32_LPTIMER
 	tristate "Support for STM32 Low-Power Timer"
 	depends on (ARCH_STM32 && OF) || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e9fd20dba18d..09dc9eb3782c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -227,4 +227,5 @@ obj-$(CONFIG_MFD_STM32_TIMERS) 	+= stm32-timers.o
 obj-$(CONFIG_MFD_MXS_LRADC)     += mxs-lradc.o
 obj-$(CONFIG_MFD_SC27XX_PMIC)	+= sprd-sc27xx-spi.o
 obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
+obj-$(CONFIG_MFD_BD71837)	+= bd71837.o
 
diff --git a/drivers/mfd/bd71837.c b/drivers/mfd/bd71837.c
new file mode 100644
index 000000000000..93525fb36259
--- /dev/null
+++ b/drivers/mfd/bd71837.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837.c -- ROHM BD71837MWV mfd driver
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/bd71837.h>
+
+/* bd71837 multi function cells */
+static struct mfd_cell bd71837_mfd_cells[] = {
+	{
+		.name = "bd71837-clk",
+		.of_compatible = "rohm,bd71837-clk",
+	}, {
+		.name = "bd71837-pmic",
+	},
+};
+
+static const struct regmap_irq bd71837_irqs[] = {
+	REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK),
+	REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK),
+};
+
+static struct regmap_irq_chip bd71837_irq_chip = {
+	.name = "bd71837-irq",
+	.irqs = bd71837_irqs,
+	.num_irqs = ARRAY_SIZE(bd71837_irqs),
+	.num_regs = 1,
+	.irq_reg_stride = 1,
+	.status_base = BD71837_REG_IRQ,
+	.mask_base = BD71837_REG_MIRQ,
+	.mask_invert = false,
+};
+
+static int bd71837_irq_exit(struct bd71837 *bd71837)
+{
+	if (bd71837->chip_irq > 0)
+		regmap_del_irq_chip(bd71837->chip_irq, bd71837->irq_data);
+	return 0;
+}
+
+static const struct regmap_range pmic_status_range = {
+	.range_min = BD71837_REG_IRQ,
+	.range_max = BD71837_REG_POW_STATE,
+};
+
+static const struct regmap_access_table volatile_regs = {
+	.yes_ranges = &pmic_status_range,
+	.n_yes_ranges = 1,
+};
+
+static const struct regmap_config bd71837_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_table = &volatile_regs,
+	.max_register = BD71837_MAX_REGISTER - 1,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id bd71837_of_match[] = {
+	{ .compatible = "rohm,bd71837", .data = (void *)0},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bd71837_of_match);
+
+static int bd71837_parse_dt(struct i2c_client *client, struct bd71837_board **b)
+{
+	struct device_node *np = client->dev.of_node;
+	struct bd71837_board *board_info;
+	unsigned int prop;
+	int r;
+	int rv = -ENOMEM;
+
+	board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
+			GFP_KERNEL);
+	if (!board_info)
+		goto err_out;
+
+	if (client->irq) {
+		dev_dbg(&client->dev, "Got irq %d\n", client->irq);
+		board_info->gpio_intr = client->irq;
+	} else {
+		dev_err(&client->dev, "no pmic intr pin available\n");
+		rv = -ENOENT;
+		goto err_intr;
+	}
+	r = of_property_read_u32(np, "irq_base", &prop);
+	if (!r)
+		board_info->irq_base = prop;
+	else
+		board_info->irq_base = 0;
+
+	rv = 0;
+	*b = board_info;
+	if (0) {
+err_intr:
+		devm_kfree(&client->dev, board_info);
+err_out:
+		dev_err(&client->dev, "failed to parse device-tree (%d)\n", rv);
+	}
+	return rv;
+}
+#endif //CONFIG_OF
+
+static int bd71837_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct bd71837 *bd71837;
+	struct bd71837_board *pmic_plat_data;
+	int ret = -EINVAL;
+
+	pmic_plat_data = dev_get_platdata(&i2c->dev);
+
+	if (!pmic_plat_data && i2c->dev.of_node)
+		ret = bd71837_parse_dt(i2c, &pmic_plat_data);
+
+	if (!pmic_plat_data)
+		return ret;
+
+	bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL);
+	if (bd71837 == NULL)
+		return -ENOMEM;
+
+	bd71837->of_plat_data = pmic_plat_data;
+	i2c_set_clientdata(i2c, bd71837);
+	bd71837->dev = &i2c->dev;
+	bd71837->i2c_client = i2c;
+	bd71837->chip_irq = pmic_plat_data->gpio_intr;
+
+	bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
+	if (IS_ERR(bd71837->regmap)) {
+		ret = PTR_ERR(bd71837->regmap);
+		dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+		goto err_out;
+	}
+
+	ret = bd71837_reg_read(bd71837, BD71837_REG_REV);
+	if (ret < 0) {
+		dev_err(bd71837->dev,
+			"%s(): Read BD71837_REG_DEVICE failed!\n", __func__);
+		goto err_out;
+	}
+
+	ret = regmap_add_irq_chip(bd71837->regmap, bd71837->chip_irq,
+		IRQF_ONESHOT, 0,
+		&bd71837_irq_chip, &bd71837->irq_data);
+	if (ret < 0) {
+		dev_err(bd71837->dev, "Failed to add irq_chip %d\n", ret);
+		goto err_out;
+	}
+
+	ret = mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO,
+			      bd71837_mfd_cells, ARRAY_SIZE(bd71837_mfd_cells),
+			      NULL, 0,
+			      regmap_irq_get_domain(bd71837->irq_data));
+	if (ret)
+		regmap_del_irq_chip(bd71837->chip_irq, bd71837->irq_data);
+err_out:
+
+	return ret;
+}
+
+static int bd71837_i2c_remove(struct i2c_client *i2c)
+{
+	struct bd71837 *bd71837 = i2c_get_clientdata(i2c);
+
+	bd71837_irq_exit(bd71837);
+	mfd_remove_devices(bd71837->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id bd71837_i2c_id[] = {
+	{ .name = "bd71837", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bd71837_i2c_id);
+
+static struct i2c_driver bd71837_i2c_driver = {
+	.driver = {
+		.name = "bd71837-mfd",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(bd71837_of_match),
+	},
+	.probe = bd71837_i2c_probe,
+	.remove = bd71837_i2c_remove,
+	.id_table = bd71837_i2c_id,
+};
+
+static int __init bd71837_i2c_init(void)
+{
+	return i2c_add_driver(&bd71837_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(bd71837_i2c_init);
+
+static void __exit bd71837_i2c_exit(void)
+{
+	i2c_del_driver(&bd71837_i2c_driver);
+}
+module_exit(bd71837_i2c_exit);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837 chip multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/bd71837.h b/include/linux/mfd/bd71837.h
new file mode 100644
index 000000000000..641b7dba3076
--- /dev/null
+++ b/include/linux/mfd/bd71837.h
@@ -0,0 +1,288 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018 ROHM Semiconductors */
+
+/*
+ * ROHM BD71837MWV header file
+ */
+
+#ifndef __LINUX_MFD_BD71837_H__
+#define __LINUX_MFD_BD71837_H__
+
+#include <linux/regmap.h>
+
+enum {
+	BD71837_BUCK1	=	0,
+	BD71837_BUCK2,
+	BD71837_BUCK3,
+	BD71837_BUCK4,
+	BD71837_BUCK5,
+	BD71837_BUCK6,
+	BD71837_BUCK7,
+	BD71837_BUCK8,
+	BD71837_LDO1,
+	BD71837_LDO2,
+	BD71837_LDO3,
+	BD71837_LDO4,
+	BD71837_LDO5,
+	BD71837_LDO6,
+	BD71837_LDO7,
+	BD71837_REGULATOR_CNT,
+};
+
+#define BD71837_BUCK1_VOLTAGE_NUM	0x40
+#define BD71837_BUCK2_VOLTAGE_NUM	0x40
+#define BD71837_BUCK3_VOLTAGE_NUM	0x40
+#define BD71837_BUCK4_VOLTAGE_NUM	0x40
+
+#define BD71837_BUCK5_VOLTAGE_NUM	0x08
+#define BD71837_BUCK6_VOLTAGE_NUM	0x04
+#define BD71837_BUCK7_VOLTAGE_NUM	0x08
+#define BD71837_BUCK8_VOLTAGE_NUM	0x40
+
+#define BD71837_LDO1_VOLTAGE_NUM	0x04
+#define BD71837_LDO2_VOLTAGE_NUM	0x02
+#define BD71837_LDO3_VOLTAGE_NUM	0x10
+#define BD71837_LDO4_VOLTAGE_NUM	0x10
+#define BD71837_LDO5_VOLTAGE_NUM	0x10
+#define BD71837_LDO6_VOLTAGE_NUM	0x10
+#define BD71837_LDO7_VOLTAGE_NUM	0x10
+
+enum {
+	BD71837_REG_REV                = 0x00,
+	BD71837_REG_SWRESET            = 0x01,
+	BD71837_REG_I2C_DEV            = 0x02,
+	BD71837_REG_PWRCTRL0           = 0x03,
+	BD71837_REG_PWRCTRL1           = 0x04,
+	BD71837_REG_BUCK1_CTRL         = 0x05,
+	BD71837_REG_BUCK2_CTRL         = 0x06,
+	BD71837_REG_BUCK3_CTRL         = 0x07,
+	BD71837_REG_BUCK4_CTRL         = 0x08,
+	BD71837_REG_BUCK5_CTRL         = 0x09,
+	BD71837_REG_BUCK6_CTRL         = 0x0A,
+	BD71837_REG_BUCK7_CTRL         = 0x0B,
+	BD71837_REG_BUCK8_CTRL         = 0x0C,
+	BD71837_REG_BUCK1_VOLT_RUN     = 0x0D,
+	BD71837_REG_BUCK1_VOLT_IDLE    = 0x0E,
+	BD71837_REG_BUCK1_VOLT_SUSP    = 0x0F,
+	BD71837_REG_BUCK2_VOLT_RUN     = 0x10,
+	BD71837_REG_BUCK2_VOLT_IDLE    = 0x11,
+	BD71837_REG_BUCK3_VOLT_RUN     = 0x12,
+	BD71837_REG_BUCK4_VOLT_RUN     = 0x13,
+	BD71837_REG_BUCK5_VOLT         = 0x14,
+	BD71837_REG_BUCK6_VOLT         = 0x15,
+	BD71837_REG_BUCK7_VOLT         = 0x16,
+	BD71837_REG_BUCK8_VOLT         = 0x17,
+	BD71837_REG_LDO1_VOLT          = 0x18,
+	BD71837_REG_LDO2_VOLT          = 0x19,
+	BD71837_REG_LDO3_VOLT          = 0x1A,
+	BD71837_REG_LDO4_VOLT          = 0x1B,
+	BD71837_REG_LDO5_VOLT          = 0x1C,
+	BD71837_REG_LDO6_VOLT          = 0x1D,
+	BD71837_REG_LDO7_VOLT          = 0x1E,
+	BD71837_REG_TRANS_COND0        = 0x1F,
+	BD71837_REG_TRANS_COND1        = 0x20,
+	BD71837_REG_VRFAULTEN          = 0x21,
+	BD71837_REG_MVRFLTMASK0        = 0x22,
+	BD71837_REG_MVRFLTMASK1        = 0x23,
+	BD71837_REG_MVRFLTMASK2        = 0x24,
+	BD71837_REG_RCVCFG             = 0x25,
+	BD71837_REG_RCVNUM             = 0x26,
+	BD71837_REG_PWRONCONFIG0       = 0x27,
+	BD71837_REG_PWRONCONFIG1       = 0x28,
+	BD71837_REG_RESETSRC           = 0x29,
+	BD71837_REG_MIRQ               = 0x2A,
+	BD71837_REG_IRQ                = 0x2B,
+	BD71837_REG_IN_MON             = 0x2C,
+	BD71837_REG_POW_STATE          = 0x2D,
+	BD71837_REG_OUT32K             = 0x2E,
+	BD71837_REG_REGLOCK            = 0x2F,
+	BD71837_REG_OTPVER             = 0xFF,
+	BD71837_MAX_REGISTER           = 0x100,
+};
+
+#define REGLOCK_PWRSEQ	0x1
+#define REGLOCK_VREG	0x10
+
+/* Generic BUCK control masks */
+#define BD71837_BUCK_SEL	0x02
+#define BD71837_BUCK_EN		0x01
+#define BD71837_BUCK_RUN_ON	0x04
+
+/* Generic LDO masks */
+#define BD71837_LDO_SEL		0x80
+#define BD71837_LDO_EN		0x40
+
+/* BD71837 BUCK ramp rate CTRL reg bits */
+#define BUCK_RAMPRATE_MASK	0xC0
+#define BUCK_RAMPRATE_10P00MV	0x0
+#define BUCK_RAMPRATE_5P00MV	0x1
+#define BUCK_RAMPRATE_2P50MV	0x2
+#define BUCK_RAMPRATE_1P25MV	0x3
+
+/* BD71837_REG_BUCK1_VOLT_RUN bits */
+#define BUCK1_RUN_MASK		0x3F
+#define BUCK1_RUN_DEFAULT	0x14
+
+/* BD71837_REG_BUCK1_VOLT_SUSP bits */
+#define BUCK1_SUSP_MASK		0x3F
+#define BUCK1_SUSP_DEFAULT	0x14
+
+/* BD71837_REG_BUCK1_VOLT_IDLE bits */
+#define BUCK1_IDLE_MASK		0x3F
+#define BUCK1_IDLE_DEFAULT	0x14
+
+/* BD71837_REG_BUCK2_VOLT_RUN bits */
+#define BUCK2_RUN_MASK		0x3F
+#define BUCK2_RUN_DEFAULT	0x1E
+
+/* BD71837_REG_BUCK2_VOLT_IDLE bits */
+#define BUCK2_IDLE_MASK		0x3F
+#define BUCK2_IDLE_DEFAULT	0x14
+
+/* BD71837_REG_BUCK3_VOLT_RUN bits */
+#define BUCK3_RUN_MASK		0x3F
+#define BUCK3_RUN_DEFAULT	0x1E
+
+/* BD71837_REG_BUCK4_VOLT_RUN bits */
+#define BUCK4_RUN_MASK		0x3F
+#define BUCK4_RUN_DEFAULT	0x1E
+
+/* BD71837_REG_BUCK5_VOLT bits */
+#define BUCK5_MASK		0x07
+#define BUCK5_DEFAULT		0x02
+
+/* BD71837_REG_BUCK6_VOLT bits */
+#define BUCK6_MASK		0x03
+#define BUCK6_DEFAULT		0x03
+
+/* BD71837_REG_BUCK7_VOLT bits */
+#define BUCK7_MASK		0x07
+#define BUCK7_DEFAULT		0x03
+
+/* BD71837_REG_BUCK8_VOLT bits */
+#define BUCK8_MASK		0x3F
+#define BUCK8_DEFAULT		0x1E
+
+/* BD71837_REG_IRQ bits */
+#define IRQ_SWRST		0x40
+#define IRQ_PWRON_S		0x20
+#define IRQ_PWRON_L		0x10
+#define IRQ_PWRON		0x08
+#define IRQ_WDOG		0x04
+#define IRQ_ON_REQ		0x02
+#define IRQ_STBY_REQ		0x01
+
+/* BD71837_REG_OUT32K bits */
+#define BD71837_OUT32K_EN	0x01
+
+/* BD71837 gated clock rate */
+#define BD71837_CLK_RATE 32768
+
+/* BD71837 irqs */
+enum {
+	BD71837_INT_STBY_REQ,
+	BD71837_INT_ON_REQ,
+	BD71837_INT_WDOG,
+	BD71837_INT_PWRBTN,
+	BD71837_INT_PWRBTN_L,
+	BD71837_INT_PWRBTN_S,
+	BD71837_INT_SWRST
+};
+
+/* BD71837 interrupt masks */
+#define BD71837_INT_SWRST_MASK		0x40
+#define BD71837_INT_PWRBTN_S_MASK	0x20
+#define BD71837_INT_PWRBTN_L_MASK	0x10
+#define BD71837_INT_PWRBTN_MASK		0x8
+#define BD71837_INT_WDOG_MASK		0x4
+#define BD71837_INT_ON_REQ_MASK		0x2
+#define BD71837_INT_STBY_REQ_MASK	0x1
+
+/* BD71837_REG_LDO1_VOLT bits */
+#define LDO1_MASK		0x03
+
+/* BD71837_REG_LDO1_VOLT bits */
+#define LDO2_MASK		0x20
+
+/* BD71837_REG_LDO3_VOLT bits */
+#define LDO3_MASK		0x0F
+
+/* BD71837_REG_LDO4_VOLT bits */
+#define LDO4_MASK		0x0F
+
+/* BD71837_REG_LDO5_VOLT bits */
+#define LDO5_MASK		0x0F
+
+/* BD71837_REG_LDO6_VOLT bits */
+#define LDO6_MASK		0x0F
+
+/* BD71837_REG_LDO7_VOLT bits */
+#define LDO7_MASK		0x0F
+
+struct bd71837;
+struct bd71837_pmic;
+struct bd71837_clk;
+
+/*
+ * Board platform data may be used to initialize regulators.
+ */
+
+struct bd71837_board {
+	struct regulator_init_data *init_data[BD71837_REGULATOR_CNT];
+	int	gpio_intr;
+	int	irq_base;
+};
+
+struct bd71837 {
+	struct device *dev;
+	struct i2c_client *i2c_client;
+	struct regmap *regmap;
+	unsigned long int id;
+
+	int chip_irq;
+	struct regmap_irq_chip_data *irq_data;
+
+	struct bd71837_pmic *pmic;
+	struct bd71837_clk *clk;
+
+	struct bd71837_board *of_plat_data;
+};
+
+/*
+ * bd71837 sub-driver chip access routines
+ */
+
+static inline int bd71837_reg_read(struct bd71837 *bd71837, u8 reg)
+{
+	int r, val;
+
+	r = regmap_read(bd71837->regmap, reg, &val);
+	if (r < 0)
+		return r;
+	return val;
+}
+
+static inline int bd71837_reg_write(struct bd71837 *bd71837, u8 reg,
+				    unsigned int val)
+{
+	return regmap_write(bd71837->regmap, reg, val);
+}
+
+static inline int bd71837_set_bits(struct bd71837 *bd71837, u8 reg, u8 mask)
+{
+	return regmap_update_bits(bd71837->regmap, reg, mask, mask);
+}
+
+static inline int bd71837_clear_bits(struct bd71837 *bd71837, u8 reg,
+				     u8 mask)
+{
+	return regmap_update_bits(bd71837->regmap, reg, mask, 0);
+}
+
+static inline int bd71837_update_bits(struct bd71837 *bd71837, u8 reg,
+				      u8 mask, u8 val)
+{
+	return regmap_update_bits(bd71837->regmap, reg, mask, val);
+}
+
+#endif /* __LINUX_MFD_BD71837_H__ */
-- 
2.14.3

^ permalink raw reply related

* [PATCH v4 2/6] mfd: bd71837: Devicetree bindings for ROHM BD71837 PMIC
From: Matti Vaittinen @ 2018-05-30  8:42 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Document devicetree bindings for ROHM BD71837 PMIC MFD.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 .../devicetree/bindings/mfd/rohm,bd71837-pmic.txt  | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt b/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
new file mode 100644
index 000000000000..bbc46d38b162
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
@@ -0,0 +1,52 @@
+* ROHM BD71837 Power Management Integrated Circuit bindings
+
+BD71837MWV is a programmable Power Management IC for powering single-core,
+dual-core, and quad-core SoC’s such as NXP-i.MX 8M. It is optimized for
+low BOM cost and compact solution footprint. It integrates 8 Buck
+egulators and 7 LDO’s to provide all the power rails required by the SoC and
+the commonly used peripherals.
+
+Required properties:
+ - compatible		: Should be "rohm,bd71837".
+ - reg			: I2C slave address.
+ - interrupt-parent	: Phandle to the parent interrupt controller.
+ - interrupts		: The interrupt line the device is connected to.
+ - interrupt-controller	: Marks the device node as an interrupt controller.
+ - #interrupt-cells	: The number of cells to describe an IRQ, should be 1 or 2.
+			    The first cell is the IRQ number.
+			    The second cell if present is the flags, encoded as trigger
+			    masks from ../interrupt-controller/interrupts.txt.
+ - regulators:		: List of child nodes that specify the regulators
+			  Please see ../regulator/rohm,bd71837-regulator.txt
+ - clock:		: Please see ../clock/rohm,bd71837-clock.txt
+
+Example:
+
+	pmic: bd71837@4b {
+		compatible = "rohm,bd71837";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x4b>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <29 GPIO_ACTIVE_LOW>;
+		interrupt-names = "irq";
+		#interrupt-cells = <1>;
+		interrupt-controller;
+
+		regulators {
+			buck1: BUCK1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <700000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-boot-on;
+				regulator-ramp-delay = <1250>;
+			};
+			...
+		};
+		clk: bd71837-32k-out {
+			compatible = "rohm,bd71837-clk";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "bd71837-32k-out";
+		};
+	};
-- 
2.14.3

^ permalink raw reply related

* [PATCH v4 3/6] regulator: bd71837: Devicetree bindings for BD71837 regulators
From: Matti Vaittinen @ 2018-05-30  8:42 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Document devicetree bindings for ROHM BD71837 PMIC regulators.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 .../bindings/regulator/rohm,bd71837-regulator.txt  | 126 +++++++++++++++++++++
 1 file changed, 126 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt
new file mode 100644
index 000000000000..4edf3137d9f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt
@@ -0,0 +1,126 @@
+ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings
+
+BD71837MWV is a programmable Power Management
+IC (PMIC) for powering single-core, dual-core, and
+quad-core SoC’s such as NXP-i.MX 8M. It is optimized
+for low BOM cost and compact solution footprint. It
+integrates 8 Buck regulators and 7 LDO’s to provide all
+the power rails required by the SoC and the commonly
+used peripherals.
+
+Required properties:
+ - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7"
+
+List of regulators provided by this controller. BD71837 regulators node
+should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
+Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
+Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
+definition for each of these nodes is defined using the standard
+binding for regulators at
+Documentation/devicetree/bindings/regulator/regulator.txt.
+Note that if BD71837 starts at RUN state you probably want to use
+regulator-boot-on at least for BUCK6 and BUCK7 so that those are not
+disabled by driver at startup. LDO5 and LDO6 are supplied by those and
+if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
+cause PMIC to reset.
+
+The valid names for regulator nodes are:
+BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
+LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
+
+Optional properties:
+- Any optional property defined in bindings/regulator/regulator.txt
+
+Example:
+regulators {
+	buck1: BUCK1 {
+		regulator-name = "buck1";
+		regulator-min-microvolt = <700000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-boot-on;
+		regulator-ramp-delay = <1250>;
+	};
+	buck2: BUCK2 {
+		regulator-name = "buck2";
+		regulator-min-microvolt = <700000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-ramp-delay = <1250>;
+	};
+	buck3: BUCK3 {
+		regulator-name = "buck3";
+		regulator-min-microvolt = <700000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-boot-on;
+	};
+	buck4: BUCK4 {
+		regulator-name = "buck4";
+		regulator-min-microvolt = <700000>;
+		regulator-max-microvolt = <1300000>;
+		regulator-boot-on;
+	};
+	buck5: BUCK5 {
+		regulator-name = "buck5";
+		regulator-min-microvolt = <700000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-boot-on;
+	};
+	buck6: BUCK6 {
+		regulator-name = "buck6";
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+	};
+	buck7: BUCK7 {
+		regulator-name = "buck7";
+		regulator-min-microvolt = <1605000>;
+		regulator-max-microvolt = <1995000>;
+		regulator-boot-on;
+	};
+	buck8: BUCK8 {
+		regulator-name = "buck8";
+		regulator-min-microvolt = <800000>;
+		regulator-max-microvolt = <1400000>;
+	};
+
+	ldo1: LDO1 {
+		regulator-name = "ldo1";
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+	};
+	ldo2: LDO2 {
+		regulator-name = "ldo2";
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <900000>;
+		regulator-boot-on;
+	};
+	ldo3: LDO3 {
+		regulator-name = "ldo3";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+	ldo4: LDO4 {
+		regulator-name = "ldo4";
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1800000>;
+	};
+	ldo5: LDO5 {
+		regulator-name = "ldo5";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+	ldo6: LDO6 {
+		regulator-name = "ldo6";
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1800000>;
+	};
+	ldo7_reg: LDO7 {
+		regulator-name = "ldo7";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+
-- 
2.14.3

^ permalink raw reply related

* Re: [PATCH v3 2/3] arm: shmobile: Add the R9A06G032 SMP enabler driver
From: Geert Uytterhoeven @ 2018-05-30  8:42 UTC (permalink / raw)
  To: Michel Pollet
  Cc: Michel Pollet, Mark Rutland, Phil Edworthy, Florian Fainelli,
	Rajendra Nayak, Juri Lelli,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Greg Kroah-Hartman, Stefan Wahren, Magnus Damm, Russell King,
	Rob Herring, Linux Kernel Mailing List, Linux-Renesas,
	Chen-Yu Tsai, Simon Horman, Carlo Caione, Kevin Hilman,
	Andreas Färber, Frank Rowand
In-Reply-To: <OSBPR01MB20546AE06422C9AD896F8F60D26C0@OSBPR01MB2054.jpnprd01.prod.outlook.com>

Hi Michel,

On Wed, May 30, 2018 at 10:19 AM, Michel Pollet
<michel.pollet@bp.renesas.com> wrote:
> On 25 May 2018 10:49, Geert wrote:
>> On Thu, May 24, 2018 at 12:30 PM, Michel Pollet
>> <michel.pollet@bp.renesas.com> wrote:
>> > The Renesas R9A06G032 second CA7 is parked in a ROM pen at boot time,
>> > it requires a special enable method to get it started.
>> >
>> > Signed-off-by: Michel Pollet <michel.pollet@bp.renesas.com>
>>
>> Thanks for your patch!
>>
>> >  arch/arm/mach-shmobile/smp-r9a06g032.c | 85
>> > ++++++++++++++++++++++++++++++++++
>>
>> I think you can safely call this driver smp-rzn1d.c, or smp-rzn1.c.
>> Source files are not covered by the stable DT ABI, and can be reordered later
>> at will.
>>
>> I expect you will just add more CPU_METHOD_OF_DECLARE() lines later
>> (perhaps with a little bit of extra code to handle deviations).
>
> Now I am completely confused -- you had me remove the mention of rzn1
> from everywhere it mattered to handle 'family' cases, and now you are
> telling me that in *this* case where there is not a single chance of that file
> covering another part and there's a clear cut case for it to be part specific
> .... I should call it rzn1?!?

Sorry for confusing you.
There's a difference between stable DT ABI and (non-existing) kernel stable ABI.
A driver that handles multiple SoCs can be named after the SoC family.

I agree this one is a bit special, as only RZ/N1D has the dual Cortex A7
(RZ/N1S has a single A7, RZ/N1L has no A7), so for now[*] there's no need
to use it on anything but r9a06g032 aka RZ/N1D.

> I'd like consistency -- I *thought* I had a consistent naming scheme before,
> now I've moved to your part specific one (under duress), I'd rather stick to
> something that is consistent and keep everything as r9a06g032 now.

OK for me. Driver names can be changed any time.

[*] Until e.g. a quad A7 arrives :-)
    Perhaps this can also be used to enable the A7s on both RZ/N1D and
    RZ/N1S when running Linux on the Cortex M3?

Gr{oetje,eeting}s,

                        Geert

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

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

^ permalink raw reply

* [PATCH v4 4/6] clk: bd71837: Devicetree bindings for ROHM BD71837 PMIC
From: Matti Vaittinen @ 2018-05-30  8:42 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Document devicetree bindings for ROHM BD71837 PMIC clock output.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 .../bindings/clock/rohm,bd71837-clock.txt          | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/rohm,bd71837-clock.txt

diff --git a/Documentation/devicetree/bindings/clock/rohm,bd71837-clock.txt b/Documentation/devicetree/bindings/clock/rohm,bd71837-clock.txt
new file mode 100644
index 000000000000..9759fd145781
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rohm,bd71837-clock.txt
@@ -0,0 +1,37 @@
+ROHM BD71837 Power Management Integrated Circuit clock bindings
+
+BD71837 clock node should be sub node of the BD71837 MFD node.
+See BD71837 MFD bindings at
+Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
+
+Required properties:
+- compatible		: Should be "rohm,bd71837-clk"
+- clock-frequency	: Should be 32768
+- #clock-cells		: Should be 0
+
+Optional properties:
+- clock-output-names	: Should contain name for output clock.
+  Name "bd71837-32k-out" is used if this is not given.
+
+
+Example:
+
+pmic: bd71837@4b {
+	compatible = "rohm,bd71837";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	reg = <0x4b>;
+	interrupt-parent = <&gpio1>;
+	interrupts = <29 GPIO_ACTIVE_LOW>;
+	interrupt-names = "irq";
+	#interrupt-cells = <1>;
+	interrupt-controller;
+
+	/* Clock node */
+	clk: bd71837-32k-out {
+		compatible = "rohm,bd71837-clk";
+		#clock-cells = <0>;
+		clock-frequency  = <32768>;
+		clock-output-names = "bd71837-32k-out";
+	};
+};
-- 
2.14.3

^ permalink raw reply related

* [PATCH v4 5/6] clk: bd71837: Add driver for BD71837 PMIC clock
From: Matti Vaittinen @ 2018-05-30  8:43 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Support BD71837 gateable 32768 Hz clock.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 drivers/clk/Kconfig       |   9 +++
 drivers/clk/Makefile      |   1 +
 drivers/clk/clk-bd71837.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 drivers/clk/clk-bd71837.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 41492e980ef4..4b045699bb5e 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -279,6 +279,15 @@ config COMMON_CLK_STM32H7
 	---help---
 	  Support for stm32h7 SoC family clocks
 
+config COMMON_CLK_BD71837
+	tristate "Clock driver for ROHM BD71837 PMIC MFD"
+	depends on MFD_BD71837
+	depends on I2C=y
+	depends on OF
+	help
+	  This driver supports ROHM BD71837 PMIC clock.
+
+
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/imgtec/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index de6d06ac790b..8393c4af7d5a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -21,6 +21,7 @@ endif
 obj-$(CONFIG_MACH_ASM9260)		+= clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
+obj-$(CONFIG_COMMON_CLK_BD71837)	+= clk-bd71837.o
 obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
 obj-$(CONFIG_COMMON_CLK_CDCE925)	+= clk-cdce925.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
diff --git a/drivers/clk/clk-bd71837.c b/drivers/clk/clk-bd71837.c
new file mode 100644
index 000000000000..91456d1077ac
--- /dev/null
+++ b/drivers/clk/clk-bd71837.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837.c  -- ROHM BD71837MWV clock driver
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/bd71837.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+static int bd71837_clk_enable(struct clk_hw *hw);
+static void bd71837_clk_disable(struct clk_hw *hw);
+static int bd71837_clk_is_enabled(struct clk_hw *hw);
+
+struct bd71837_clk {
+	struct clk_hw hw;
+	uint8_t reg;
+	uint8_t mask;
+	unsigned long rate;
+	struct platform_device *pdev;
+	struct bd71837 *mfd;
+};
+
+static unsigned long bd71837_clk_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate);
+
+static const struct clk_ops bd71837_clk_ops = {
+	.recalc_rate = &bd71837_clk_recalc_rate,
+	.prepare = &bd71837_clk_enable,
+	.unprepare = &bd71837_clk_disable,
+	.is_prepared = &bd71837_clk_is_enabled,
+};
+
+static int bd71837_clk_set(struct clk_hw *hw, int status)
+{
+	struct bd71837_clk *c = container_of(hw, struct bd71837_clk, hw);
+
+	return bd71837_update_bits(c->mfd, c->reg, c->mask, status);
+}
+
+static void bd71837_clk_disable(struct clk_hw *hw)
+{
+	int rv;
+	struct bd71837_clk *c = container_of(hw, struct bd71837_clk, hw);
+
+	rv = bd71837_clk_set(hw, 0);
+	if (rv)
+		dev_err(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv);
+}
+
+static int bd71837_clk_enable(struct clk_hw *hw)
+{
+	return bd71837_clk_set(hw, 1);
+}
+
+static int bd71837_clk_is_enabled(struct clk_hw *hw)
+{
+	struct bd71837_clk *c = container_of(hw, struct bd71837_clk, hw);
+
+	return c->mask & bd71837_reg_read(c->mfd, c->reg);
+}
+
+static unsigned long bd71837_clk_recalc_rate(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct bd71837_clk *c = container_of(hw, struct bd71837_clk, hw);
+
+	return c->rate;
+}
+
+static int bd71837_clk_probe(struct platform_device *pdev)
+{
+	struct bd71837_clk *c;
+	int rval = -ENOMEM;
+	struct bd71837 *mfd = dev_get_drvdata(pdev->dev.parent);
+	const char *errstr = "memory allocation for bd71837 data failed";
+	struct clk_init_data init = {
+		.name = "bd71837-32k-out",
+		.ops = &bd71837_clk_ops,
+	};
+
+	c = kzalloc(sizeof(struct bd71837_clk), GFP_KERNEL);
+	if (!c)
+		goto err_out;
+
+	c->reg = BD71837_REG_OUT32K;
+	c->mask = BD71837_OUT32K_EN;
+	c->rate = BD71837_CLK_RATE;
+	c->mfd = mfd;
+	c->pdev = pdev;
+
+	if (pdev->dev.of_node)
+		of_property_read_string_index(pdev->dev.of_node,
+					      "clock-output-names", 0,
+					      &init.name);
+
+	c->hw.init = &init;
+
+	errstr = "failed to register 32K clk";
+	rval = clk_hw_register(&pdev->dev, &c->hw);
+	if (rval)
+		goto err_free;
+
+	errstr = "failed to register clkdev for bd71837";
+	rval = clk_hw_register_clkdev(&c->hw, init.name, NULL);
+	if (rval)
+		goto err_unregister;
+
+	platform_set_drvdata(pdev, c);
+	dev_dbg(&pdev->dev, "bd71837_clk successfully probed\n");
+
+	return 0;
+
+err_unregister:
+	clk_hw_unregister(&c->hw);
+err_free:
+	kfree(c);
+err_out:
+	dev_err(&pdev->dev, "%s\n", errstr);
+	return rval;
+}
+
+static int bd71837_clk_remove(struct platform_device *pdev)
+{
+	struct bd71837_clk *c = platform_get_drvdata(pdev);
+
+	if (c) {
+		clk_hw_unregister(&c->hw);
+		kfree(c);
+		platform_set_drvdata(pdev, NULL);
+	}
+	return 0;
+}
+
+static struct platform_driver bd71837_clk = {
+	.driver = {
+		.name = "bd71837-clk",
+	},
+	.probe = bd71837_clk_probe,
+	.remove = bd71837_clk_remove,
+};
+
+module_platform_driver(bd71837_clk);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837 chip clk driver");
+MODULE_LICENSE("GPL");
-- 
2.14.3

^ permalink raw reply related

* [PATCH v4 6/6] regulator: bd71837: BD71837 PMIC regulator driver
From: Matti Vaittinen @ 2018-05-30  8:43 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount
  Cc: linux-clk, devicetree, linux-kernel, mikko.mutanen,
	heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Support for controlling the 8 bucks and 7 LDOs the PMIC contains.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 drivers/regulator/Kconfig             |  11 +
 drivers/regulator/Makefile            |   1 +
 drivers/regulator/bd71837-regulator.c | 640 ++++++++++++++++++++++++++++++++++
 3 files changed, 652 insertions(+)
 create mode 100644 drivers/regulator/bd71837-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 097f61784a7d..139f4b53fea0 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -180,6 +180,17 @@ config REGULATOR_BCM590XX
 	  BCM590xx PMUs. This will enable support for the software
 	  controllable LDO/Switching regulators.
 
+config REGULATOR_BD71837
+	tristate "ROHM BD71837 Power Regulator"
+	depends on MFD_BD71837
+	help
+	  This driver supports voltage regulators on ROHM BD71837 PMIC.
+	  This will enable support for the software controllable buck
+	  and LDO regulators.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called bd71837-regulator.
+
 config REGULATOR_BD9571MWV
 	tristate "ROHM BD9571MWV Regulators"
 	depends on MFD_BD9571MWV
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 590674fbecd7..1b4d8ec416c2 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
+obj-$(CONFIG_REGULATOR_BD71837) += bd71837-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
new file mode 100644
index 000000000000..6eae4d0432a2
--- /dev/null
+++ b/drivers/regulator/bd71837-regulator.c
@@ -0,0 +1,640 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837-regulator.c ROHM BD71837MWV regulator driver
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/bd71837.h>
+#include <linux/regulator/of_regulator.h>
+
+struct bd71837_pmic {
+	struct regulator_desc descs[BD71837_REGULATOR_CNT];
+	struct bd71837 *mfd;
+	struct platform_device *pdev;
+	struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
+};
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec	10mV 2uS
+ * 10: 2.50mV/usec	10mV 4uS
+ * 11: 1.25mV/usec	10mV 8uS
+ */
+static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
+					   int ramp_delay)
+{
+	struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
+	struct bd71837 *mfd = pmic->mfd;
+	int id = rdev->desc->id;
+	unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
+
+	dev_dbg(&(pmic->pdev->dev), "Buck[%d] Set Ramp = %d\n", id + 1,
+		ramp_delay);
+	switch (ramp_delay) {
+	case 1 ... 1250:
+		ramp_value = BUCK_RAMPRATE_1P25MV;
+		break;
+	case 1251 ... 2500:
+		ramp_value = BUCK_RAMPRATE_2P50MV;
+		break;
+	case 2501 ... 5000:
+		ramp_value = BUCK_RAMPRATE_5P00MV;
+		break;
+	case 5001 ... 10000:
+		ramp_value = BUCK_RAMPRATE_10P00MV;
+		break;
+	default:
+		ramp_value = BUCK_RAMPRATE_10P00MV;
+		dev_err(&pmic->pdev->dev,
+			"%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+			rdev->desc->name, ramp_delay);
+	}
+
+	return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
+				  BUCK_RAMPRATE_MASK, ramp_value << 6);
+}
+
+/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
+ * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
+ * is changed. Hence we return -EBUSY for these if voltage is changed
+ * when BUCK/LDO is enabled.
+ */
+static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
+						    unsigned int sel)
+{
+	int ret;
+
+	ret = regulator_is_enabled_regmap(rdev);
+	if (!ret)
+		ret = regulator_set_voltage_sel_regmap(rdev, sel);
+	else if (ret == 1)
+		ret = -EBUSY;
+	return ret;
+}
+
+static struct regulator_ops bd71837_ldo_regulator_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_table,
+	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd71837_buck_regulator_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_table,
+	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd71837_buck1234_regulator_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.set_ramp_delay = bd71837_buck1234_set_ramp_delay,
+};
+
+/*
+ * BUCK1/2/3/4
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+	REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BUCK5
+ * 0.9V to 1.35V ()
+ */
+static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+	REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+	REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+};
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BUCK7
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const unsigned int buck_7_volts[] = {
+	1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+	REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * LDO2
+ * 0.8 or 0.9V
+ */
+const unsigned int ldo_2_volts[] = {
+	900000, 800000
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+	REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO5
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+	REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
+	REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static const struct regulator_desc bd71837_regulators[] = {
+	{
+		.name = "buck1",
+		.of_match = of_match_ptr("BUCK1"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK1,
+		.ops = &bd71837_buck1234_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck1234_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
+		.vsel_mask = BUCK1_RUN_MASK,
+		.enable_reg = BD71837_REG_BUCK1_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck2",
+		.of_match = of_match_ptr("BUCK2"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK2,
+		.ops = &bd71837_buck1234_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck1234_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
+		.vsel_mask = BUCK2_RUN_MASK,
+		.enable_reg = BD71837_REG_BUCK2_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck3",
+		.of_match = of_match_ptr("BUCK3"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK3,
+		.ops = &bd71837_buck1234_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck1234_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+		.vsel_mask = BUCK3_RUN_MASK,
+		.enable_reg = BD71837_REG_BUCK3_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck4",
+		.of_match = of_match_ptr("BUCK4"),
+		.regulators_node = of_match_ptr("regulators"),
+			.id = BD71837_BUCK4,
+		.ops = &bd71837_buck1234_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck1234_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+		.vsel_mask = BUCK4_RUN_MASK,
+		.enable_reg = BD71837_REG_BUCK4_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck5",
+		.of_match = of_match_ptr("BUCK5"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK5,
+		.ops = &bd71837_buck_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck5_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK5_VOLT,
+		.vsel_mask = BUCK5_MASK,
+		.enable_reg = BD71837_REG_BUCK5_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck6",
+		.of_match = of_match_ptr("BUCK6"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK6,
+		.ops = &bd71837_buck_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck6_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK6_VOLT,
+		.vsel_mask = BUCK6_MASK,
+		.enable_reg = BD71837_REG_BUCK6_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck7",
+		.of_match = of_match_ptr("BUCK7"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK7,
+		.ops = &bd71837_buck_regulator_nolinear_ops,
+		.type = REGULATOR_VOLTAGE,
+		.volt_table = &buck_7_volts[0],
+		.n_voltages = ARRAY_SIZE(buck_7_volts),
+		.vsel_reg = BD71837_REG_BUCK7_VOLT,
+		.vsel_mask = BUCK7_MASK,
+		.enable_reg = BD71837_REG_BUCK7_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "buck8",
+		.of_match = of_match_ptr("BUCK8"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_BUCK8,
+		.ops = &bd71837_buck_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
+		.linear_ranges = bd71837_buck8_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
+		.vsel_reg = BD71837_REG_BUCK8_VOLT,
+		.vsel_mask = BUCK8_MASK,
+		.enable_reg = BD71837_REG_BUCK8_CTRL,
+		.enable_mask = BD71837_BUCK_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo1",
+		.of_match = of_match_ptr("LDO1"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO1,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO1_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo1_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
+		.vsel_reg = BD71837_REG_LDO1_VOLT,
+		.vsel_mask = LDO1_MASK,
+		.enable_reg = BD71837_REG_LDO1_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo2",
+		.of_match = of_match_ptr("LDO2"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO2,
+		.ops = &bd71837_ldo_regulator_nolinear_ops,
+		.type = REGULATOR_VOLTAGE,
+		.volt_table = &ldo_2_volts[0],
+		.vsel_reg = BD71837_REG_LDO2_VOLT,
+		.vsel_mask = LDO2_MASK,
+		.n_voltages = ARRAY_SIZE(ldo_2_volts),
+		.n_voltages = BD71837_LDO2_VOLTAGE_NUM,
+		.enable_reg = BD71837_REG_LDO2_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo3",
+		.of_match = of_match_ptr("LDO3"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO3,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO3_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo3_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
+		.vsel_reg = BD71837_REG_LDO3_VOLT,
+		.vsel_mask = LDO3_MASK,
+		.enable_reg = BD71837_REG_LDO3_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo4",
+		.of_match = of_match_ptr("LDO4"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO4,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO4_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo4_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
+		.vsel_reg = BD71837_REG_LDO4_VOLT,
+		.vsel_mask = LDO4_MASK,
+		.enable_reg = BD71837_REG_LDO4_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo5",
+		.of_match = of_match_ptr("LDO5"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO5,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo5_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
+		/* LDO5 is supplied by buck6 */
+		.supply_name = "buck6",
+		.vsel_reg = BD71837_REG_LDO5_VOLT,
+		.vsel_mask = LDO5_MASK,
+		.enable_reg = BD71837_REG_LDO5_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo6",
+		.of_match = of_match_ptr("LDO6"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO6,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO6_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo6_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
+		/* LDO6 is supplied by buck7 */
+		.supply_name = "buck7",
+		.vsel_reg = BD71837_REG_LDO6_VOLT,
+		.vsel_mask = LDO6_MASK,
+		.enable_reg = BD71837_REG_LDO6_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ldo7",
+		.of_match = of_match_ptr("LDO7"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = BD71837_LDO7,
+		.ops = &bd71837_ldo_regulator_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+		.linear_ranges = bd71837_ldo7_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
+		.vsel_reg = BD71837_REG_LDO7_VOLT,
+		.vsel_mask = LDO7_MASK,
+		.enable_reg = BD71837_REG_LDO7_VOLT,
+		.enable_mask = BD71837_LDO_EN,
+		.owner = THIS_MODULE,
+	},
+};
+
+struct reg_init {
+	unsigned int reg;
+	unsigned int mask;
+};
+
+static int bd71837_probe(struct platform_device *pdev)
+{
+	struct bd71837_pmic *pmic;
+	struct bd71837_board *pdata;
+	struct regulator_config config = { 0 };
+	struct reg_init pmic_regulator_inits[] = {
+		{
+			.reg = BD71837_REG_BUCK1_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK2_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK3_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK4_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK5_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK6_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK7_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_BUCK8_CTRL,
+			.mask = BD71837_BUCK_SEL,
+		}, {
+			.reg = BD71837_REG_LDO1_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO2_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO3_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO4_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO5_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO6_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}, {
+			.reg = BD71837_REG_LDO7_VOLT,
+			.mask = BD71837_LDO_SEL,
+		}
+	};
+
+	int i, err;
+
+	pmic = devm_kzalloc(&pdev->dev, sizeof(struct bd71837_pmic),
+			    GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
+
+	pmic->pdev = pdev;
+	pmic->mfd = dev_get_drvdata(pdev->dev.parent);
+
+	if (!pmic->mfd) {
+		dev_err(&pdev->dev, "No MFD driver data\n");
+		err = -EINVAL;
+		goto err;
+	}
+	platform_set_drvdata(pdev, pmic);
+	pdata = dev_get_platdata(pmic->mfd->dev);
+
+	/* Register LOCK release */
+	err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
+				 (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
+	if (err) {
+		dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
+		goto err;
+	} else {
+		dev_dbg(&pmic->pdev->dev, "%s: Unlocked lock register 0x%x\n",
+			__func__, BD71837_REG_REGLOCK);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
+
+		struct regulator_desc *desc;
+		struct regulator_dev *rdev;
+
+		desc = &pmic->descs[i];
+
+		if (pdata)
+			config.init_data = pdata->init_data[i];
+
+		config.dev = pdev->dev.parent;
+		config.driver_data = pmic;
+		config.regmap = pmic->mfd->regmap;
+
+		rdev = devm_regulator_register(&pdev->dev, desc, &config);
+		if (IS_ERR(rdev)) {
+			dev_err(pmic->mfd->dev,
+				"failed to register %s regulator\n",
+				desc->name);
+			err = PTR_ERR(rdev);
+			goto err;
+		}
+		/* Regulator register gets the regulator constraints and
+		 * applies them (set_machine_constraints). This should have
+		 * turned the control register(s) to correct values and we
+		 * can now switch the control from PMIC state machine to the
+		 * register interface
+		 */
+		err = regmap_update_bits(pmic->mfd->regmap,
+					 pmic_regulator_inits[i].reg,
+					 pmic_regulator_inits[i].mask,
+					 0xFFFFFFFF);
+		if (err) {
+			dev_err(&pmic->pdev->dev,
+				"Failed to write BUCK/LDO SEL bit for (%s)\n",
+				desc->name);
+			goto err;
+		}
+
+		pmic->rdev[i] = rdev;
+	}
+
+	return 0;
+
+err:
+	return err;
+}
+
+static struct platform_driver bd71837_regulator = {
+	.driver = {
+		.name = "bd71837-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = bd71837_probe,
+};
+
+module_platform_driver(bd71837_regulator);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837 voltage regulator driver");
+MODULE_LICENSE("GPL");
-- 
2.14.3

^ permalink raw reply related

* Re: [PATCH v2 5/6] soc: qcom: rpmh powerdomain driver
From: Rajendra Nayak @ 2018-05-30  8:55 UTC (permalink / raw)
  To: David Collins, viresh.kumar, sboyd, andy.gross, ulf.hansson
  Cc: devicetree, linux-arm-msm, linux-kernel, Lina Iyer
In-Reply-To: <6f8e5fe2-199d-ba1f-19d7-2faf276075f3@codeaurora.org>

[]...

>>> +Required Properties:
>>> + - compatible: Should be one of the following
>>> +	* qcom,sdm845-rpmhpd: RPMh powerdomain for the sdm845 family of SoC
>>> + - power-domain-cells: number of cells in power domain specifier
>>> +	must be 1
>>> + - operating-points-v2: Phandle to the OPP table for the power-domain.
>>> +	Refer to Documentation/devicetree/bindings/power/power_domain.txt
>>> +	and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details
>>> +
>>> +Example:
>>> +
>>> +	rpmhpd: power-controller {
>>> +		compatible = "qcom,sdm845-rpmhpd";
>>> +		#power-domain-cells = <1>;
>>> +		operating-points-v2 = <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>,
>>> +				      <&rpmhpd_opp_table>;
>>
>> Can this be changed to simply:
>>   operating-points-v2 = <&rpmhpd_opp_table>;
>>
>> The opp binding documentation [1] states that this should be ok:
>>
>>     If only one phandle is available, then the same OPP table will be used
>>     for all power domains provided by the power domain provider.
> 
> thanks, I mentioned this to Viresh but didn't realize he fixed it up.
> Will remove the redundant entries.

Looks like the kernel implementation does not handle this yet, and I get
an error adding the OPP tables for the powerdomains if I just specify
a single OPP table phandle.

Viresh, is this expected with the latest patches in linux-next?

It would be good if I can specify just one phandle instead of coping
the same phandle n times. 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply

* Re: [PATCH v4 0/6] mfd/regulator/clk: bd71837: ROHM BD71837 PMIC driver
From: Matti Vaittinen @ 2018-05-30  9:05 UTC (permalink / raw)
  To: Matti Vaittinen
  Cc: mturquette, sboyd, robh+dt, mark.rutland, lee.jones, lgirdwood,
	broonie, mazziesaccount, linux-clk, devicetree, linux-kernel,
	mikko.mutanen, heikki.haikola
In-Reply-To: <cover.1527669443.git.matti.vaittinen@fi.rohmeurope.com>

Hello All,

I would like to ask for an educated opinion from more experienced
regulator driver developers.

On Wed, May 30, 2018 at 11:41:13AM +0300, Matti Vaittinen wrote:
> Patch series adding support for ROHM BD71837 PMIC.
> 
> BD71837 is a programmable Power Management IC for powering single-core,
> dual-core, and quad-core SoC’s such as NXP-i.MX 8M. It is optimized for
> low BOM cost and compact solution footprint. It integrates 8 buck
> regulators and 7 LDO’s to provide all the power rails required by the
> SoC and the commonly used peripherals.
> 
> The driver aims to not limit the usage of PMIC. Thus the buck and LDO
> naming is generic and not tied to any specific purposes. However there
> is following limitations which make it mostly suitable for use cases
> where the processor where PMIC driver is running is powered by the PMIC:
> 
> - The PMIC is not re-initialized if it resets. PMIC may reset as a
>   result of voltage monitoring (over/under voltage) or due to reset
>   request. Driver is only initializing PMIC at probe. This is not
>   problem as long as processor controlling PMIC is powered by PMIC.
> 
> - The PMIC internal state machine is ignored by driver. Driver assumes
>   the PMIC is wired so that it is always in "run" state when controlled
>   by the driver.
> 
> Changelog v4
> - remove mutex from regulator state check as core prevents simultaneous
>   accesses
> - allow voltage change for bucks 1 to 4 when regulator is enabled

This chip has 8 bucks. 4 of then support DVS (dynamic voltage scaling).
Other 4 can be used on PWM or PFM switching mode. When PWM is used
voltages can be changed without disabling regulator. On PFM this should
not be done. These latter 4 regulators can be forced to PWM mode via
control bit in register. This driver does not support controlling this
mode though. So this driver version just checks if regulator is enabled
before changing the voltage and if it is the voltage change fails with
-EBUSY

My question is whether it would be good idea to also read the 'force
PWM' bit when voltage is changed and allow the change if PWM mode is
forced to be used? Problem is that the check and voltage change can't be
atomic so there is a chance someone changes the mode (bypassing the
driver and regulator core) after this check but before we get to modify
the voltage. Furthermore, I doubt the 'force PWM' is widely used (but I
can't say for sure as I can't imagine all use cases) as it is not so
power efficient.

But as I am really inexperienced on this area I would like to get
opinions from people who know this field of industry better...

Br,
	Matti Vaittinen

^ permalink raw reply

* Re: [PATCH 3/3] ASoC: simple-card: add support for clock divider setup
From: Mark Brown @ 2018-05-30  9:10 UTC (permalink / raw)
  To: Daniel Mack; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <d6b9da97-8c71-ccfb-07e4-353620396a31@zonque.org>


[-- Attachment #1.1: Type: text/plain, Size: 1030 bytes --]

On Tue, May 29, 2018 at 10:29:10PM +0200, Daniel Mack wrote:
> On Tuesday, May 29, 2018 01:35 PM, Mark Brown wrote:

> > Why do we have anything that actually needs this?  The devices with a
> > set_clkdiv() operation are pretty legacy at this point and most of them
> > should just be figuring out the dividers for themselves anyway.

> The PXA platform CPU DAI still has it, and grepping also reveals some
> Freescale and Samsung platforms.

PXA is definitely very legacy, as are some of the Samsung and Freescale
ones - PXA in particular hasn't had much love in years.

> If that's considered legacy, we shouldn't add bindings for it of course. I
> can look into the PXA driver and see if it can auto-detect the dividers
> itself. It won't be straight forward though as the clocking setup also
> depends on configurations such as TDM slots, external vs. internal clocks
> etc. Meh.

It's usually relatively straightforward - something along the lines of
work out what your BCLK needs to be and everything else flows from that.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: [PATCH 3/3] ASoC: simple-card: add support for clock divider setup
From: Daniel Mack @ 2018-05-30  9:12 UTC (permalink / raw)
  To: Mark Brown; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <20180530091011.GA6920@sirena.org.uk>

On Wednesday, May 30, 2018 11:10 AM, Mark Brown wrote:
> On Tue, May 29, 2018 at 10:29:10PM +0200, Daniel Mack wrote:
>> On Tuesday, May 29, 2018 01:35 PM, Mark Brown wrote:
> 
>>> Why do we have anything that actually needs this?  The devices with a
>>> set_clkdiv() operation are pretty legacy at this point and most of them
>>> should just be figuring out the dividers for themselves anyway.
> 
>> The PXA platform CPU DAI still has it, and grepping also reveals some
>> Freescale and Samsung platforms.
> 
> PXA is definitely very legacy, as are some of the Samsung and Freescale
> ones - PXA in particular hasn't had much love in years.

Yes, I'm currently preparing a larger series of cleanups that I'll send 
for 4.18. I hope I can also tackle the clkdiv/pll things with that.


Thanks,
Daniel

^ permalink raw reply

* Re: [PATCH v14 0/2] Kryo CPU scaling driver
From: Viresh Kumar @ 2018-05-30  9:15 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Ilia Lin, Viresh Kumar, Nishanth Menon, Stephen Boyd, Rob Herring,
	Mark Rutland, Rafael J. Wysocki, Linux PM,
	devicetree@vger.kernel.org, Linux Kernel Mailing List
In-Reply-To: <CAJZ5v0gwtu-ptPskMeiXqWcRLhaGvvFVRyi-kX=nw_s6if7XGg@mail.gmail.com>

On 30-05-18, 10:08, Rafael J. Wysocki wrote:
> On Fri, May 25, 2018 at 2:07 PM, Ilia Lin <ilialin@codeaurora.org> wrote:
> > [v14]
> >  * Addressed comment from Sudeep about DT compatible
> >  * Added MAINTAINERS entry
> 
> This causes a build issue to occur in my bleeding-edge branch.
> 
> Does it depend on anything new in arm-soc?

He already sent a v15 and the changelog suggest he fixed that build
issue.

-- 
viresh

^ permalink raw reply

* Re: [PATCH v2 1/6] soc: qcom: rpmpd: Add a powerdomain driver to model corners
From: Ulf Hansson @ 2018-05-30  9:17 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: Viresh Kumar, Stephen Boyd, Andy Gross, devicetree, linux-arm-msm,
	Linux Kernel Mailing List, collinsd
In-Reply-To: <20180525100121.28214-2-rnayak@codeaurora.org>

On 25 May 2018 at 12:01, Rajendra Nayak <rnayak@codeaurora.org> wrote:
> The powerdomains for corners just pass the performance state set by the
> consumers to the RPM (Remote Power manager) which then takes care
> of setting the appropriate voltage on the corresponding rails to
> meet the performance needs.
>
> We add all powerdomain data needed on msm8996 here. This driver can easily
> be extended by adding data for other qualcomm SoCs as well.
>
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
>  .../devicetree/bindings/power/qcom,rpmpd.txt  |  55 ++++

Please split DT doc changes into separate patches, to simplify review.

>  drivers/soc/qcom/Kconfig                      |   9 +
>  drivers/soc/qcom/Makefile                     |   1 +
>  drivers/soc/qcom/rpmpd.c                      | 299 ++++++++++++++++++
>  4 files changed, 364 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmpd.txt
>  create mode 100644 drivers/soc/qcom/rpmpd.c
>

[...]

> +++ b/drivers/soc/qcom/rpmpd.c
> @@ -0,0 +1,299 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/export.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_domain.h>
> +#include <linux/mfd/qcom_rpm.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/soc/qcom/smd-rpm.h>
> +
> +#include <dt-bindings/mfd/qcom-rpm.h>
> +
> +#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
> +
> +/* Resource types */
> +#define RPMPD_SMPA 0x61706d73
> +#define RPMPD_LDOA 0x616f646c
> +
> +/* Operation Keys */
> +#define KEY_CORNER             0x6e726f63 /* corn */
> +#define KEY_ENABLE             0x6e657773 /* swen */
> +#define KEY_FLOOR_CORNER       0x636676   /* vfc */
> +
> +#define DEFINE_RPMPD_CORN_SMPA(_platform, _name, _active, r_id)                \
> +       static struct rpmpd _platform##_##_active;                      \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .peer = &_platform##_##_active,                         \
> +               .res_type = RPMPD_SMPA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       };                                                              \
> +       static struct rpmpd _platform##_##_active = {                   \
> +               .pd = { .name = #_active, },                            \
> +               .peer = &_platform##_##_name,                           \
> +               .active_only = true,                                    \
> +               .res_type = RPMPD_SMPA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       }
> +
> +#define DEFINE_RPMPD_CORN_LDOA(_platform, _name, r_id)                 \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .res_type = RPMPD_LDOA,                                 \
> +               .res_id = r_id,                                         \
> +               .key = KEY_CORNER,                                      \
> +       }
> +
> +#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type)               \
> +       static struct rpmpd _platform##_##_name = {                     \
> +               .pd = { .name = #_name, },                              \
> +               .res_type = r_type,                                     \
> +               .res_id = r_id,                                         \
> +               .key = KEY_FLOOR_CORNER,                                \
> +       }
> +
> +#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id)                  \
> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA)
> +
> +#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id)                  \
> +       DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA)
> +
> +struct rpmpd_req {
> +       __le32 key;
> +       __le32 nbytes;
> +       __le32 value;
> +};
> +
> +struct rpmpd {
> +       struct generic_pm_domain pd;
> +       struct rpmpd *peer;
> +       const bool active_only;
> +       unsigned long corner;
> +       bool enabled;
> +       const char *res_name;
> +       const int res_type;
> +       const int res_id;
> +       struct qcom_smd_rpm *rpm;
> +       __le32 key;
> +};
> +
> +struct rpmpd_desc {
> +       struct rpmpd **rpmpds;
> +       size_t num_pds;
> +};
> +
> +static DEFINE_MUTEX(rpmpd_lock);
> +
> +/* msm8996 RPM powerdomains */
> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddcx, vddcx_ao, 1);
> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddmx, vddmx_ao, 2);
> +DEFINE_RPMPD_CORN_LDOA(msm8996, vddsscx, 26);
> +
> +DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1);
> +DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26);
> +
> +static struct rpmpd *msm8996_rpmpds[] = {
> +       [0] = &msm8996_vddcx,
> +       [1] = &msm8996_vddcx_ao,
> +       [2] = &msm8996_vddcx_vfc,
> +       [3] = &msm8996_vddmx,
> +       [4] = &msm8996_vddmx_ao,
> +       [5] = &msm8996_vddsscx,
> +       [6] = &msm8996_vddsscx_vfc,
> +};

It's not my call, but honestly the above all macros makes the code
less readable.

Anyway, I think you should convert to allocate these structs
dynamically from the heap (kzalloc/kcalloc), instead of statically as
above.

> +
> +static const struct rpmpd_desc msm8996_desc = {
> +       .rpmpds = msm8996_rpmpds,
> +       .num_pds = ARRAY_SIZE(msm8996_rpmpds),
> +};
> +
> +static const struct of_device_id rpmpd_match_table[] = {
> +       { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, rpmpd_match_table);

[...]

> +static int rpmpd_aggregate_corner(struct rpmpd *pd)
> +{

Isn't the aggregation of the performance states in genpd sufficient
for your case?

I guess this is SoC specific and needed anyways, but then could you
perhaps add a few comments about what goes on here?

> +       int ret;
> +       struct rpmpd *peer = pd->peer;
> +       unsigned long active_corner, sleep_corner;
> +       unsigned long this_corner = 0, this_sleep_corner = 0;
> +       unsigned long peer_corner = 0, peer_sleep_corner = 0;
> +
> +       to_active_sleep(pd, pd->corner, &this_corner, &this_sleep_corner);
> +
> +       if (peer && peer->enabled)
> +               to_active_sleep(peer, peer->corner, &peer_corner,
> +                               &peer_sleep_corner);
> +
> +       active_corner = max(this_corner, peer_corner);
> +
> +       ret = rpmpd_send_corner(pd, QCOM_RPM_ACTIVE_STATE, active_corner);
> +       if (ret)
> +               return ret;
> +
> +       sleep_corner = max(this_sleep_corner, peer_sleep_corner);
> +
> +       return rpmpd_send_corner(pd, QCOM_RPM_SLEEP_STATE, sleep_corner);
> +}

[...]

> +static int rpmpd_probe(struct platform_device *pdev)
> +{
> +       int i;
> +       size_t num;
> +       struct genpd_onecell_data *data;
> +       struct qcom_smd_rpm *rpm;
> +       struct rpmpd **rpmpds;
> +       const struct rpmpd_desc *desc;
> +
> +       rpm = dev_get_drvdata(pdev->dev.parent);
> +       if (!rpm) {
> +               dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
> +               return -ENODEV;
> +       }
> +
> +       desc = of_device_get_match_data(&pdev->dev);
> +       if (!desc)
> +               return -EINVAL;
> +
> +       rpmpds = desc->rpmpds;
> +       num = desc->num_pds;
> +
> +       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +       if (!data)
> +               return -ENOMEM;
> +
> +       data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
> +                                    GFP_KERNEL);
> +       data->num_domains = num;
> +
> +       for (i = 0; i < num; i++) {
> +               if (!rpmpds[i])
> +                       continue;
> +
> +               rpmpds[i]->rpm = rpm;
> +               rpmpds[i]->pd.power_off = rpmpd_power_off;
> +               rpmpds[i]->pd.power_on = rpmpd_power_on;
> +               pm_genpd_init(&rpmpds[i]->pd, NULL, true);

Question: Is there no hierarchical topology of the PM domains. No
genpd subdomains?

> +
> +               data->domains[i] = &rpmpds[i]->pd;
> +       }
> +
> +       return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
> +}
> +
> +static int rpmpd_remove(struct platform_device *pdev)
> +{
> +       of_genpd_del_provider(pdev->dev.of_node);
> +       return 0;
> +}
> +
> +static struct platform_driver rpmpd_driver = {
> +       .driver = {
> +               .name = "qcom-rpmpd",
> +               .of_match_table = rpmpd_match_table,
> +       },
> +       .probe = rpmpd_probe,
> +       .remove = rpmpd_remove,
> +};
> +
> +static int __init rpmpd_init(void)
> +{
> +       return platform_driver_register(&rpmpd_driver);
> +}
> +core_initcall(rpmpd_init);
> +
> +static void __exit rpmpd_exit(void)
> +{
> +       platform_driver_unregister(&rpmpd_driver);
> +}
> +module_exit(rpmpd_exit);
> +
> +MODULE_DESCRIPTION("Qualcomm RPM Power Domain Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:qcom-rpmpd");
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
>

Besides the minor things above, this looks good to me.

Kind regards
Uffe

^ permalink raw reply

* Re: [PATCH v10 0/2] Initial Allwinner V3s CSI Support
From: Sakari Ailus @ 2018-05-30  9:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Yong Deng, Hans Verkuil, Mauro Carvalho Chehab, Rob Herring,
	Mark Rutland, Chen-Yu Tsai, David S. Miller, Greg Kroah-Hartman,
	Andrew Morton, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Yannick Fertre, Thierry Reding
In-Reply-To: <20180529095757.qkz7jyuxza7movbc@flea.home>

On Tue, May 29, 2018 at 11:57:57AM +0200, Maxime Ripard wrote:
> On Thu, May 17, 2018 at 11:02:24AM +0200, Maxime Ripard wrote:
> > On Fri, May 04, 2018 at 02:44:08PM +0800, Yong Deng wrote:
> > > This patchset add initial support for Allwinner V3s CSI.
> > > 
> > > Allwinner V3s SoC features two CSI module. CSI0 is used for MIPI CSI-2
> > > interface and CSI1 is used for parallel interface. This is not
> > > documented in datasheet but by test and guess.
> > > 
> > > This patchset implement a v4l2 framework driver and add a binding 
> > > documentation for it. 
> > > 
> > > Currently, the driver only support the parallel interface. And has been
> > > tested with a BT1120 signal which generating from FPGA. The following
> > > fetures are not support with this patchset:
> > >   - ISP 
> > >   - MIPI-CSI2
> > >   - Master clock for camera sensor
> > >   - Power regulator for the front end IC
> > 
> > I tested it on my H3 with a parallel camera, and it still works. Thanks!
> > 
> > Hans, Sakari, any chance this might land in 4.18?
> 
> Ping?

I'll try to look into this soonish but it seems to be too late for 4.18.
Sorry about that.

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: renesas: condor: add I2C0 support
From: Simon Horman @ 2018-05-30  9:35 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Mark Rutland, devicetree, Magnus Damm, Catalin Marinas,
	Will Deacon, linux-renesas-soc, Rob Herring,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <9bc27b57-cf26-3b03-6ec4-1e9788a46426@cogentembedded.com>

On Tue, May 29, 2018 at 06:46:10PM +0300, Sergei Shtylyov wrote:
> Hello!
> 
> On 05/29/2018 04:10 PM, Simon Horman wrote:
> 
> >> Define the Condor board dependent part of the I2C0 device node.
> >>
> >> The I2C0 bus is populated by 2 ON Semiconductor PCA9654 I/O expanders
> >> and Analog Devices  ADV7511W HDMI transmitter (but we're only describing
> >> the former chips now).
> >>
> >> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> >>
> >> ---
> >>  arch/arm64/boot/dts/renesas/r8a77980-condor.dts |   27 ++++++++++++++++++++++++
> >>  1 file changed, 27 insertions(+)
> >>
> >> Index: renesas/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> ===================================================================
> >> --- renesas.orig/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> +++ renesas/arch/arm64/boot/dts/renesas/r8a77980-condor.dts
> >> @@ -80,6 +80,28 @@
> >>  	clock-frequency = <32768>;
> >>  };
> >>  
> >> +&i2c0 {
> >> +	pinctrl-0 = <&i2c0_pins>;
> >> +	pinctrl-names = "default";
> >> +
> >> +	status = "okay";
> >> +	clock-frequency = <400000>;
> >> +
> >> +	io_expander0: gpio@20 {
> > 
> > Hi Sergei,
> > 
> > I'm a little confused about where 0x20 and 0x21 are derived from.
> > Could you explain a little?
> 
>    r-carv3h_system_evaluation_board_rev020.pdf, pp. 16-17, lower left corners.
> The schematics gives the 8-bit read/write addresses but we use uniform 7-bit
> I2C address in DTs.

Thanks, this patch looks fine to me.
However, I'd like to give others a chance to review it,
and it is dependent on patch 1/2 where I have a different review question.

Reviewed-by: Simon Horman <horms+renesas@verge.net.au>

> >> +		compatible = "onnn,pca9654";
> >> +		reg = <0x20>;
> >> +		gpio-controller;
> >> +		#gpio-cells = <2>;
> >> +	};
> >> +
> >> +	io_expander1: gpio@21 {
> >> +		compatible = "onnn,pca9654";
> >> +		reg = <0x21>;
> >> +		gpio-controller;
> >> +		#gpio-cells = <2>;
> >> +	};
> >> +};
> >> +
> >>  &mmc0 {
> >>  	pinctrl-0 = <&mmc_pins>;
> >>  	pinctrl-1 = <&mmc_pins_uhs>;
> 

^ permalink raw reply

* Re: [PATCH v3 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: Mark Brown @ 2018-05-30  9:37 UTC (permalink / raw)
  To: Doug Anderson
  Cc: David Collins, Liam Girdwood, Rob Herring, Mark Rutland,
	linux-arm-msm, Linux ARM, devicetree, LKML, Rajendra Nayak,
	Stephen Boyd
In-Reply-To: <CAD=FV=W4aDxWbcaJ9GZ1KkvyiTPAPR-oUoTFzJfS+LftU5ZP=Q@mail.gmail.com>

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

On Tue, May 29, 2018 at 10:30:33PM -0700, Doug Anderson wrote:
> On Wed, May 23, 2018 at 8:56 AM, Mark Brown <broonie@kernel.org> wrote:

> > Yes, that's definitely not what's expected but it's unfortunately what
> > the firmware chose to implement so we may well be stuck with it
> > unfortunately.

> We're not really stuck with it if we do what I was suggesting.  I was
> suggesting that every time we disable the regulator in Linux we have
> Linux vote for the lowest voltage it's comfortable with.  Linux keeps
> track of the true voltage that the driver wants and will always change
> its vote back to that before enabling.  Thus (assuming Linux is OK
> with 1.2 V - 1.4 V for a rail):

That's pretty much what it should do anyway with normally designed
hardware.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply


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