* Re: [PATCH v2 1/2] drm/panel: Add support for S6E3HA2 panel driver on TM2 board
From: Andrzej Hajda @ 2016-12-27 11:36 UTC (permalink / raw)
To: Hoegeun Kwon, robh-DgEjT+Ai2ygdnm+yROfE0A,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w, airlied-cv59FeDIM0c,
kgene-DgEjT+Ai2ygdnm+yROfE0A, krzk-DgEjT+Ai2ygdnm+yROfE0A
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, Donghwa Lee,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
cw00.choi-Sze3O3UU22JBDgjK7y7TUQ, Hyungwon Hwang
In-Reply-To: <1482829548-20842-2-git-send-email-hoegeun.kwon-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Hi Hoegeun Kwon,
Thanks for the patch.
On 27.12.2016 10:05, Hoegeun Kwon wrote:
> This patch add support for MIPI-DSI based S6E3HA2 AMOLED panel
> driver. This panel has 1440x2560 resolution in 5.7-inch physical
> panel in the TM2 device.
>
> Signed-off-by: Donghwa Lee <dh09.lee-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Hyungwon Hwang <human.hwang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Hoegeun Kwon <hoegeun.kwon-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
> Changes for V2:
>
> - Fixed the samsung,s6e3ha2.txt DT document.
> - Added active high or low after the description of the GPIOs.
> - Removed the reg and added a description of the virtual
> channel number of a DSI peripheral.
I do not understand this change, according to Rob's comment for previous
patch:
> reg doesn't really work here unless this node is a child of the DSI
> controller node. But if it is a child node, then you don't need the OF
> graph.
As the panel is controlled via DSI bus the node should be a child of DSI
controller, and therefore 'reg' property is required. Nice novum for me
is that OF graph is not required in that case.
>
> .../bindings/display/panel/samsung,s6e3ha2.txt | 62 ++
> drivers/gpu/drm/panel/Kconfig | 6 +
> drivers/gpu/drm/panel/Makefile | 1 +
> drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c | 756 +++++++++++++++++++++
> 4 files changed, 825 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
> create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
>
> diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
> new file mode 100644
> index 0000000..6e989ee
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
> @@ -0,0 +1,62 @@
> +Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel
> +
> +Required properties:
> + - compatible: "samsung,s6e3ha2"
> + - vdd3-supply: core voltage supply
Shouldn't be 'I/O voltage supply' ?
> + - vci-supply: voltage supply for analog circuits
> + - reset-gpios: a GPIO spec for the reset pin (active high)
According to specs it is active low, logic in the driver should be also
adjusted.
> + - enable-gpios: a GPIO spec for the panel enable pin (active high)
> + - te-gpios: a GPIO spec for the tearing effect synchronization signal
> + gpio pin (active high)
> +
> +Optional properties:
> + - display-timings: timings for the connected panel as described by [1]
In case of panels timings should be provided by device driver, not by dts.
> +
> +The device node can contain one 'port' child node with one child
> +'endpoint' node, according to the bindings defined in [2]. This
> +node should describe panel's video bus.
This could be dropped according to Rob's advice.
> +
> +The virtual channel number of a DSI peripheral as described by [3].
> +Must be in the range from 0 to 3.
> +/* peripheral responds to virtual channel 0 */
> +peripheral@0 {
> + compatible = "...";
> + reg = <0>;
> +};
> +
> +[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
> +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
> +[3]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
> +
> +Example:
> +
> + panel@0 {
> + ...
> +
> + compatible = "samsung,s6e3ha2";
> + vdd3-supply = <&ldo27_reg>;
> + vci-supply = <&ldo28_reg>;
> + reset-gpios = <&gpg0 0 GPIO_ACTIVE_HIGH>;
> + enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>;
> + te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>;
> +
> + display-timings {
> + timing-0 {
> + clock-frequency = <0>;
> + hactive = <1440>;
> + vactive = <2560>;
> + hfront-porch = <1>;
> + hback-porch = <1>;
> + hsync-len = <1>;
> + vfront-porch = <1>;
> + vback-porch = <15>;
> + vsync-len = <1>;
> + };
> + };
> +
> + port {
> + dsi_in: endpoint {
> + remote-endpoint = <&dsi_out>;
> + };
> + };
> + };
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 62aba97..e1a2fcd 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -58,6 +58,12 @@ config DRM_PANEL_SAMSUNG_S6E8AA0
> select DRM_MIPI_DSI
> select VIDEOMODE_HELPERS
>
> +config DRM_PANEL_SAMSUNG_S6E3HA2
> + tristate "Samsung S6E3HA2 DSI video mode panel"
> + depends on OF
> + select DRM_MIPI_DSI
It should be "depends on" in case of panels.
> + select VIDEOMODE_HELPERS
> +
> config DRM_PANEL_SHARP_LQ101R1SX01
> tristate "Sharp LQ101R1SX01 panel"
> depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index a5c7ec0..993699b 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -4,5 +4,6 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
> obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
> obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
> obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
> +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
Shoudn't it be sorted?
> obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
> obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
> diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
> new file mode 100644
> index 0000000..a6ad63b
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
> @@ -0,0 +1,756 @@
> +/*
> + * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
> + *
> + * Copyright (c) 2016 Samsung Electronics Co., Ltd.
> + * Donghwa Lee <dh09.lee-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + * Hyungwon Hwang <human.hwang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + * Hoegeun Kwon <hoegeun.kwon-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/regulator/consumer.h>
> +#include <video/mipi_display.h>
> +#include <video/of_videomode.h>
> +#include <video/videomode.h>
> +#include <linux/backlight.h>
> +
> +#define S6E3HA2_MIN_BRIGHTNESS 0
> +#define S6E3HA2_MAX_BRIGHTNESS 100
> +#define S6E3HA2_DEFAULT_BRIGHTNESS 80
> +
> +#define S6E3HA2_NUM_GAMMA_STEPS 46
> +#define S6E3HA2_GAMMA_CMD_CNT 35
> +#define S6E3HA2_VINT_STATUS_MAX 10
> +
> +static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
> + 0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
> + 0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
> + 0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
> + 0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
> + 0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
> + 0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
> + 0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
> + 0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
> + 0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
> + 0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
> + 0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
> + 0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
> + 0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
> + 0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
> + 0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
> + 0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
> + 0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
> + 0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
> + 0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
> + 0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
> + 0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
> + 0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
> + 0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
> + 0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
> + 0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
> + 0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
> + 0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
> + 0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
> + 0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
> + 0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
> + 0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
> + 0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
> + 0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
> + 0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
> + 0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
> + 0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
> + 0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
> + 0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
> + 0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
> + 0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
> + 0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
> + 0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
> + 0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
> + 0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
> + 0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
> + 0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
> + 0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
> + 0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
> + 0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
> + 0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
> + 0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
> + 0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
> + 0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
> + 0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
> + 0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
> + 0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
> + 0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
> + 0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
> + 0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
> + 0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
> + 0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
> + 0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
> + 0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
> + 0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
> + 0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
> + 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
> + 0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
> + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 },
> + { 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
> + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
> + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
> + 0x00, 0x00 }
> +};
> +
> +unsigned char VINT_TABLE[S6E3HA2_VINT_STATUS_MAX] = {
Lower case names.
> + 0x18, 0x19, 0x1a, 0x1b, 0x1c,
> + 0x1d, 0x1e, 0x1f, 0x20, 0x21
> +};
> +
> +struct s6e3ha2 {
> + struct device *dev;
> + struct drm_panel panel;
> + struct backlight_device *bl_dev;
> +
> + struct regulator_bulk_data supplies[2];
> + struct gpio_desc *reset_gpio;
> + struct gpio_desc *enable_gpio;
> + u32 power_on_delay;
> + u32 reset_delay;
> + struct videomode vm;
> +
> + /* This field is tested by functions directly accessing DSI bus before
> + * transfer, transfer is skipped if it is set. In case of transfer
> + * failure or unexpected response the field is set to error value.
> + * Such construct allows to eliminate many checks in higher level
> + * functions.
> + */
> + int error;
> +};
> +
> +static int s6e3ha2_clear_error(struct s6e3ha2 *ctx)
> +{
> + int ret = ctx->error;
> +
> + ctx->error = 0;
> + return ret;
> +}
> +
> +static void s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
> +{
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> + ssize_t ret;
> +
> + if (ctx->error < 0)
> + return;
> +
> + ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
> + if (ret < 0) {
> + dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n",
> + ret, (int)len, data);
> + ctx->error = ret;
> + }
> +}
> +
> +#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do { \
> + static const u8 d[] = { seq }; \
> + s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d)); \
> +} while (0)
> +
> +static void s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
> +}
> +
> +static void s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
> +}
> +
> +static void s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
> +}
> +
> +static void s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
> +}
> +
> +static void s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
> +}
> +
> +static void s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
> + s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62,
> + 0x40, 0x80, 0xc0, 0x28, 0x28, 0x28, 0x28, 0x39, 0xc5);
> +}
> +
> +static void s6e3ha2_aor_control(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
> +}
> +
> +static void s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
> +}
> +
> +static void s6e3ha2_acl_off(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
> +}
> +
> +static void s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
> +}
> +
> +static void s6e3ha2_test_global(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
> +}
> +
> +static void s6e3ha2_test(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
> +}
> +
> +static void s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx) {
> + s6e3ha2_dcs_write_seq_static(ctx,
> + 0xbd, 0x33, 0x11, 0x02, 0x16, 0x02, 0x16);
> +}
> +
> +static void s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
> +}
> +
> +static void s6e3ha2_poc_global(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
> +}
> +
> +static void s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
> +}
> +
> +static void s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
> +}
> +
> +static void s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
> +}
> +
> +static void s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
> +}
> +
> +static void s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
> +}
> +
> +static void s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
> +{
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
> + ndelay(100); /* need for 100ns delay */
> + s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
> +}
> +
> +static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
> +{
> + return bl_dev->props.brightness;
> +}
> +
> +static void s6e3ha2_set_vint(struct s6e3ha2 *ctx) {
Curly bracket should be on new line.
> + struct backlight_device *bl_dev = ctx->bl_dev;
> + unsigned int brightness = bl_dev->props.brightness;
> + unsigned char data[] = { 0xf4, 0x8b,
> + VINT_TABLE[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
> + S6E3HA2_MAX_BRIGHTNESS] };
> +
> + s6e3ha2_dcs_write(ctx, data, 3);
> +}
> +
> +static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
> +{
> + return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
> + S6E3HA2_MAX_BRIGHTNESS;
> +}
> +
> +static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
> +{
> + struct backlight_device *bl_dev = ctx->bl_dev;
> + unsigned int index = s6e3ha2_get_brightness_index(brightness);
> + u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
> +
> + memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
> + s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
> +
> + s6e3ha2_gamma_update(ctx);
> + bl_dev->props.brightness = brightness;
> +
> + return 0;
> +}
> +
> +static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
> +{
> + struct s6e3ha2 *ctx = (struct s6e3ha2 *)bl_get_data(bl_dev);
> + unsigned int brightness = bl_dev->props.brightness;
> +
> + if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
> + brightness > bl_dev->props.max_brightness) {
> + dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
> + return -EINVAL;
> + }
> +
> + if (bl_dev->props.power > FB_BLANK_NORMAL) {
> + dev_err(ctx->dev,
> + "panel must be at least in fb blank normal state\n");
This message adds unnecessary noise to the logs, it should be definitely
removed.
I do not know how this callback should react here, it would be good to
verify it in documentation of backlight interface, or other drivers.
> + return -EPERM;
> + }
> +
> + s6e3ha2_test_key_on_f0(ctx);
> + s6e3ha2_update_gamma(ctx, brightness);
> + s6e3ha2_aor_control(ctx);
> + s6e3ha2_set_vint(ctx);
> + s6e3ha2_test_key_off_f0(ctx);
> +
> + return ctx->error;
I think 'return s6e3ha2_clear_error(ctx);' would be better here, but
this is just my suggestion.
By the way, backlight framework is not synchronized with drm framework,
so there are possible races here.
> +}
> +
> +static const struct backlight_ops s6e3ha2_bl_ops = {
> + .get_brightness = s6e3ha2_get_brightness,
> + .update_status = s6e3ha2_set_brightness,
> +};
> +
> +static void s6e3ha2_panel_init(struct s6e3ha2 *ctx)
> +{
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> + u32 reset_delay = ctx->reset_delay * 1000;
> +
> + mipi_dsi_dcs_exit_sleep_mode(dsi);
> + usleep_range(reset_delay, reset_delay + 1000);
> +
> + s6e3ha2_test_key_on_f0(ctx);
> + s6e3ha2_single_dsi_set(ctx);
> + s6e3ha2_test_key_on_fc(ctx);
> + s6e3ha2_freq_calibration(ctx);
> + s6e3ha2_test_key_off_fc(ctx);
> + s6e3ha2_test_key_off_f0(ctx);
> +}
> +
> +static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
> +{
> + return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +}
> +
> +static int s6e3ha2_disable(struct drm_panel *panel)
> +{
> + struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> +
> + mipi_dsi_dcs_enter_sleep_mode(dsi);
> + if (ctx->error != 0)
> + goto err;
> +
> + mipi_dsi_dcs_set_display_off(dsi);
> + if (ctx->error != 0)
> + goto err;
> +
> + msleep(40);
> + ctx->bl_dev->props.power = FB_BLANK_NORMAL;
> +
> + return 0;
> +err:
> + return ctx->error;
> +}
> +
> +static int s6e3ha2_unprepare(struct drm_panel *panel)
> +{
> + struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
> + int ret;
> +
> + ret = s6e3ha2_clear_error(ctx);
> + if (!ret)
> + ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
> +
> + return s6e3ha2_power_off(ctx);
> +}
> +
> +static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
> +{
> + u32 reset_delay = ctx->reset_delay * 1000;
> + int ret;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> + if (ret < 0)
> + return ret;
> +
> + msleep(ctx->power_on_delay);
> +
> + gpiod_set_value(ctx->enable_gpio, 0);
> + usleep_range(reset_delay, reset_delay + 1000);
> + gpiod_set_value(ctx->enable_gpio, 1);
> +
> + gpiod_set_value(ctx->reset_gpio, 0);
> + usleep_range(reset_delay, reset_delay + 1000);
> + gpiod_set_value(ctx->reset_gpio, 1);
> + usleep_range(reset_delay, reset_delay + 1000);
> +
> + return 0;
> +}
> +static int s6e3ha2_prepare(struct drm_panel *panel)
> +{
> + struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
> + int ret;
> +
> + ret = s6e3ha2_power_on(ctx);
> + if (ret < 0)
> + return ret;
> +
> + s6e3ha2_panel_init(ctx);
> +
> + ret = s6e3ha2_clear_error(ctx);
> + if (ret < 0) {
> + s6e3ha2_power_off(ctx);
> + return ret;
> + }
> +
> + ctx->bl_dev->props.power = FB_BLANK_NORMAL;
> +
> + return 0;
> +}
> +
> +static int s6e3ha2_enable(struct drm_panel *panel)
> +{
> + struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
> + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
> +
> + /* common setting */
> + mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> +
> + s6e3ha2_test_key_on_f0(ctx);
> + s6e3ha2_test_key_on_fc(ctx);
> + s6e3ha2_touch_hsync_on1(ctx);
> + s6e3ha2_pentile_control(ctx);
> + s6e3ha2_poc_global(ctx);
> + s6e3ha2_poc_setting(ctx);
> + s6e3ha2_test_key_off_fc(ctx);
> +
> + /* pcd setting off for TB */
> + s6e3ha2_pcd_set_off(ctx);
> + s6e3ha2_err_fg_set(ctx);
> + s6e3ha2_te_start_setting(ctx);
> +
> + /* brightness setting */
> + s6e3ha2_set_brightness(ctx->bl_dev);
> + s6e3ha2_aor_control(ctx);
> + s6e3ha2_caps_elvss_set(ctx);
> + s6e3ha2_gamma_update(ctx);
> + s6e3ha2_acl_off(ctx);
> + s6e3ha2_acl_off_opr(ctx);
> + s6e3ha2_hbm_off(ctx);
> +
> + /* elvss temp compensation */
> + s6e3ha2_test_global(ctx);
> + s6e3ha2_test(ctx);
> + s6e3ha2_test_key_off_f0(ctx);
> +
> + mipi_dsi_dcs_set_display_on(dsi);
> + if (ctx->error != 0)
> + return ctx->error;
> +
> + ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
> +
> + return 0;
> +}
> +
> +static int s6e3ha2_get_modes(struct drm_panel *panel)
> +{
> + struct drm_connector *connector = panel->connector;
> + struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
> + struct drm_display_mode *mode;
> +
> + mode = drm_mode_create(connector->dev);
> + if (!mode) {
> + DRM_ERROR("failed to create a new display mode\n");
> + return 0;
> + }
> +
> + drm_display_mode_from_videomode(&ctx->vm, mode);
> + mode->vrefresh = 60;
> + mode->width_mm = 71;
> + mode->height_mm = 125;
> + connector->display_info.width_mm = mode->width_mm;
> + connector->display_info.height_mm = mode->height_mm;
> +
> + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> + drm_mode_probed_add(connector, mode);
> +
> + return 1;
> +}
> +
> +static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
> + .disable = s6e3ha2_disable,
> + .unprepare = s6e3ha2_unprepare,
> + .prepare = s6e3ha2_prepare,
> + .enable = s6e3ha2_enable,
> + .get_modes = s6e3ha2_get_modes,
> +};
> +
> +static int s6e3ha2_parse_dt(struct s6e3ha2 *ctx)
> +{
> + struct device *dev = ctx->dev;
> + struct device_node *np = dev->of_node;
> + int ret;
> +
> + ret = of_get_videomode(dev->of_node, &ctx->vm, 0);
> + if (ret < 0)
> + return ret;
> +
> + of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
> + of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
These props are not described in bindings, anyway I think these
properties similarly to display-timings are panel specific, so they
should be hardcoded into the driver.
> +
> + return 0;
> +}
> +
> +static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
> +{
> + struct device *dev = &dsi->dev;
> + struct s6e3ha2 *ctx;
> + int ret;
> +
> + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + mipi_dsi_set_drvdata(dsi, ctx);
> +
> + ctx->dev = dev;
> +
> + dsi->lanes = 4;
> + dsi->format = MIPI_DSI_FMT_RGB888;
> + dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
> +
> + ret = s6e3ha2_parse_dt(ctx);
> + if (ret < 0)
> + return ret;
> +
> + ctx->supplies[0].supply = "vdd3";
> + ctx->supplies[1].supply = "vci";
> +
> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
> + ctx->supplies);
> + if (ret < 0) {
> + dev_err(dev, "failed to get regulators: %d\n", ret);
> + return ret;
> + }
> +
> + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
> + if (IS_ERR(ctx->reset_gpio)) {
> + dev_err(dev, "cannot get reset-gpios %ld\n",
> + PTR_ERR(ctx->reset_gpio));
> + return PTR_ERR(ctx->reset_gpio);
> + }
> +
> + ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
> + if (IS_ERR(ctx->enable_gpio)) {
> + dev_err(dev, "cannot get enable-gpios %ld\n",
> + PTR_ERR(ctx->enable_gpio));
> + return PTR_ERR(ctx->enable_gpio);
> + }
> +
> + ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
> + &s6e3ha2_bl_ops, NULL);
> + if (IS_ERR(ctx->bl_dev)) {
> + dev_err(dev, "failed to register backlight device\n");
> + return PTR_ERR(ctx->bl_dev);
> + }
> +
> + ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
> + ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
> + ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
> +
> + drm_panel_init(&ctx->panel);
> + ctx->panel.dev = dev;
> + ctx->panel.funcs = &s6e3ha2_drm_funcs;
> +
> + ret = drm_panel_add(&ctx->panel);
> + if (ret < 0)
> + goto unregister_backlight;
> +
> + ret = mipi_dsi_attach(dsi);
> + if (ret < 0)
> + goto remove_panel;
> +
> + return ret;
> +
> +remove_panel:
> + drm_panel_remove(&ctx->panel);
> +
> +unregister_backlight:
> + backlight_device_unregister(ctx->bl_dev);
> +
> + return ret;
> +}
> +
> +static int s6e3ha2_remove(struct mipi_dsi_device *dsi)
> +{
> + struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
> +
> + mipi_dsi_detach(dsi);
> + drm_panel_remove(&ctx->panel);
> + backlight_device_unregister(ctx->bl_dev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id s6e3ha2_of_match[] = {
> + { .compatible = "samsung,s6e3ha2" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
> +
> +static struct mipi_dsi_driver s6e3ha2_driver = {
> + .probe = s6e3ha2_probe,
> + .remove = s6e3ha2_remove,
> + .driver = {
> + .name = "panel-samsung-s6e3ha2",
> + .of_match_table = s6e3ha2_of_match,
> + },
> +};
> +module_mipi_dsi_driver(s6e3ha2_driver);
> +
> +MODULE_AUTHOR("Donghwa Lee <dh09.lee-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_AUTHOR("Hyungwon Hwang <human.hwang-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
> +MODULE_LICENSE("GPL v2");
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 05/12] Document: dt: binding: imx: update pinctrl doc for imx6sll
From: Linus Walleij @ 2016-12-27 12:59 UTC (permalink / raw)
To: Bai Ping
Cc: Shawn Guo, Michael Turquette, Stephen Boyd, Rob Herring,
Mark Rutland, Sascha Hauer, Fabio Estevam, Daniel Lezcano,
Thomas Gleixner, Philipp Zabel, linux-clk,
devicetree@vger.kernel.org, linux-gpio@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, jacky.baip
In-Reply-To: <1482832070-22668-6-git-send-email-ping.bai@nxp.com>
On Tue, Dec 27, 2016 at 10:47 AM, Bai Ping <ping.bai@nxp.com> wrote:
> Add pinctrl binding doc update for imx6sll.
>
> Signed-off-by: Bai Ping <ping.bai@nxp.com>
I have to push back on this a bit.
> +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
> +and usage.
I understand that it is building on top of the old i.MX bindings and that
it has some kind of "tradition" coming with it.
At the same time, the i.MX bindings came about before we had the
generic pin control bindings defined.
> +CONFIG bits definition:
> +PAD_CTL_LVE (1 << 22)
> +PAD_CTL_HYS (1 << 16)
> +PAD_CTL_PUS_100K_DOWN (0 << 14)
> +PAD_CTL_PUS_47K_UP (1 << 14)
> +PAD_CTL_PUS_100K_UP (2 << 14)
> +PAD_CTL_PUS_22K_UP (3 << 14)
> +PAD_CTL_PUE (1 << 13)
> +PAD_CTL_PKE (1 << 12)
> +PAD_CTL_ODE (1 << 11)
> +PAD_CTL_SPEED_LOW (0 << 6)
> +PAD_CTL_SPEED_MED (1 << 6)
> +PAD_CTL_SPEED_HIGH (3 << 6)
> +PAD_CTL_DSE_DISABLE (0 << 3)
> +PAD_CTL_DSE_260ohm (1 << 3)
> +PAD_CTL_DSE_130ohm (2 << 3)
> +PAD_CTL_DSE_87ohm (3 << 3)
> +PAD_CTL_DSE_65ohm (4 << 3)
> +PAD_CTL_DSE_52ohm (5 << 3)
> +PAD_CTL_DSE_43ohm (6 << 3)
> +PAD_CTL_DSE_37ohm (7 << 3)
> +PAD_CTL_SRE_FAST (1 << 0)
> +PAD_CTL_SRE_SLOW (0 << 0)
A whole slew of these if not all correspond to the generic bindings.
I would consider augmenting the code in the driver to handle the generic
bindings *in addition* to the old legacy bindings, and use those over these
random custom bits.
Read drivers using CONFIG_GENERIC_PINCONF as an inspiration.
For example see commit
cefbf1a1b29531a970bc2908a50a75d6474fcc38
"pinctrl: sunxi: Support generic binding"
from Maxime Ripard, where he does a similar thing for sunxi.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v2 06/12] driver: pinctrl: imx: Add pinctrl driver support for imx6sll
From: Linus Walleij @ 2016-12-27 13:01 UTC (permalink / raw)
To: Bai Ping
Cc: Mark Rutland, devicetree@vger.kernel.org, Philipp Zabel,
Michael Turquette, Daniel Lezcano, Stephen Boyd,
linux-gpio@vger.kernel.org, Rob Herring, Sascha Hauer, jacky.baip,
Fabio Estevam, Thomas Gleixner, Shawn Guo, linux-clk,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1482832070-22668-7-git-send-email-ping.bai@nxp.com>
On Tue, Dec 27, 2016 at 10:47 AM, Bai Ping <ping.bai@nxp.com> wrote:
> Add pinctrl driver support for imx6sll.
>
> Signed-off-by: Bai Ping <ping.bai@nxp.com>
(...)
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -514,6 +514,7 @@ config SOC_IMX6SL
>
> config SOC_IMX6SLL
> bool "i.MX6 SoloLiteLite support"
> + select PINCTRL_IMX6SLL
This needs to be separate so I can merge the pure pin control patch
to my tree.
Apart from that, look into using generic pinconf.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v7 0/2] Add support for Omnivision OV5647
From: Ramiro Oliveira @ 2016-12-27 13:59 UTC (permalink / raw)
To: mchehab-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-media-u79uwXL29TY76Z2rM5mHXA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
linux-0h96xk9xTtrk1uMJSBkQmQ, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
dheitmueller-eb9eJ82Ua7k9XoPSrs7Ehg,
slongerbeam-Re5JQEeQqe8AvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
robert.jarzmik-GANU6spQydw, pavel-+ZI9xUNit7I,
pali.rohar-Re5JQEeQqe8AvxtiuMwx3w,
sakari.ailus-VuQAYsv1563Yd54FQh9/CA, mark.rutland-5wv7dgnIgG8,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
Hello,
This patch adds support for the Omnivision OV5647 sensor.
At the moment it only supports 640x480 in Raw 8.
This is the seventh version of the OV5647 camera driver patchset.
v7:
- Remove "0x" and leading 0 from DT documentation examples
v6:
- Add example to DT documentation
- Remove data-lanes and clock-lane property from DT
- Add external clock property to DT
- Order includes
- Remove unused variables and functions
- Add external clock handling
- Add power on counter
- Change from g/s_parm to g/s_frame_interval
v5:
- Refactor code
- Change comments
- Add missing error handling in some functions
v4:
- Add correct license
- Revert debugging info to generic infrastructure
- Turn defines into enums
- Correct code style issues
- Remove unused defines
- Make sure all errors where being handled
- Rename some functions to make code more readable
- Add some debugging info
v3:
- No changes. Re-submitted due to lack of responses
v2:
- Corrections in DT documentation
Ramiro Oliveira (2):
Add OV5647 device tree documentation
Add support for OV5647 sensor.
.../devicetree/bindings/media/i2c/ov5647.txt | 35 +
MAINTAINERS | 7 +
drivers/media/i2c/Kconfig | 12 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/ov5647.c | 718 +++++++++++++++++++++
5 files changed, 773 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ov5647.txt
create mode 100644 drivers/media/i2c/ov5647.c
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v7 1/2] Add OV5647 device tree documentation
From: Ramiro Oliveira @ 2016-12-27 13:59 UTC (permalink / raw)
To: mchehab, linux-kernel, linux-media, robh+dt, devicetree
Cc: davem, gregkh, geert+renesas, akpm, linux, hverkuil, dheitmueller,
slongerbeam, lars, robert.jarzmik, pavel, pali.rohar,
sakari.ailus, mark.rutland, Ramiro.Oliveira, CARLOS.PALMINHA
In-Reply-To: <cover.1482846784.git.roliveir@synopsys.com>
Create device tree bindings documentation.
Signed-off-by: Ramiro Oliveira <roliveir@synopsys.com>
---
.../devicetree/bindings/media/i2c/ov5647.txt | 35 ++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ov5647.txt
diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.txt b/Documentation/devicetree/bindings/media/i2c/ov5647.txt
new file mode 100644
index 000000000000..57fd40036c26
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.txt
@@ -0,0 +1,35 @@
+Omnivision OV5647 raw image sensor
+---------------------------------
+
+OV5647 is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces
+and CCI (I2C compatible) control bus.
+
+Required properties:
+
+- compatible : "ovti,ov5647".
+- reg : I2C slave address of the sensor.
+- clocks : Reference to the xclk clock.
+- clock-names : Should be "xclk".
+- clock-frequency : Frequency of the xclk clock.
+
+The common video interfaces bindings (see video-interfaces.txt) should be
+used to specify link to the image data receiver. The OV5647 device
+node should contain one 'port' child node with an 'endpoint' subnode.
+
+Example:
+
+ i2c@2000 {
+ ...
+ ov: camera@36 {
+ compatible = "ovti,ov5647";
+ reg = <0x36>;
+ clocks = <&camera_clk>;
+ clock-names = "xclk";
+ clock-frequency = <30000000>;
+ port {
+ camera_1: endpoint {
+ remote-endpoint = <&csi1_ep1>;
+ };
+ };
+ };
+ };
--
2.11.0
^ permalink raw reply related
* [PATCH v7 2/2] Add support for OV5647 sensor.
From: Ramiro Oliveira @ 2016-12-27 13:59 UTC (permalink / raw)
To: mchehab, linux-kernel, linux-media, robh+dt, devicetree
Cc: davem, gregkh, geert+renesas, akpm, linux, hverkuil, dheitmueller,
slongerbeam, lars, robert.jarzmik, pavel, pali.rohar,
sakari.ailus, mark.rutland, Ramiro.Oliveira, CARLOS.PALMINHA
In-Reply-To: <cover.1482846784.git.roliveir@synopsys.com>
Modes supported:
- 640x480 RAW 8
Signed-off-by: Ramiro Oliveira <roliveir@synopsys.com>
---
MAINTAINERS | 7 +
drivers/media/i2c/Kconfig | 12 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/ov5647.c | 718 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 738 insertions(+)
create mode 100644 drivers/media/i2c/ov5647.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cfff2c9e3d94..346bd8d55703 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9095,6 +9095,13 @@ M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/char/pcmcia/cm4040_cs.*
+OMNIVISION OV5647 SENSOR DRIVER
+M: Ramiro Oliveira <roliveir@synopsys.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/ov5647.c
+
OMNIVISION OV7670 SENSOR DRIVER
M: Jonathan Corbet <corbet@lwn.net>
L: linux-media@vger.kernel.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index b979ea148251..155878b25566 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -531,6 +531,18 @@ config VIDEO_OV2659
To compile this driver as a module, choose M here: the
module will be called ov2659.
+config VIDEO_OV5647
+ tristate "OmniVision OV5647 sensor support"
+ depends on OF
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV5647 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov5647.
+
config VIDEO_OV7640
tristate "OmniVision OV7640 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 92773b2e6225..0d9014c7ab43 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -82,3 +82,4 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
+obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
new file mode 100644
index 000000000000..c2828650d3a3
--- /dev/null
+++ b/drivers/media/i2c/ov5647.c
@@ -0,0 +1,718 @@
+/*
+ * A V4L2 driver for OmniVision OV5647 cameras.
+ *
+ * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver
+ * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * Copyright (C) 2016, Synopsys, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-of.h>
+
+#define SENSOR_NAME "ov5647"
+
+#define OV5647_SW_RESET 0x1003
+#define OV5647_REG_CHIPID_H 0x300A
+#define OV5647_REG_CHIPID_L 0x300B
+
+#define REG_TERM 0xfffe
+#define VAL_TERM 0xfe
+#define REG_DLY 0xffff
+
+#define OV5647_ROW_START 0x01
+#define OV5647_ROW_START_MIN 0
+#define OV5647_ROW_START_MAX 2004
+#define OV5647_ROW_START_DEF 54
+
+#define OV5647_COLUMN_START 0x02
+#define OV5647_COLUMN_START_MIN 0
+#define OV5647_COLUMN_START_MAX 2750
+#define OV5647_COLUMN_START_DEF 16
+
+#define OV5647_WINDOW_HEIGHT 0x03
+#define OV5647_WINDOW_HEIGHT_MIN 2
+#define OV5647_WINDOW_HEIGHT_MAX 2006
+#define OV5647_WINDOW_HEIGHT_DEF 1944
+
+#define OV5647_WINDOW_WIDTH 0x04
+#define OV5647_WINDOW_WIDTH_MIN 2
+#define OV5647_WINDOW_WIDTH_MAX 2752
+#define OV5647_WINDOW_WIDTH_DEF 2592
+
+struct regval_list {
+ u16 addr;
+ u8 data;
+};
+
+struct cfg_array {
+ struct regval_list *regs;
+ int size;
+};
+
+struct ov5647 {
+ struct device *dev;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct mutex lock;
+ struct v4l2_mbus_framefmt format;
+ unsigned int width;
+ unsigned int height;
+ int power_count;
+ struct clk *xclk;
+ /* External clock frequency currently supported is 30MHz */
+ u32 xclk_freq;
+};
+
+static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov5647, sd);
+}
+
+static struct regval_list sensor_oe_disable_regs[] = {
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+};
+
+static struct regval_list sensor_oe_enable_regs[] = {
+ {0x3000, 0x0f},
+ {0x3001, 0xff},
+ {0x3002, 0xe4},
+};
+
+static struct regval_list ov5647_640x480[] = {
+ {0x0100, 0x00},
+ {0x0103, 0x01},
+ {0x3034, 0x08},
+ {0x3035, 0x21},
+ {0x3036, 0x46},
+ {0x303c, 0x11},
+ {0x3106, 0xf5},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3827, 0xec},
+ {0x370c, 0x0f},
+ {0x3612, 0x59},
+ {0x3618, 0x00},
+ {0x5000, 0x06},
+ {0x5001, 0x01},
+ {0x5002, 0x41},
+ {0x5003, 0x08},
+ {0x5a00, 0x08},
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+ {0x3016, 0x08},
+ {0x3017, 0xe0},
+ {0x3018, 0x44},
+ {0x301c, 0xf8},
+ {0x301d, 0xf0},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3c01, 0x80},
+ {0x3b07, 0x0c},
+ {0x380c, 0x07},
+ {0x380d, 0x68},
+ {0x380e, 0x03},
+ {0x380f, 0xd8},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3708, 0x64},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xE0},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xa1},
+ {0x3811, 0x08},
+ {0x3813, 0x02},
+ {0x3630, 0x2e},
+ {0x3632, 0xe2},
+ {0x3633, 0x23},
+ {0x3634, 0x44},
+ {0x3636, 0x06},
+ {0x3620, 0x64},
+ {0x3621, 0xe0},
+ {0x3600, 0x37},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x3731, 0x02},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3f05, 0x02},
+ {0x3f06, 0x10},
+ {0x3f01, 0x0a},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0d, 0x04},
+ {0x3a0e, 0x03},
+ {0x3a0f, 0x58},
+ {0x3a10, 0x50},
+ {0x3a1b, 0x58},
+ {0x3a1e, 0x50},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x28},
+ {0x4001, 0x02},
+ {0x4004, 0x02},
+ {0x4000, 0x09},
+ {0x4837, 0x24},
+ {0x4050, 0x6e},
+ {0x4051, 0x8f},
+ {0x0100, 0x01},
+};
+
+/**
+ * @short I2C Write operation
+ * @param[in] i2c_client I2C client
+ * @param[in] reg register address
+ * @param[in] val value to write
+ * @return Error code
+ */
+static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+{
+ int ret;
+ unsigned char data[3] = { reg >> 8, reg & 0xff, val};
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = i2c_master_send(client, data, 3);
+ if (ret != 3) {
+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+ return 0;
+}
+
+/**
+ * @short I2C Read operation
+ * @param[in] i2c_client I2C client
+ * @param[in] reg register address
+ * @param[out] val value read
+ * @return Error code
+ */
+static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
+{
+ int ret;
+ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+
+ ret = i2c_master_send(client, data_w, 2);
+
+ if (ret < 2) {
+ dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+
+
+ ret = i2c_master_recv(client, val, 1);
+
+ if (ret < 1) {
+ dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+ return 0;
+}
+
+static int ov5647_write_array(struct v4l2_subdev *sd,
+ struct regval_list *regs, int array_size)
+{
+ int i = 0;
+ int ret = 0;
+
+ if (!regs)
+ return -EINVAL;
+
+ while (i < array_size) {
+ ret = ov5647_write(sd, regs->addr, regs->data);
+ if (ret < 0)
+ return ret;
+ i++;
+ regs++;
+ }
+ return 0;
+}
+
+static void ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
+{
+ u8 channel_id;
+
+ ov5647_read(sd, 0x4814, &channel_id);
+ channel_id &= ~(3 << 6);
+ ov5647_write(sd, 0x4814, channel_id | (channel << 6));
+}
+
+void ov5647_stream_on(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ov5647_write(sd, 0x4202, 0x00);
+ dev_dbg(&client->dev, "Stream on");
+ ov5647_write(sd, 0x300D, 0x00);
+}
+
+void ov5647_stream_off(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ov5647_write(sd, 0x4202, 0x0f);
+ dev_dbg(&client->dev, "Stream off");
+ ov5647_write(sd, 0x300D, 0x01);
+}
+
+/**
+ * @short Set SW standby
+ * @param[in] sd v4l2 sd
+ * @param[in] stanby standby mode status (on or off)
+ * @return Error code
+ */
+static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
+{
+ int ret;
+ unsigned char rdval;
+
+ ret = ov5647_read(sd, 0x0100, &rdval);
+ if (ret != 0)
+ return ret;
+
+ if (standby)
+ rdval &= 0xfe;
+ else
+ rdval |= 0x01;
+
+ ret = ov5647_write(sd, 0x0100, rdval);
+
+ return ret;
+}
+
+/**
+ * @short Initialize sensor
+ * @param[in] sd v4l2 subdev
+ * @param[in] val not used
+ * @return Error code
+ */
+static int __sensor_init(struct v4l2_subdev *sd)
+{
+ int ret;
+ u8 resetval;
+ u8 rdval;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ dev_dbg(&client->dev, "sensor init\n");
+
+ ret = ov5647_read(sd, 0x0100, &rdval);
+ if (ret != 0)
+ return ret;
+
+ ov5647_write(sd, 0x4800, 0x25);
+ ov5647_stream_off(sd);
+
+ ret = ov5647_write_array(sd, ov5647_640x480,
+ ARRAY_SIZE(ov5647_640x480));
+ if (ret < 0) {
+ dev_err(&client->dev, "write sensor_default_regs error\n");
+ return ret;
+ }
+
+ ov5647_set_virtual_channel(sd, 0);
+
+ ov5647_read(sd, 0x0100, &resetval);
+ if (!(resetval & 0x01)) {
+ dev_err(&client->dev, "Device was in SW standby");
+ ov5647_write(sd, 0x0100, 0x01);
+ }
+
+ ov5647_write(sd, 0x4800, 0x04);
+ ov5647_stream_on(sd);
+
+ return 0;
+}
+
+/**
+ * @short Control sensor power state
+ * @param[in] sd v4l2 subdev
+ * @param[in] on Sensor power
+ * @return Error code
+ */
+static int sensor_power(struct v4l2_subdev *sd, int on)
+{
+ int ret;
+ struct ov5647 *ov5647 = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = 0;
+ mutex_lock(&ov5647->lock);
+
+ if (on && !ov5647->power_count) {
+ dev_dbg(&client->dev, "OV5647 power on\n");
+
+ clk_set_rate(ov5647->xclk, ov5647->xclk_freq);
+
+ ret = clk_prepare_enable(ov5647->xclk);
+ if (ret < 0) {
+ dev_err(ov5647->dev, "clk prepare enable failed\n");
+ goto out;
+ }
+
+ ret = ov5647_write_array(sd, sensor_oe_enable_regs,
+ ARRAY_SIZE(sensor_oe_enable_regs));
+ if (ret < 0) {
+ clk_disable_unprepare(ov5647->xclk);
+ dev_err(&client->dev,
+ "write sensor_oe_enable_regs error\n");
+ goto out;
+ }
+
+ ret = __sensor_init(sd);
+ if (ret < 0) {
+ clk_disable_unprepare(ov5647->xclk);
+ dev_err(&client->dev,
+ "Camera not available, check Power\n");
+ goto out;
+ }
+ } else if (!on && ov5647->power_count == 1) {
+ dev_dbg(&client->dev, "OV5647 power off\n");
+
+ dev_dbg(&client->dev, "disable oe\n");
+ ret = ov5647_write_array(sd, sensor_oe_disable_regs,
+ ARRAY_SIZE(sensor_oe_disable_regs));
+
+ if (ret < 0)
+ dev_dbg(&client->dev, "disable oe failed\n");
+
+ ret = set_sw_standby(sd, true);
+
+ if (ret < 0)
+ dev_dbg(&client->dev, "soft stby failed\n");
+
+ clk_disable_unprepare(ov5647->xclk);
+ }
+
+ /* Update the power count. */
+ ov5647->power_count += on ? 1 : -1;
+ WARN_ON(ov5647->power_count < 0);
+
+out:
+ mutex_unlock(&ov5647->lock);
+
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/**
+ * @short Get register value
+ * @param[in] sd v4l2 subdev
+ * @param[in] reg register struct
+ * @return Error code
+ */
+static int sensor_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ unsigned char val = 0;
+ int ret;
+
+ ret = ov5647_read(sd, reg->reg & 0xff, &val);
+ if (ret != 0)
+ return ret;
+
+ reg->val = val;
+ reg->size = 1;
+
+ return ret;
+}
+
+/**
+ * @short Set register value
+ * @param[in] sd v4l2 subdev
+ * @param[in] reg register struct
+ * @return Error code
+ */
+static int sensor_set_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff);
+}
+#endif
+
+/**
+ * @short Subdev core operations registration
+ */
+static const struct v4l2_subdev_core_ops sensor_core_ops = {
+ .s_power = sensor_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = sensor_get_register,
+ .s_register = sensor_set_register,
+#endif
+};
+
+static int enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops subdev_pad_ops = {
+ .enum_mbus_code = enum_mbus_code,
+};
+
+
+/**
+ * @short Subdev operations registration
+ *
+ */
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &sensor_core_ops,
+ .pad = &subdev_pad_ops,
+};
+
+/**
+ * @short Detect camera version and model
+ * @param[in] sd v4l2 subdev
+ * @return Error code
+ */
+static int ov5647_detect(struct v4l2_subdev *sd)
+{
+ unsigned char v;
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = ov5647_write(sd, OV5647_SW_RESET, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x56) {
+ dev_err(&client->dev, "Wrong model version detected");
+ return -ENODEV;
+ }
+ ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x47) {
+ dev_err(&client->dev, "Wrong model version detected");
+ return -ENODEV;
+ }
+
+ ret = ov5647_write(sd, OV5647_SW_RESET, 0x00);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * @short Detect if camera is registered
+ * @param[in] sd v4l2 subdev
+ * @return Error code
+ */
+static int ov5647_registered(struct v4l2_subdev *sd)
+{
+ return 0;
+}
+
+/**
+ * @short Open device
+ * @param[in] sd v4l2 subdev
+ * @param[in] fh v4l2 file handler
+ * @return Error code
+ */
+static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_rect *crop =
+ v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+
+ crop->left = OV5647_COLUMN_START_DEF;
+ crop->top = OV5647_ROW_START_DEF;
+ crop->width = OV5647_WINDOW_WIDTH_DEF;
+ crop->height = OV5647_WINDOW_HEIGHT_DEF;
+
+ format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+
+ format->width = OV5647_WINDOW_WIDTH_DEF;
+ format->height = OV5647_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return sensor_power(sd, true);
+}
+
+/**
+ * @short Open device
+ * @param[in] sd v4l2 subdev
+ * @param[in] fh v4l2 file handler
+ * @return Error code
+ */
+static int ov5647_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return sensor_power(sd, false);
+}
+
+/**
+ * @short Subdev internal operations registration
+ *
+ */
+static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
+ .registered = ov5647_registered,
+ .open = ov5647_open,
+ .close = ov5647_close,
+};
+
+/**
+ * @short Initialization routine - Entry point of the driver
+ * @param[in] client pointer to the i2c client structure
+ * @param[in] id pointer to the i2c device id structure
+ * @return 0 on success and a negative number on failure
+ */
+static int ov5647_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ov5647 *sensor;
+ int ret;
+ struct v4l2_subdev *sd;
+
+ dev_info(&client->dev, "Installing OmniVision OV5647 camera driver\n");
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ /* get system clock (xclk) */
+ sensor->xclk = devm_clk_get(dev, "xclk");
+ if (IS_ERR(sensor->xclk)) {
+ dev_err(dev, "could not get xclk");
+ return PTR_ERR(sensor->xclk);
+ }
+
+ ret = of_property_read_u32(dev->of_node, "clock-frequency",
+ &sensor->xclk_freq);
+ if (ret) {
+ dev_err(dev, "could not get xclk frequency\n");
+ return ret;
+ }
+
+ mutex_init(&sensor->lock);
+ sensor->dev = dev;
+
+ sd = &sensor->sd;
+ v4l2_i2c_subdev_init(sd, client, &subdev_ops);
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
+ if (ret < 0)
+ goto mutex_remove;
+
+ ret = ov5647_detect(sd);
+ if (ret < 0)
+ goto error;
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+error:
+ media_entity_cleanup(&sd->entity);
+mutex_remove:
+ mutex_destroy(&sensor->lock);
+ return ret;
+}
+
+/**
+ * @short Exit routine - Exit point of the driver
+ * @param[in] client pointer to the i2c client structure
+ * @return 0 on success and a negative number on failure
+ */
+static int ov5647_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5647 *ov5647 = to_state(sd);
+
+ v4l2_async_unregister_subdev(&ov5647->sd);
+ media_entity_cleanup(&ov5647->sd.entity);
+ v4l2_device_unregister_subdev(sd);
+ mutex_destroy(&ov5647->lock);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov5647_id[] = {
+ { "ov5647", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5647_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov5647_of_match[] = {
+ { .compatible = "ovti,ov5647" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov5647_of_match);
+#endif
+
+/**
+ * @short i2c driver structure
+ */
+static struct i2c_driver ov5647_driver = {
+ .driver = {
+ .of_match_table = of_match_ptr(ov5647_of_match),
+ .owner = THIS_MODULE,
+ .name = "ov5647",
+ },
+ .probe = ov5647_probe,
+ .remove = ov5647_remove,
+ .id_table = ov5647_id,
+};
+
+module_i2c_driver(ov5647_driver);
+
+MODULE_AUTHOR("Ramiro Oliveira <roliveir@synopsys.com>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors");
+MODULE_LICENSE("GPL v2");
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v4 4/4] clk: rockchip: add clock controller for rk3328
From: Heiko Stuebner @ 2016-12-27 14:05 UTC (permalink / raw)
To: Elaine Zhang
Cc: mark.rutland-5wv7dgnIgG8, huangtao-TNX95d0MmH7DzftRWevZcw,
xf-TNX95d0MmH7DzftRWevZcw, mturquette-rdvid1DuHRBWk0Htik3J/w,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ, xxx-TNX95d0MmH7DzftRWevZcw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-clk-u79uwXL29TY76Z2rM5mHXA, cl-TNX95d0MmH7DzftRWevZcw
In-Reply-To: <1482820373-10186-5-git-send-email-zhangqing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Hi Elaine,
Am Dienstag, 27. Dezember 2016, 14:32:53 CET schrieb Elaine Zhang:
> Add the clock tree definition for the new rk3328 SoC.
looks good in general, I have some styling nitpicks below and would like
the grf-clocks solved differently, also explained below:
> diff --git a/drivers/clk/rockchip/clk-rk3328.c
> b/drivers/clk/rockchip/clk-rk3328.c new file mode 100644
> index 000000000000..9958ce7d0dcd
> --- /dev/null
> +++ b/drivers/clk/rockchip/clk-rk3328.c
> +static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
[...]
> + /*
> + * Clock-Architecture Diagram 8
> + */
blank line between two comment blocks please.
Same for similar setups in the code above.
> + /* PD_GMAC */
> +
> + COMPOSITE(ACLK_GMAC, "aclk_gmac", mux_2plls_hdmiphy_p, 0,
> + RK3328_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
> + RK3328_CLKGATE_CON(3), 2, GFLAGS),
> + COMPOSITE_NOMUX(PCLK_GMAC, "pclk_gmac", "aclk_gmac", 0,
> + RK3328_CLKSEL_CON(25), 8, 3, DFLAGS,
> + RK3328_CLKGATE_CON(9), 0, GFLAGS),
> +
> + COMPOSITE(SCLK_MAC2IO_SRC, "clk_mac2io_src", mux_2plls_p, 0,
> + RK3328_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 5, DFLAGS,
> + RK3328_CLKGATE_CON(3), 1, GFLAGS),
> + GATE(SCLK_MAC2IO_REF, "clk_mac2io_ref", "clk_mac2io", 0,
> + RK3328_CLKGATE_CON(9), 7, GFLAGS),
> + GATE(SCLK_MAC2IO_RX, "clk_mac2io_rx", "clk_mac2io", 0,
> + RK3328_CLKGATE_CON(9), 4, GFLAGS),
> + GATE(SCLK_MAC2IO_TX, "clk_mac2io_tx", "clk_mac2io", 0,
> + RK3328_CLKGATE_CON(9), 5, GFLAGS),
> + GATE(SCLK_MAC2IO_REFOUT, "clk_mac2io_refout", "clk_mac2io", 0,
> + RK3328_CLKGATE_CON(9), 6, GFLAGS),
> + COMPOSITE(SCLK_MAC2IO_OUT, "clk_mac2io_out", mux_2plls_p, 0,
> + RK3328_CLKSEL_CON(27), 15, 1, MFLAGS, 8, 5, DFLAGS,
> + RK3328_CLKGATE_CON(3), 5, GFLAGS),
> +
> + COMPOSITE(SCLK_MAC2PHY_SRC, "clk_mac2phy_src", mux_2plls_p, 0,
> + RK3328_CLKSEL_CON(26), 7, 1, MFLAGS, 0, 5, DFLAGS,
> + RK3328_CLKGATE_CON(3), 0, GFLAGS),
> + GATE(SCLK_MAC2PHY_REF, "clk_mac2phy_ref", "clk_mac2phy", 0,
> + RK3328_CLKGATE_CON(9), 3, GFLAGS),
> + GATE(SCLK_MAC2PHY_RXTX, "clk_mac2phy_rxtx", "clk_mac2phy", 0,
> + RK3328_CLKGATE_CON(9), 1, GFLAGS),
> + COMPOSITE_NOMUX(SCLK_MAC2PHY_OUT, "clk_mac2phy_out", "clk_mac2phy", 0,
> + RK3328_CLKSEL_CON(26), 8, 2, DFLAGS,
> + RK3328_CLKGATE_CON(9), 2, GFLAGS),
Please look at the other clock drivers for indentation. I.e. don't align with
the "(", but instead use the same indent everywhere.
This makes things like the register address always sit in the same position
and thus makes it easier to read the clock diagram.
> + FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
> +
> + /*
> + * Clock-Architecture Diagram 9
> + */
> +
For the following long list of gates, just make it one line per gate and do
not line-break them ... see other clock drivers for reference.
This long gate list is very uniform (= only gates) and reducing the number
of lines needed makes it easier to parse for those.
> + /* PD_VOP */
> + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0,
> + RK3328_CLKGATE_CON(21), 10, GFLAGS),
> + GATE(0, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(22), 3, GFLAGS),
> + GATE(ACLK_VOP, "aclk_vop", "aclk_vop_pre", 0,
> + RK3328_CLKGATE_CON(21), 2, GFLAGS),
> + GATE(0, "aclk_vop_niu", "aclk_vop_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(21), 4, GFLAGS),
> +
> + GATE(ACLK_IEP, "aclk_iep", "aclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 6, GFLAGS),
> + GATE(ACLK_CIF, "aclk_cif", "aclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 8, GFLAGS),
> + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 15, GFLAGS),
> + GATE(0, "aclk_vio_niu", "aclk_vio_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(22), 2, GFLAGS),
> +
> + GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 3, GFLAGS),
> + GATE(0, "hclk_vop_niu", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 5, GFLAGS),
> + GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 7, GFLAGS),
> + GATE(HCLK_CIF, "hclk_cif", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 9, GFLAGS),
> + GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(21), 11, GFLAGS),
> + GATE(0, "hclk_ahb1tom", "hclk_vio_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(21), 12, GFLAGS),
> + GATE(0, "pclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(21), 13, GFLAGS),
> + GATE(0, "hclk_vio_h2p", "hclk_vio_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(21), 14, GFLAGS),
> + GATE(HCLK_HDCP, "hclk_hdcp", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(22), 0, GFLAGS),
> + GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(22), 1, GFLAGS),
> + GATE(PCLK_HDMI, "pclk_hdmi", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(22), 4, GFLAGS),
> + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio_pre", 0,
> + RK3328_CLKGATE_CON(22), 5, GFLAGS),
> +
> + /* PD_PERI */
> + GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(19), 11, GFLAGS),
> + GATE(ACLK_USB3OTG, "aclk_usb3otg", "aclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 4, GFLAGS),
> +
> + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 0, GFLAGS),
> + GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 1, GFLAGS),
> + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 2, GFLAGS),
> + GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 15, GFLAGS),
> + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 6, GFLAGS),
> + GATE(HCLK_HOST0_ARB, "hclk_host0_arb", "hclk_peri", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(19), 7, GFLAGS),
> + GATE(HCLK_OTG, "hclk_otg", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 8, GFLAGS),
> + GATE(HCLK_OTG_PMU, "hclk_otg_pmu", "hclk_peri", 0,
> + RK3328_CLKGATE_CON(19), 9, GFLAGS),
> + GATE(0, "hclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(19), 12, GFLAGS),
> + GATE(0, "pclk_peri_niu", "hclk_peri", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(19), 13, GFLAGS),
> +
> + /* PD_GMAC */
> + GATE(ACLK_MAC2PHY, "aclk_mac2phy", "aclk_gmac", 0,
> + RK3328_CLKGATE_CON(26), 0, GFLAGS),
> + GATE(ACLK_MAC2IO, "aclk_mac2io", "aclk_gmac", 0,
> + RK3328_CLKGATE_CON(26), 2, GFLAGS),
> + GATE(0, "aclk_gmac_niu", "aclk_gmac", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(26), 4, GFLAGS),
> + GATE(PCLK_MAC2PHY, "pclk_mac2phy", "pclk_gmac", 0,
> + RK3328_CLKGATE_CON(26), 1, GFLAGS),
> + GATE(PCLK_MAC2IO, "pclk_mac2io", "pclk_gmac", 0,
> + RK3328_CLKGATE_CON(26), 3, GFLAGS),
> + GATE(0, "pclk_gmac_niu", "pclk_gmac", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(26), 5, GFLAGS),
> +
> + /* PD_BUS */
> + GATE(0, "aclk_bus_niu", "aclk_bus_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 12, GFLAGS),
> + GATE(ACLK_DCF, "aclk_dcf", "aclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 11, GFLAGS),
> + GATE(ACLK_TSP, "aclk_tsp", "aclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(17), 12, GFLAGS),
> + GATE(0, "aclk_intmem", "aclk_bus_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 0, GFLAGS),
> + GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_bus_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 1, GFLAGS),
> +
> + GATE(0, "hclk_rom", "hclk_bus_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 2, GFLAGS),
> + GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 3, GFLAGS),
> + GATE(HCLK_I2S1_8CH, "hclk_i2s1_8ch", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 4, GFLAGS),
> + GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 5, GFLAGS),
> + GATE(HCLK_SPDIF_8CH, "hclk_spdif_8ch", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 6, GFLAGS),
> + GATE(HCLK_TSP, "hclk_tsp", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(17), 11, GFLAGS),
> + GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 7, GFLAGS),
> + GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(15), 8, GFLAGS),
> + GATE(0, "hclk_bus_niu", "hclk_bus_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 13, GFLAGS),
> + GATE(HCLK_PDM, "hclk_pdm", "hclk_bus_pre", 0,
> + RK3328_CLKGATE_CON(28), 0, GFLAGS),
> +
> + GATE(0, "pclk_bus_niu", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 14, GFLAGS),
> + GATE(0, "pclk_efuse", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 9, GFLAGS),
> + GATE(0, "pclk_otp", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(28), 4, GFLAGS),
> + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(15), 10, GFLAGS),
> + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 0, GFLAGS),
> + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 1, GFLAGS),
> + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 2, GFLAGS),
> + GATE(PCLK_TIMER, "pclk_timer0", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 3, GFLAGS),
> + GATE(0, "pclk_stimer", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 4, GFLAGS),
> + GATE(PCLK_SPI, "pclk_spi", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 5, GFLAGS),
> + GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 6, GFLAGS),
> + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 7, GFLAGS),
> + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 8, GFLAGS),
> + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 9, GFLAGS),
> + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 10, GFLAGS),
> + GATE(PCLK_UART0, "pclk_uart0", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 11, GFLAGS),
> + GATE(PCLK_UART1, "pclk_uart1", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 12, GFLAGS),
> + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 13, GFLAGS),
> + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 14, GFLAGS),
> + GATE(PCLK_DCF, "pclk_dcf", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(16), 15, GFLAGS),
> + GATE(PCLK_GRF, "pclk_grf", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 0, GFLAGS),
> + GATE(0, "pclk_cru", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 4, GFLAGS),
> + GATE(0, "pclk_sgrf", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 6, GFLAGS),
> + GATE(0, "pclk_sim", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 10, GFLAGS),
> + GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus", 0,
> + RK3328_CLKGATE_CON(17), 15, GFLAGS),
> + GATE(0, "pclk_pmu", "pclk_bus", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(28), 3, GFLAGS),
> +
> + GATE(PCLK_USB3PHY_OTG, "pclk_usb3phy_otg", "pclk_phy_pre", 0,
> + RK3328_CLKGATE_CON(28), 1, GFLAGS),
> + GATE(PCLK_USB3PHY_PIPE, "pclk_usb3phy_pipe", "pclk_phy_pre", 0,
> + RK3328_CLKGATE_CON(28), 2, GFLAGS),
> + GATE(PCLK_USB3_GRF, "pclk_usb3_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 2, GFLAGS),
> + GATE(PCLK_USB2_GRF, "pclk_usb2_grf", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 14, GFLAGS),
> + GATE(0, "pclk_ddrphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 13, GFLAGS),
> + GATE(0, "pclk_acodecphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 5, GFLAGS),
> + GATE(PCLK_HDMIPHY, "pclk_hdmiphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 7, GFLAGS),
> + GATE(0, "pclk_vdacphy", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(17), 8, GFLAGS),
> + GATE(0, "pclk_phy_niu", "pclk_phy_pre", CLK_IGNORE_UNUSED,
> + RK3328_CLKGATE_CON(15), 15, GFLAGS),
> +static void __init rk3328_clk_init(struct device_node *np)
> +{
> + struct rockchip_clk_provider *ctx;
> + void __iomem *reg_base;
> +
> + reg_base = of_iomap(np, 0);
> + if (!reg_base) {
> + pr_err("%s: could not map cru region\n", __func__);
> + return;
> + }
> +
> + rk3328_cru_base = reg_base;
> +
> + ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
> + if (IS_ERR(ctx)) {
> + pr_err("%s: rockchip clk init failed\n", __func__);
> + iounmap(reg_base);
> + return;
> + }
> +
> + rockchip_clk_register_plls(ctx, rk3328_pll_clks,
> + ARRAY_SIZE(rk3328_pll_clks),
> + RK3328_GRF_SOC_STATUS0);
> + rockchip_clk_register_branches(ctx, rk3328_clk_branches,
> + ARRAY_SIZE(rk3328_clk_branches));
> + rockchip_clk_protect_critical(rk3328_critical_clocks,
> + ARRAY_SIZE(rk3328_critical_clocks));
> +
> + rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
> + mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
> + &rk3328_cpuclk_data, rk3328_cpuclk_rates,
> + ARRAY_SIZE(rk3328_cpuclk_rates));
> +
> + rockchip_register_softrst(np, 11, reg_base + RK3328_SOFTRST_CON(0),
> + ROCKCHIP_SOFTRST_HIWORD_MASK);
> +
> + rockchip_register_restart_notifier(ctx, RK3328_GLB_SRST_FST, NULL);
> +
> + rockchip_clk_of_add_provider(np, ctx);
> +
> + atomic_notifier_chain_register(&panic_notifier_list,
> + &rk3328_clk_panic_block);
please drop this notifier and asorted code above for dumping cru registers.
> +}
> +
> +CLK_OF_DECLARE(rk3328_cru, "rockchip,rk3328-cru", rk3328_clk_init);
> +
> +static void __init rk3328_grf_clk_init(struct device_node *np)
> +{
> + struct rockchip_clk_provider *ctx;
> + void __iomem *reg_base;
> +
> + reg_base = of_iomap(np, 0);
> + if (!reg_base) {
> + pr_err("%s: could not map cru pmu region\n", __func__);
> + return;
> + }
> +
> + ctx = rockchip_clk_init(np, reg_base, CLKGRF_NR_CLKS);
> + if (IS_ERR(ctx)) {
> + pr_err("%s: rockchip pmu clk init failed\n", __func__);
> + return;
> + }
> +
> + rockchip_clk_register_branches(ctx, rk3328_clk_grf_branches,
> + ARRAY_SIZE(rk3328_clk_grf_branches));
> +
> + rockchip_clk_of_add_provider(np, ctx);
> +}
We definitly don't want to bind against the regular GRF node. This causes a
double mapping of the region and in general this isn't the clock-controller
and just contains 2 clocks controls that somehow ended up in the GRF :-) .
Instead please take a look at the muxgrf clock patches I Cc'ed you on some
minutes ago.
> +CLK_OF_DECLARE(rk3328_cru_grf, "rockchip,rk3328-grf", rk3328_grf_clk_init);
> diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index
> 06acb7e0911f..7225997f8d52 100644
> --- a/drivers/clk/rockchip/clk.h
> +++ b/drivers/clk/rockchip/clk.h
> @@ -91,6 +91,28 @@
> #define RK3288_EMMC_CON0 0x218
> #define RK3288_EMMC_CON1 0x21c
>
> +#define RK3328_PLL_CON(x) RK2928_PLL_CON(x)
> +#define RK3328_CLKSEL_CON(x) ((x) * 0x4 + 0x100)
> +#define RK3328_CLKGATE_CON(x) ((x) * 0x4 + 0x200)
> +#define RK3328_GRFCLKSEL_CON(x) ((x) * 0x4 + 0x100)
> +#define RK3328_GLB_SRST_FST 0x9c
> +#define RK3328_GLB_SRST_SND 0x98
> +#define RK3328_SOFTRST_CON(x) ((x) * 0x4 + 0x300)
> +#define RK3328_MODE_CON 0x80
> +#define RK3328_MISC_CON 0x84
-----
> +#define RK3328_DIV_ACLKM_MASK 0x7
> +#define RK3328_DIV_ACLKM_SHIFT 4
> +#define RK3328_DIV_PCLK_DBG_MASK 0xf
> +#define RK3328_DIV_PCLK_DBG_SHIFT 0
-----
please move these to the armclk defintion in the controller driver
where already the other definitions are
Thanks
Heiko
^ permalink raw reply
* Re: [PATCH v3 3/3] nfc: trf7970a: Prevent repeated polling from crashing the kernel
From: Geoff Lansberry @ 2016-12-27 14:18 UTC (permalink / raw)
To: Mark Greer
Cc: linux-wireless, Lauro Ramos Venancio, Aloisio Almeida Jr,
Samuel Ortiz, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, netdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Justin Bronder, Jaret Cantu
In-Reply-To: <20161224172439.GA15103-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
Mark - I will split this off soon.
In the meantime - here is some more info about how we use it.
We do use NFC structures. I did find an interesting clue in that
there are certain bottles that cause neard to segfault, I'm not sure
what is different about them. We write a string, like
"coppola_chardonnay_2015" to the bottles. Come to think of it, I
haven't done anything special to make that an ndef record, just
assumed that it would happen by default, I'll look into this further.
Also, I've been running neard with --plugin nfctype2. Just in case
the problem was happening due to cycling through other tag types. It
didn't seem to make any difference, but I have not gone back to
default.
Geoff
Geoff Lansberry
Engineering Guy
Kuvée, Inc
125 Kingston St., 3rd Floor
Boston, MA 02111
1-617-290-1118 (m)
geoff.lansberry (skype)
http://www.kuvee.com
On Sat, Dec 24, 2016 at 12:24 PM, Mark Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org> wrote:
> On Sat, Dec 24, 2016 at 11:17:18AM -0500, Geoff Lansberry wrote:
>> Mark - I'm sorry, but I did not write this code, and therefore was not
>> able to accurately describe it. It is fixing a different issue, not
>> the neard segfault that we are still chasing. Last week Jaret Cantu
>> sent a separate email explaining the purpose of the code, which had
>> you copied, did you see that?
>
> Hm, no, I didn't. I received an email from Justin Bronder but not from
> Jaret Cantu. Justin's email did help but is still pretty high-level.
> We need a clear understanding as to what is happening in the digital
> layer and the driver to know how execution is getting into a block of
> error handling code that should never be executed. Once we understand
> that we can start thinking about what the best fix is.
>
>> Does it explain why it was done to
>> your satisfaction? I've asked him to join in on the effort to push
>> the change upstream, however he will not be available until the new
>> year.
>
> I expect that it would help if he joins. After the holidays is fine -
> I think many people are taking it easy for the next week or so, anyway.
>
>> I know you did suggest that we split off that change from the others,
>> and if now is the time to do that, let me know. If you don't have
>> the email from Jaret, also please let me know and I will forward it to
>> you.
>
> I think it would help you if you split it off because the first two patches
> have a good chance of being accepted but this one doesn't (yet). If you
> separate the them, it will make it easier for Samuel to take the first two
> (or he may take the first two anyway but its always good to make it as
> easy maintainers as you can).
>
> Mark
> --
^ permalink raw reply
* Re: [PATCH 7/9] pinctrl: samsung: Add property to mark pad state as suitable for power down
From: Krzysztof Kozlowski @ 2016-12-27 15:33 UTC (permalink / raw)
To: Marek Szyprowski
Cc: Krzysztof Kozlowski, linux-gpio, linux-arm-kernel, linux-pm,
linux-samsung-soc, Sylwester Nawrocki, Linus Walleij, Tomasz Figa,
Ulf Hansson, Bartlomiej Zolnierkiewicz, devicetree
In-Reply-To: <bd48fe32-5296-fc23-dbb8-d212292d76cd@samsung.com>
On Tue, Dec 27, 2016 at 11:30:57AM +0100, Marek Szyprowski wrote:
> Hi Krzysztof,
>
>
> On 2016-12-25 20:19, Krzysztof Kozlowski wrote:
> > On Fri, Dec 23, 2016 at 01:24:47PM +0100, Marek Szyprowski wrote:
> > > Add support for special property "samsung,off-state", which indicates a special
> > > state suitable for device's "sleep" state. Its pin values/properties should
> > > match the configuration in power down mode. It indicates that pin controller
> > > can notify runtime power management subsystem, that it is ready for runtime
> > > suspend if its all pins are configured for such state. This in turn might
> > > allow to turn respective power domain off to reduce power consumption.
> > >
> > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > > ---
> > > Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt | 8 ++++++++
> > > drivers/pinctrl/samsung/pinctrl-samsung.c | 4 ++++
> > > drivers/pinctrl/samsung/pinctrl-samsung.h | 1 +
> > > 3 files changed, 13 insertions(+)
> > >
> > > diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
> > > index b7bd2e12a269..354eea0e7798 100644
> > > --- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
> > > +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
> > > @@ -105,6 +105,7 @@ Required Properties:
> > > - samsung,pin-drv: Drive strength configuration.
> > > - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
> > > - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
> > > + - samsung,off-state: Mark this configuration as suitable for bank power off.
> > > The values specified by these config properties should be derived from the
> > > hardware manual and these values are programmed as-is into the pin
> > > @@ -113,6 +114,13 @@ Required Properties:
> > > Note: A child should include atleast a pin function selection property or
> > > pin configuration property (one or more) or both.
> > > + Note: Special property "samsung,off-state" indicates that this state can
> > > + be used for device's "sleep" pins state. Its pin values/properties should
> > > + match the configuration in power down mode.
> > Why power down values cannot be used for sleep state? Why you need
> > separate pin control state? If pins values should match power down
> > configuration, then they could just be added to default state, couldn't
> > they?
>
> Separate sleep state is needed because of the pin control bindings and
> design.
>
> A separate sleep state is required to let pin control client driver (in this
> case
> Exynos I2S driver) let to choose when it is okay to switch pads into sleep
> state and I see no other way to achieve this.
Maybe the pinctrl API should be extended for this? Doing this in DTS
just for purpose of passing information between drivers (consumer and
provider) looks odd.
Anyway, you are proposing a new binding so please Cc devicetree mailing
list and device tree maintainers.
> > In the patch 2/9, existing configuration:
> > 716 i2s0_bus: i2s0-bus {
> > (...)
> > 719 samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
> > 720 samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> > 721 samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
> > 722 };
> >
> > additional configuration:
> > + i2s0_bus_slp: i2s0-bus-slp {
> > + samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
> > + samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
> > + samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
> > + samsung,pin-con-pdn = <EXYNOS_PIN_PDN_INPUT>;
> > + samsung,pin-pud-pdn = <EXYNOS_PIN_PULL_NONE>;
> > + samsung,off-state;
> > + };
>
> I agree that it would be possible to get rid of "samsung,off-state" property
> and
> just detect off state when func/pud pair matches power down func/pud.
>
> > > It indicates that pin control
> > > + can notify runtime power management subsystem, that it is ready for runtime
> > > + suspend if its all pins are configured for such state. This in turn might
> > > + allow to turn respective power domain off to reduce power consumption.
> > What do you mean by "notifying RPM subsystem"? Either this is
> > description of hardware in certain mode (sleep state) or this is not
> > device tree property.
>
> Maybe I wrote the description with a view too limited to the kernel
> operation
> perspective, but if we remove the need to mark state as off, the above
> description
> will not be needed.
But still it wouldn't be describing any hardware property, would it?
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH] ARM, ARM64: dts: drop "arm, amba-bus" in favor of "simple-bus" part 3
From: Masahiro Yamada @ 2016-12-27 15:51 UTC (permalink / raw)
To: arm
Cc: David Brown, Rob Herring, linux-samsung-soc, Rob Herring,
Arnd Bergmann, devicetree, linux-arm-msm, Will Deacon,
linux-kernel, Krzysztof Kozlowski, Russell King, Masahiro Yamada,
Kukjin Kim, linux-arm-kernel, Catalin Marinas, Olof Johansson,
Mark Rutland, Andy Gross, linux-soc, Javier Martinez Canillas
Tree-wide replacement was done by commit 2ef7d5f342c1 ("ARM, ARM64:
dts: drop "arm,amba-bus" in favor of "simple-bus"), then the 2nd
round by commit 15b7cc78f095 ("arm64: dts: drop "arm,amba-bus" in
favor of "simple-bus" part 2").
Here, some new users have appeared for Linux v4.10-rc1. Eliminate
them now.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
Hi Arnd, Olof,
Can you pick this up for v4.10 fixes?
If we carry arm,amba-bus until the release, we will need to
take more time to deprecate it.
arch/arm/boot/dts/qcom-mdm9615.dtsi | 2 +-
arch/arm64/boot/dts/exynos/exynos5433.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom-mdm9615.dtsi
index 5ae4ec5..c852b69 100644
--- a/arch/arm/boot/dts/qcom-mdm9615.dtsi
+++ b/arch/arm/boot/dts/qcom-mdm9615.dtsi
@@ -357,7 +357,7 @@
};
amba {
- compatible = "arm,amba-bus";
+ compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
index 64226d5..135890c 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
@@ -1367,7 +1367,7 @@
};
amba {
- compatible = "arm,amba-bus";
+ compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
--
2.7.4
^ permalink raw reply related
* Re: [RFC PATCH 3/6] ARM64: dts: exynos5433: add the pcie_phy node for PCIe
From: Krzysztof Kozlowski @ 2016-12-27 16:11 UTC (permalink / raw)
To: Jaehoon Chung
Cc: linux-pci, devicetree, linux-kernel, linux-samsung-soc, bhelgaas,
robh+dt, mark.rutland, kgene, krzk, javier, kishon, will.deacon,
catalin.marinas, cpgs
In-Reply-To: <20161226052029.10552-4-jh80.chung@samsung.com>
On Mon, Dec 26, 2016 at 02:20:26PM +0900, Jaehoon Chung wrote:
> To use the generic PHY framework, adds the pcie_phy node.
>
> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
> arch/arm64/boot/dts/exynos/exynos5433.dtsi | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> index 64226d5..2a15f18 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> @@ -805,6 +805,11 @@
> reg = <0x145f0000 0x1038>;
> };
>
> + syscon_fsys: syscon@156f0000 {
> + compatible = "syscon";
> + reg = <0x156f0000 0x1044>;
> + };
> +
> gsc_0: video-scaler@13C00000 {
> compatible = "samsung,exynos5433-gsc";
> reg = <0x13c00000 0x1000>;
> @@ -1443,6 +1448,15 @@
> status = "disabled";
> };
> };
> +
> + pcie_phy: pcie-phy@15680000 {
> + #phy-cells = <0>;
> + compatible = "samsung,exynos5433-pcie-phy";
Mostly we use the convention of compatible being first property.
> + reg = <0x15680000 0x1000>;
> + samsung,pmureg-phandle = <&pmu_system_controller>;
> + samsung,fsys-sysreg = <&syscon_fsys>;
> + status = "okay";
Why do you need to put status=okay here?
Best regards,
Krzysztof
> + };
> };
>
> timer: timer {
> --
> 2.10.2
>
^ permalink raw reply
* Re: [RFC PATCH 5/6] Documentation: pci: add the exynos5433-pcie binding
From: Krzysztof Kozlowski @ 2016-12-27 16:19 UTC (permalink / raw)
To: Jaehoon Chung
Cc: linux-pci, devicetree, linux-kernel, linux-samsung-soc, bhelgaas,
robh+dt, mark.rutland, kgene, krzk, javier, kishon, will.deacon,
catalin.marinas, cpgs
In-Reply-To: <20161226052029.10552-6-jh80.chung@samsung.com>
On Mon, Dec 26, 2016 at 02:20:28PM +0900, Jaehoon Chung wrote:
> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
> .../devicetree/bindings/pci/exynos5433-pcie.txt | 36 ++++++++++++++++++++++
> 1 file changed, 36 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/exynos5433-pcie.txt
>
> diff --git a/Documentation/devicetree/bindings/pci/exynos5433-pcie.txt b/Documentation/devicetree/bindings/pci/exynos5433-pcie.txt
> new file mode 100644
> index 0000000..932a847
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/exynos5433-pcie.txt
> @@ -0,0 +1,36 @@
> +* Samsung Exynos5433 PCIe interface
> +
> +This PCIe host controller is based on the Synopsis Designware PCIe IP
Synopsys.
> +and thus inherits all the common properties defined in designware-pcie.txt.
> +
> +Required properties:
> +- compatible: "samsung,exynos5433-pcie"
> +- reg: base addresses and lengths of the pcie controller,
> + the phy controller, additional register for the phy controller.
You mentioned three regs but the example contains four of them. Is the
config comming from snps,dw-pcie?
> +- reg-names: Must be "elbi", "phy" and "dbi" for each regs
Again, three here, four in example.
> +- interrupt-names: Must be "intr" for legacy interrupt pin.
> +
> +Other common properites refer to
> + Documentation/devicetree/binding/pci/designware-pcie.txt
> +
> +Example:
> +
> + pcie: pcie@15700000 {
> + compatible ="samsung,exynos5433-pcie", "snps,dw-pcie";
^
space needed
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "intr";
> + clocks = <&cmu_fsys CLK_PCIE>, <&cmu_fsys CLK_PCLK_PCIE_PHY>;
> + clock-names = "pcie", "pcie_bus";
> + num-lanes = <1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pcie_bus>;
> + reg = <0x156b0000 0x1000>, <0x15680000 0x1000>,
> + <0x15700000 0x1000>, <0x0c000000 0x1000>;
Indentation here looks wrong. You indented it with spaces after tabs...
but not to align with line before.
Beside that, fine with me:
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Best regards,
Krzysztof
> + reg-names = "elbi", "phy", "dbi", "config";
> + ranges = <0x81000000 0 0 0x0c001000 0 0x00010000
> + 0x82000000 0 0x0c011000 0x0c011000 0 0x3feefff>;
> + status = "disabled";
> + };
> --
> 2.10.2
>
^ permalink raw reply
* Re: [RFC PATCH 6/6] ARM64: exynos: add the pcie node for TM2
From: Krzysztof Kozlowski @ 2016-12-27 16:32 UTC (permalink / raw)
To: Jaehoon Chung
Cc: linux-pci, devicetree, linux-kernel, linux-samsung-soc, bhelgaas,
robh+dt, mark.rutland, kgene, krzk, javier, kishon, will.deacon,
catalin.marinas, cpgs
In-Reply-To: <20161226052029.10552-7-jh80.chung@samsung.com>
On Mon, Dec 26, 2016 at 02:20:29PM +0900, Jaehoon Chung wrote:
> Add the Exxynos5433 pcie node for TM2.
> This pcie device is used for supporting WiFi.
>
> And some gpios are already requested from pinctrl. so it doesn't need to
> initialize.
> GPJ2-0 is used for supplying to WiFi PCIe chip.
>
> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
> arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi | 7 +++++++
> arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 11 +++++++++--
> arch/arm64/boot/dts/exynos/exynos5433.dtsi | 23 ++++++++++++++++++++++
> 3 files changed, 39 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi
> index ad71247..3e8b728 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi
> +++ b/arch/arm64/boot/dts/exynos/exynos5433-pinctrl.dtsi
> @@ -183,6 +183,13 @@
> interrupt-controller;
> #interrupt-cells = <2>;
> };
> +
> + pcie_wlanen: pcie-wlanen {
> + samsung,pins = "gpj2-0";
> + samsung,pin-function = <0>;
> + samsung,pin-pud = <3>;
> + samsung,pin-drv = <3>;
> + };
> };
>
> &pinctrl_finger {
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> index f21bdc2..c84a2ad 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> @@ -737,6 +737,15 @@
> bus-width = <4>;
> };
>
> +&pcie {
> + assigned-clocks = <&cmu_fsys CLK_MOUT_SCLK_PCIE_100_USER>,
> + <&cmu_top CLK_MOUT_SCLK_PCIE_100>;
> + assigned-clock-parents = <&cmu_top CLK_SCLK_PCIE_100_FSYS>,
> + <&cmu_top CLK_MOUT_BUS_PLL_USER>;
> + assigned-clock-rates = <0>, <100000000>;
> + status = "okay";
> +};
> +
> &pinctrl_alive {
> pinctrl-names = "default";
> pinctrl-0 = <&initial_alive>;
> @@ -836,7 +845,6 @@
> pinctrl-0 = <&initial_ese>;
>
> initial_ese: initial-state {
> - PIN(IN, gpj2-0, DOWN, LV1);
> PIN(IN, gpj2-1, DOWN, LV1);
> PIN(IN, gpj2-2, DOWN, LV1);
> };
> @@ -851,7 +859,6 @@
> PIN(IN, gpr3-1, DOWN, LV1);
> PIN(IN, gpr3-2, DOWN, LV1);
> PIN(IN, gpr3-3, DOWN, LV1);
> - PIN(IN, gpr3-7, NONE, LV1);
> };
> };
>
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> index 2a15f18..da287f4 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> @@ -1457,6 +1457,29 @@
> samsung,fsys-sysreg = <&syscon_fsys>;
> status = "okay";
> };
> +
> + pcie: pcie@15700000 {
> + compatible = "samsung,exynos5433-pcie", "snps,dw-pcie";
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "intr";
> + clocks = <&cmu_fsys CLK_PCIE>,
> + <&cmu_fsys CLK_PCLK_PCIE_PHY>;
Here and in the 'reg' property - indentation looks weird. Tabs+spaces
but not aligned. Either you use spaces to align... or just don't care
and use tabs. I prefer consistency and below the 'ranges' property is
aligned.
> + clock-names = "pcie", "pcie_bus";
> + num-lanes = <1>;
> + pinctrl-names = "default";
> + phys = <&pcie_phy>;
> + phy-names = "pcie-phy";
> + pinctrl-0 = <&pcie_bus &pcie_wlanen>;
> + reg = <0x156b0000 0x1000>, <0x15700000 0x1000>,
> + <0x0c000000 0x1000>;
> + reg-names = "elbi", "dbi", "config";
This does not match the bindings documentation.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [RFC PATCH 6/6] ARM64: exynos: add the pcie node for TM2
From: Krzysztof Kozlowski @ 2016-12-27 16:33 UTC (permalink / raw)
To: Jaehoon Chung
Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, kgene-DgEjT+Ai2ygdnm+yROfE0A,
Krzysztof Kozlowski, Javier Martinez Canillas, kishon-l0cyMroinI0,
will.deacon-5wv7dgnIgG8, catalin.marinas-5wv7dgnIgG8,
cpgs-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <20161227163200.6noed454fmtgozrv@kozik-lap>
On Tue, Dec 27, 2016 at 6:32 PM, Krzysztof Kozlowski <krzk-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Mon, Dec 26, 2016 at 02:20:29PM +0900, Jaehoon Chung wrote:
>> Add the Exxynos5433 pcie node for TM2.
>> This pcie device is used for supporting WiFi.
>>
>> And some gpios are already requested from pinctrl. so it doesn't need to
>> initialize.
>> GPJ2-0 is used for supplying to WiFi PCIe chip.
>>
>> Signed-off-by: Jaehoon Chung <jh80.chung-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
Ahhh, and one more comment - please add missing 'dts' prefix in the subject.
BR,
Krzysztof
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RESEND PATCH v2] arm64: dts: rockchip: add u2phy clock for ehci and ohci of rk3399
From: Heiko Stuebner @ 2016-12-27 17:04 UTC (permalink / raw)
To: Xing Zheng
Cc: linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
dianders-F7+t8E8rja9g9hUCZPvPmw, wxt-TNX95d0MmH7DzftRWevZcw,
shawn.lin-TNX95d0MmH7DzftRWevZcw,
briannorris-F7+t8E8rja9g9hUCZPvPmw, jay.xu-TNX95d0MmH7DzftRWevZcw,
zhangqing-TNX95d0MmH7DzftRWevZcw, david.wu-TNX95d0MmH7DzftRWevZcw,
wulf-TNX95d0MmH7DzftRWevZcw, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dianders-hpIqsD4AKlfQT0dZR+AlfA,
frank.wang-TNX95d0MmH7DzftRWevZcw
In-Reply-To: <1482316865-2769-1-git-send-email-zhengxing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Am Mittwoch, 21. Dezember 2016, 18:41:05 CET schrieb Xing Zheng:
> From: William wu <wulf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>
> We found that the suspend process was blocked when it run into
> ehci/ohci module due to clk-480m of usb2-phy was disabled.
>
> The root cause is that usb2-phy suspended earlier than ehci/ohci
> (usb2-phy will be auto suspended if no devices plug-in). and the
> clk-480m provided by it was disabled if no module used. However,
> some suspend process related ehci/ohci are base on this clock,
> so we should refer it into ehci/ohci driver to prevent this case.
>
> The u2phy clock flow like this:
> ===
> u2phy ________________
>
> | | |-----> UTMI_CLK ---------> | EHCI |
>
> OSC_24M ---|---> PHY_PLL----|----|
>
> |________^_______| |-----> 480M_CLK ---|G|---> |
> |USBPHY_480M_SRC| ----> USBPHY_480M for SoC
> GRF
> ===
>
> Signed-off-by: William wu <wulf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> Signed-off-by: Xing Zheng <zhengxing-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
applied for 4.11 with Doug's Review-tag
Thanks
Heiko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCHv2 0/5] Add generic pinctrl helpers for managing groups and function
From: Tony Lindgren @ 2016-12-27 17:19 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA
Hi all,
Here are some changes to add generic helpers for managing pinctrl groups and
functions.
Regards,
Tony
Changes since v1:
- Updates to the first patch in the series to use delayed work for pinctrl
hogs based on what was discussed on the mailing list, mostly to pass
pctldev to the parsers and add pinctrl_dt_has_hogs() check
Tony Lindgren (5):
pinctrl: core: Use delayed work for hogs
pinctrl: core: Add generic pinctrl functions for managing groups
pinctrl: core: Add generic pinctrl functions for managing groups
pinctrl: single: Use generic pinctrl helpers for managing groups
pinctrl: single: Use generic pinmux helpers for managing functions
drivers/pinctrl/Kconfig | 11 +-
drivers/pinctrl/core.c | 270 +++++++++++++++++++++++++++++++-----
drivers/pinctrl/core.h | 67 +++++++++
drivers/pinctrl/devicetree.c | 28 +++-
drivers/pinctrl/devicetree.h | 12 +-
drivers/pinctrl/pinctrl-single.c | 290 ++++-----------------------------------
drivers/pinctrl/pinmux.c | 173 +++++++++++++++++++++++
drivers/pinctrl/pinmux.h | 42 ++++++
8 files changed, 591 insertions(+), 302 deletions(-)
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/5] pinctrl: core: Use delayed work for hogs
From: Tony Lindgren @ 2016-12-27 17:19 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio, devicetree, linux-kernel, linux-omap
In-Reply-To: <20161227172003.6517-1-tony@atomide.com>
Having the pin control framework call pin controller functions
before it's probe has finished is not nice as the pin controller
device driver does not yet have struct pinctrl_dev handle.
Let's fix this issue by adding deferred work for late init. This is
needed to be able to add pinctrl generic helper functions that expect
to know struct pinctrl_dev handle. Note that we now need to call
create_pinctrl() directly as we don't want to add the pin controller
to the list of controllers until the hogs are claimed. We also need
to pass the pinctrl_dev to the device tree parser functions as they
otherwise won't find the right controller at this point.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/pinctrl/core.c | 90 ++++++++++++++++++++++++++++----------------
drivers/pinctrl/core.h | 2 +
drivers/pinctrl/devicetree.c | 28 +++++++++++---
drivers/pinctrl/devicetree.h | 12 +++++-
4 files changed, 93 insertions(+), 39 deletions(-)
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -720,7 +720,8 @@ static struct pinctrl_state *create_state(struct pinctrl *p,
return state;
}
-static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
+static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
+ struct pinctrl_map const *map)
{
struct pinctrl_state *state;
struct pinctrl_setting *setting;
@@ -744,7 +745,11 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
setting->type = map->type;
- setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+ if (pctldev)
+ setting->pctldev = pctldev;
+ else
+ setting->pctldev =
+ get_pinctrl_dev_from_devname(map->ctrl_dev_name);
if (setting->pctldev == NULL) {
kfree(setting);
/* Do not defer probing of hogs (circular loop) */
@@ -800,7 +805,8 @@ static struct pinctrl *find_pinctrl(struct device *dev)
static void pinctrl_free(struct pinctrl *p, bool inlist);
-static struct pinctrl *create_pinctrl(struct device *dev)
+static struct pinctrl *create_pinctrl(struct device *dev,
+ struct pinctrl_dev *pctldev)
{
struct pinctrl *p;
const char *devname;
@@ -823,7 +829,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
- ret = pinctrl_dt_to_map(p);
+ ret = pinctrl_dt_to_map(p, pctldev);
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
@@ -838,7 +844,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
if (strcmp(map->dev_name, devname))
continue;
- ret = add_setting(p, map);
+ ret = add_setting(p, pctldev, map);
/*
* At this point the adding of a setting may:
*
@@ -899,7 +905,7 @@ struct pinctrl *pinctrl_get(struct device *dev)
return p;
}
- return create_pinctrl(dev);
+ return create_pinctrl(dev, NULL);
}
EXPORT_SYMBOL_GPL(pinctrl_get);
@@ -1738,6 +1744,46 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
}
/**
+ * pinctrl_late_init() - finish pin controller device registration
+ * @work: work struct
+ */
+static void pinctrl_late_init(struct work_struct *work)
+{
+ struct pinctrl_dev *pctldev;
+
+ pctldev = container_of(work, struct pinctrl_dev, late_init.work);
+
+ pctldev->p = create_pinctrl(pctldev->dev, pctldev);
+ if (!IS_ERR(pctldev->p)) {
+ kref_get(&pctldev->p->users);
+ pctldev->hog_default =
+ pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(pctldev->hog_default)) {
+ dev_dbg(pctldev->dev,
+ "failed to lookup the default state\n");
+ } else {
+ if (pinctrl_select_state(pctldev->p,
+ pctldev->hog_default))
+ dev_err(pctldev->dev,
+ "failed to select default state\n");
+ }
+
+ pctldev->hog_sleep =
+ pinctrl_lookup_state(pctldev->p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(pctldev->hog_sleep))
+ dev_dbg(pctldev->dev,
+ "failed to lookup the sleep state\n");
+ }
+
+ mutex_lock(&pinctrldev_list_mutex);
+ list_add_tail(&pctldev->node, &pinctrldev_list);
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ pinctrl_init_device_debugfs(pctldev);
+}
+
+/**
* pinctrl_register() - register a pin controller device
* @pctldesc: descriptor for this pin controller
* @dev: parent device for this pin controller
@@ -1766,6 +1812,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
+ INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
pctldev->dev = dev;
mutex_init(&pctldev->mutex);
@@ -1800,32 +1847,10 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
goto out_err;
}
- mutex_lock(&pinctrldev_list_mutex);
- list_add_tail(&pctldev->node, &pinctrldev_list);
- mutex_unlock(&pinctrldev_list_mutex);
-
- pctldev->p = pinctrl_get(pctldev->dev);
-
- if (!IS_ERR(pctldev->p)) {
- pctldev->hog_default =
- pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
- if (IS_ERR(pctldev->hog_default)) {
- dev_dbg(dev, "failed to lookup the default state\n");
- } else {
- if (pinctrl_select_state(pctldev->p,
- pctldev->hog_default))
- dev_err(dev,
- "failed to select default state\n");
- }
-
- pctldev->hog_sleep =
- pinctrl_lookup_state(pctldev->p,
- PINCTRL_STATE_SLEEP);
- if (IS_ERR(pctldev->hog_sleep))
- dev_dbg(dev, "failed to lookup the sleep state\n");
- }
-
- pinctrl_init_device_debugfs(pctldev);
+ if (pinctrl_dt_has_hogs(pctldev))
+ schedule_delayed_work(&pctldev->late_init, 0);
+ else
+ pinctrl_late_init(&pctldev->late_init.work);
return pctldev;
@@ -1848,6 +1873,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
if (pctldev == NULL)
return;
+ cancel_delayed_work_sync(&pctldev->late_init);
mutex_lock(&pctldev->mutex);
pinctrl_remove_device_debugfs(pctldev);
mutex_unlock(&pctldev->mutex);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -33,6 +33,7 @@ struct pinctrl_gpio_range;
* @p: result of pinctrl_get() for this device
* @hog_default: default state for pins hogged by this device
* @hog_sleep: sleep state for pins hogged by this device
+ * @late_init: delayed work for pin controller to finish registration
* @mutex: mutex taken on each pin controller specific action
* @device_root: debugfs root for this device
*/
@@ -47,6 +48,7 @@ struct pinctrl_dev {
struct pinctrl *p;
struct pinctrl_state *hog_default;
struct pinctrl_state *hog_sleep;
+ struct delayed_work late_init;
struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -100,11 +100,12 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
return get_pinctrl_dev_from_of_node(np);
}
-static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
+static int dt_to_map_one_config(struct pinctrl *p,
+ struct pinctrl_dev *pctldev,
+ const char *statename,
struct device_node *np_config)
{
struct device_node *np_pctldev;
- struct pinctrl_dev *pctldev;
const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
@@ -121,7 +122,8 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
/* OK let's just assume this will appear later then */
return -EPROBE_DEFER;
}
- pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
+ if (!pctldev)
+ pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
break;
/* Do not defer probing of hogs (circular loop) */
@@ -166,7 +168,22 @@ static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
return dt_remember_or_free_map(p, statename, NULL, map, 1);
}
-int pinctrl_dt_to_map(struct pinctrl *p)
+bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev)
+{
+ struct device_node *np;
+ struct property *prop;
+ int size;
+
+ np = pctldev->dev->of_node;
+ if (!np)
+ return false;
+
+ prop = of_find_property(np, "pinctrl-0", &size);
+
+ return prop ? true : false;
+}
+
+int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{
struct device_node *np = p->dev->of_node;
int state, ret;
@@ -233,7 +250,8 @@ int pinctrl_dt_to_map(struct pinctrl *p)
}
/* Parse the node */
- ret = dt_to_map_one_config(p, statename, np_config);
+ ret = dt_to_map_one_config(p, pctldev, statename,
+ np_config);
of_node_put(np_config);
if (ret < 0)
goto err;
diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
--- a/drivers/pinctrl/devicetree.h
+++ b/drivers/pinctrl/devicetree.h
@@ -20,8 +20,10 @@ struct of_phandle_args;
#ifdef CONFIG_OF
+bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev);
+
void pinctrl_dt_free_maps(struct pinctrl *p);
-int pinctrl_dt_to_map(struct pinctrl *p);
+int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev);
int pinctrl_count_index_with_args(const struct device_node *np,
const char *list_name);
@@ -32,7 +34,13 @@ int pinctrl_parse_index_with_args(const struct device_node *np,
#else
-static inline int pinctrl_dt_to_map(struct pinctrl *p)
+static inline bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev)
+{
+ return false;
+}
+
+static inline int pinctrl_dt_to_map(struct pinctrl *p,
+ struct pinctrl_dev *pctldev)
{
return 0;
}
--
2.11.0
^ permalink raw reply
* [PATCH 2/5] pinctrl: core: Add generic pinctrl functions for managing groups
From: Tony Lindgren @ 2016-12-27 17:20 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161227172003.6517-1-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
We can add generic helpers for pin group handling for cases where the pin
controller driver does not need to use static arrays.
Signed-off-by: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
---
drivers/pinctrl/Kconfig | 3 +
drivers/pinctrl/core.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/pinctrl/core.h | 47 +++++++++++++
3 files changed, 228 insertions(+)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -8,6 +8,9 @@ config PINCTRL
menu "Pin controllers"
depends on PINCTRL
+config GENERIC_PINCTRL
+ bool
+
config PINMUX
bool "Support pin multiplexing controllers" if COMPILE_TEST
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -540,6 +540,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
}
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+#ifdef CONFIG_GENERIC_PINCTRL
+
+/**
+ * pinctrl_generic_get_group_count() - returns the number of pin groups
+ * @pctldev: pin controller device
+ */
+int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev)
+{
+ return pctldev->num_groups;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_count);
+
+/**
+ * pinctrl_generic_get_group_name() - returns the name of a pin group
+ * @pctldev: pin controller device
+ * @selector: group number
+ */
+const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct group_desc *group;
+
+ group = radix_tree_lookup(&pctldev->pin_group_tree,
+ selector);
+ if (!group)
+ return NULL;
+
+ return group->name;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_name);
+
+/**
+ * pinctrl_generic_get_group_pins() - gets the pin group pins
+ * @pctldev: pin controller device
+ * @selector: group number
+ * @pins: pins in the group
+ * @num_pins: number of pins in the group
+ */
+int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ struct group_desc *group;
+
+ group = radix_tree_lookup(&pctldev->pin_group_tree,
+ selector);
+ if (!group) {
+ dev_err(pctldev->dev, "%s could not find pingroup%i\n",
+ __func__, selector);
+ return -EINVAL;
+ }
+
+ *pins = group->pins;
+ *num_pins = group->num_pins;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_pins);
+
+/**
+ * pinctrl_generic_get_group() - returns a pin group based on the number
+ * @pctldev: pin controller device
+ * @gselector: group number
+ */
+struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct group_desc *group;
+
+ group = radix_tree_lookup(&pctldev->pin_group_tree,
+ selector);
+ if (!group)
+ return NULL;
+
+ return group;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group);
+
+/**
+ * pinctrl_generic_add_group() - adds a new pin group
+ * @pctldev: pin controller device
+ * @name: name of the pin group
+ * @pins: pins in the pin group
+ * @num_pins: number of pins in the pin group
+ * @data: pin controller driver specific data
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
+ int *pins, int num_pins, void *data)
+{
+ struct group_desc *group;
+
+ group = devm_kzalloc(pctldev->dev, sizeof(*group), GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+
+ group->name = name;
+ group->pins = pins;
+ group->num_pins = num_pins;
+ group->data = data;
+
+ radix_tree_insert(&pctldev->pin_group_tree, pctldev->num_groups,
+ group);
+
+ pctldev->num_groups++;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_add_group);
+
+/**
+ * pinctrl_generic_remove_group() - removes a numbered pin group
+ * @pctldev: pin controller device
+ * @selector: group number
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct group_desc *group;
+
+ group = radix_tree_lookup(&pctldev->pin_group_tree,
+ selector);
+ if (!group)
+ return -ENOENT;
+
+ radix_tree_delete(&pctldev->pin_group_tree, selector);
+ devm_kfree(pctldev->dev, group);
+
+ pctldev->num_groups--;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_remove_group);
+
+/**
+ * pinctrl_generic_free_groups() - removes all pin groups
+ * @pctldev: pin controller device
+ *
+ * Note that the caller must take care of locking.
+ */
+static void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev)
+{
+ struct radix_tree_iter iter;
+ struct group_desc *group;
+ unsigned long *indices;
+ void **slot;
+ int i = 0;
+
+ indices = devm_kzalloc(pctldev->dev, sizeof(*indices) *
+ pctldev->num_groups, GFP_KERNEL);
+ if (!indices)
+ return;
+
+ radix_tree_for_each_slot(slot, &pctldev->pin_group_tree, &iter, 0)
+ indices[i++] = iter.index;
+
+ for (i = 0; i < pctldev->num_groups; i++) {
+ group = radix_tree_lookup(&pctldev->pin_group_tree,
+ indices[i]);
+ radix_tree_delete(&pctldev->pin_group_tree, indices[i]);
+ devm_kfree(pctldev->dev, group);
+ }
+
+ pctldev->num_groups = 0;
+}
+
+#else
+static inline void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev)
+{
+}
+#endif /* CONFIG_GENERIC_PINCTRL */
+
/**
* pinctrl_get_group_selector() - returns the group selector for a group
* @pctldev: the pin controller handling the group
@@ -1811,6 +1987,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
+ INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
pctldev->dev = dev;
@@ -1885,6 +2062,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
mutex_lock(&pctldev->mutex);
/* TODO: check that no pinmuxes are still active? */
list_del(&pctldev->node);
+ pinctrl_generic_free_groups(pctldev);
/* Destroy descriptor tree */
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
pctldev->desc->npins);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -24,6 +24,8 @@ struct pinctrl_gpio_range;
* controller
* @pin_desc_tree: each pin descriptor for this pin controller is stored in
* this radix tree
+ * @pin_group_tree: optionally each pin group can be stored in this radix tree
+ * @num_groups: optionally number of groups can be kept here
* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
* ranges are added to this list at runtime
* @dev: the device entry for this pin controller
@@ -41,6 +43,8 @@ struct pinctrl_dev {
struct list_head node;
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
+ struct radix_tree_root pin_group_tree;
+ unsigned int num_groups;
struct list_head gpio_ranges;
struct device *dev;
struct module *owner;
@@ -162,6 +166,20 @@ struct pin_desc {
};
/**
+ * struct group_desc - generic pin group descriptor
+ * @name: name of the pin group
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @data: pin controller driver specific data
+ */
+struct group_desc {
+ const char *name;
+ int *pins;
+ int num_pins;
+ void *data;
+};
+
+/**
* struct pinctrl_maps - a list item containing part of the mapping table
* @node: mapping table list node
* @maps: array of mapping table entries
@@ -173,6 +191,35 @@ struct pinctrl_maps {
unsigned num_maps;
};
+#ifdef CONFIG_GENERIC_PINCTRL
+
+int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev);
+
+const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int group_selector);
+
+int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int group_selector,
+ const unsigned int **pins,
+ unsigned int *npins);
+
+struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
+ unsigned int group_selector);
+
+int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
+ int *gpins, int ngpins, void *data);
+
+int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
+ unsigned int group_selector);
+
+static inline int
+pinctrl_generic_remove_last_group(struct pinctrl_dev *pctldev)
+{
+ return pinctrl_generic_remove_group(pctldev, pctldev->num_groups - 1);
+}
+
+#endif /* CONFIG_GENERIC_PINCTRL */
+
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 3/5] pinctrl: core: Add generic pinctrl functions for managing groups
From: Tony Lindgren @ 2016-12-27 17:20 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio, devicetree, linux-kernel, linux-omap
In-Reply-To: <20161227172003.6517-1-tony@atomide.com>
We can add generic helpers for function handling for cases where the pin
controller driver does not need to use static arrays.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/pinctrl/Kconfig | 4 ++
drivers/pinctrl/core.c | 2 +
drivers/pinctrl/core.h | 18 +++++
drivers/pinctrl/pinmux.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux.h | 42 ++++++++++++
5 files changed, 239 insertions(+)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -14,6 +14,10 @@ config GENERIC_PINCTRL
config PINMUX
bool "Support pin multiplexing controllers" if COMPILE_TEST
+config GENERIC_PINMUX
+ bool
+ select PINMUX
+
config PINCONF
bool "Support pin configuration controllers" if COMPILE_TEST
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -1988,6 +1988,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
+ INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
INIT_DELAYED_WORK(&pctldev->late_init, pinctrl_late_init);
pctldev->dev = dev;
@@ -2062,6 +2063,7 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
mutex_lock(&pctldev->mutex);
/* TODO: check that no pinmuxes are still active? */
list_del(&pctldev->node);
+ pinmux_generic_free_functions(pctldev);
pinctrl_generic_free_groups(pctldev);
/* Destroy descriptor tree */
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -25,7 +25,9 @@ struct pinctrl_gpio_range;
* @pin_desc_tree: each pin descriptor for this pin controller is stored in
* this radix tree
* @pin_group_tree: optionally each pin group can be stored in this radix tree
+ * @pin_function_tree: optionally each function can be stored in this radix tree
* @num_groups: optionally number of groups can be kept here
+ * @num_functions: optionally number of functions can be kept here
* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
* ranges are added to this list at runtime
* @dev: the device entry for this pin controller
@@ -44,7 +46,9 @@ struct pinctrl_dev {
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
struct radix_tree_root pin_group_tree;
+ struct radix_tree_root pin_function_tree;
unsigned int num_groups;
+ unsigned int num_functions;
struct list_head gpio_ranges;
struct device *dev;
struct module *owner;
@@ -180,6 +184,20 @@ struct group_desc {
};
/**
+ * struct function_desc - generic function descriptor
+ * @name: name of the function
+ * @group_names: array of pin group names
+ * @num_group_names: number of pin group names
+ * @data: pin controller driver specific data
+ */
+struct function_desc {
+ const char *name;
+ const char **group_names;
+ int num_group_names;
+ void *data;
+};
+
+/**
* struct pinctrl_maps - a list item containing part of the mapping table
* @node: mapping table list node
* @maps: array of mapping table entries
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -695,3 +695,176 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
}
#endif /* CONFIG_DEBUG_FS */
+
+#ifdef CONFIG_GENERIC_PINMUX
+
+/**
+ * pinmux_generic_get_function_count() - returns number of functions
+ * @pctldev: pin controller device
+ */
+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev)
+{
+ return pctldev->num_functions;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_count);
+
+/**
+ * pinmux_generic_get_function_name() - returns the function name
+ * @pctldev: pin controller device
+ * @selector: function number
+ */
+const char *
+pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct function_desc *function;
+
+ function = radix_tree_lookup(&pctldev->pin_function_tree,
+ selector);
+ if (!function)
+ return NULL;
+
+ return function->name;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name);
+
+/**
+ * pinmux_generic_get_function_groups() - gets the function groups
+ * @pctldev: pin controller device
+ * @selector: function number
+ * @groups: array of pin groups
+ * @num_groups: number of pin groups
+ */
+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct function_desc *function;
+
+ function = radix_tree_lookup(&pctldev->pin_function_tree,
+ selector);
+ if (!function) {
+ dev_err(pctldev->dev, "%s could not find function%i\n",
+ __func__, selector);
+ return -EINVAL;
+ }
+ *groups = function->group_names;
+ *num_groups = function->num_group_names;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups);
+
+/**
+ * pinmux_generic_get_function() - returns a function based on the number
+ * @pctldev: pin controller device
+ * @group_selector: function number
+ */
+struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct function_desc *function;
+
+ function = radix_tree_lookup(&pctldev->pin_function_tree,
+ selector);
+ if (!function)
+ return NULL;
+
+ return function;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function);
+
+/**
+ * pinmux_generic_get_function_groups() - gets the function groups
+ * @pctldev: pin controller device
+ * @name: name of the function
+ * @groups: array of pin groups
+ * @num_groups: number of pin groups
+ * @data: pin controller driver specific data
+ */
+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
+ const char *name,
+ const char **groups,
+ const unsigned int num_groups,
+ void *data)
+{
+ struct function_desc *function;
+
+ function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL);
+ if (!function)
+ return -ENOMEM;
+
+ function->name = name;
+ function->group_names = groups;
+ function->num_group_names = num_groups;
+ function->data = data;
+
+ radix_tree_insert(&pctldev->pin_function_tree, pctldev->num_functions,
+ function);
+
+ pctldev->num_functions++;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_add_function);
+
+/**
+ * pinmux_generic_remove_function() - removes a numbered function
+ * @pctldev: pin controller device
+ * @selector: function number
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct function_desc *function;
+
+ function = radix_tree_lookup(&pctldev->pin_function_tree,
+ selector);
+ if (!function)
+ return -ENOENT;
+
+ radix_tree_delete(&pctldev->pin_function_tree, selector);
+ devm_kfree(pctldev->dev, function);
+
+ pctldev->num_functions--;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_remove_function);
+
+/**
+ * pinmux_generic_free_functions() - removes all functions
+ * @pctldev: pin controller device
+ *
+ * Note that the caller must take care of locking.
+ */
+void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
+{
+ struct radix_tree_iter iter;
+ struct function_desc *function;
+ unsigned long *indices;
+ void **slot;
+ int i = 0;
+
+ indices = devm_kzalloc(pctldev->dev, sizeof(*indices) *
+ pctldev->num_functions, GFP_KERNEL);
+ if (!indices)
+ return;
+
+ radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0)
+ indices[i++] = iter.index;
+
+ for (i = 0; i < pctldev->num_functions; i++) {
+ function = radix_tree_lookup(&pctldev->pin_function_tree,
+ indices[i]);
+ radix_tree_delete(&pctldev->pin_function_tree, indices[i]);
+ devm_kfree(pctldev->dev, function);
+ }
+
+ pctldev->num_functions = 0;
+}
+
+#endif /* CONFIG_GENERIC_PINMUX */
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
--- a/drivers/pinctrl/pinmux.h
+++ b/drivers/pinctrl/pinmux.h
@@ -111,3 +111,45 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot,
}
#endif
+
+#ifdef CONFIG_GENERIC_PINMUX
+
+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);
+
+const char *
+pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector);
+
+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned * const num_groups);
+
+struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
+ unsigned int selector);
+
+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
+ const char *name,
+ const char **groups,
+ unsigned const num_groups,
+ void *data);
+
+int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
+ unsigned int selector);
+
+static inline int
+pinmux_generic_remove_last_function(struct pinctrl_dev *pctldev)
+{
+ return pinmux_generic_remove_function(pctldev,
+ pctldev->num_functions - 1);
+}
+
+void pinmux_generic_free_functions(struct pinctrl_dev *pctldev);
+
+#else
+
+static inline void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
+{
+}
+
+#endif
--
2.11.0
^ permalink raw reply
* [PATCH 4/5] pinctrl: single: Use generic pinctrl helpers for managing groups
From: Tony Lindgren @ 2016-12-27 17:20 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio, devicetree, linux-kernel, linux-omap
In-Reply-To: <20161227172003.6517-1-tony@atomide.com>
We can now drop the driver specific code for managing groups.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/pinctrl/Kconfig | 2 +-
drivers/pinctrl/pinctrl-single.c | 156 +++------------------------------------
2 files changed, 12 insertions(+), 146 deletions(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -166,8 +166,8 @@ config PINCTRL_ROCKCHIP
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
+ select GENERIC_PINCTRL
select PINMUX
- select PINCONF
select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -38,22 +38,6 @@
#define PCS_OFF_DISABLED ~0U
/**
- * struct pcs_pingroup - pingroups for a function
- * @np: pingroup device node pointer
- * @name: pingroup name
- * @gpins: array of the pins in the group
- * @ngpins: number of pins in the group
- * @node: list node
- */
-struct pcs_pingroup {
- struct device_node *np;
- const char *name;
- int *gpins;
- int ngpins;
- struct list_head node;
-};
-
-/**
* struct pcs_func_vals - mux function register offset and value pair
* @reg: register virtual address
* @val: register value
@@ -176,15 +160,12 @@ struct pcs_soc_data {
* @bits_per_mux: number of bits per mux
* @bits_per_pin: number of bits per pin
* @pins: physical pins on the SoC
- * @pgtree: pingroup index radix tree
* @ftree: function index radix tree
- * @pingroups: list of pingroups
* @functions: list of functions
* @gpiofuncs: list of gpio functions
* @irqs: list of interrupt registers
* @chip: chip container for this instance
* @domain: IRQ domain for this instance
- * @ngroups: number of pingroups
* @nfuncs: number of functions
* @desc: pin controller descriptor
* @read: register read function to use
@@ -213,15 +194,12 @@ struct pcs_device {
bool bits_per_mux;
unsigned bits_per_pin;
struct pcs_data pins;
- struct radix_tree_root pgtree;
struct radix_tree_root ftree;
- struct list_head pingroups;
struct list_head functions;
struct list_head gpiofuncs;
struct list_head irqs;
struct irq_chip chip;
struct irq_domain *domain;
- unsigned ngroups;
unsigned nfuncs;
struct pinctrl_desc desc;
unsigned (*read)(void __iomem *reg);
@@ -288,54 +266,6 @@ static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg)
writel(val, reg);
}
-static int pcs_get_groups_count(struct pinctrl_dev *pctldev)
-{
- struct pcs_device *pcs;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
-
- return pcs->ngroups;
-}
-
-static const char *pcs_get_group_name(struct pinctrl_dev *pctldev,
- unsigned gselector)
-{
- struct pcs_device *pcs;
- struct pcs_pingroup *group;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
- group = radix_tree_lookup(&pcs->pgtree, gselector);
- if (!group) {
- dev_err(pcs->dev, "%s could not find pingroup%i\n",
- __func__, gselector);
- return NULL;
- }
-
- return group->name;
-}
-
-static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
- unsigned gselector,
- const unsigned **pins,
- unsigned *npins)
-{
- struct pcs_device *pcs;
- struct pcs_pingroup *group;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
- group = radix_tree_lookup(&pcs->pgtree, gselector);
- if (!group) {
- dev_err(pcs->dev, "%s could not find pingroup%i\n",
- __func__, gselector);
- return -EINVAL;
- }
-
- *pins = group->gpins;
- *npins = group->ngpins;
-
- return 0;
-}
-
static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned pin)
@@ -369,9 +299,9 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
struct pinctrl_map **map, unsigned *num_maps);
static const struct pinctrl_ops pcs_pinctrl_ops = {
- .get_groups_count = pcs_get_groups_count,
- .get_group_name = pcs_get_group_name,
- .get_group_pins = pcs_get_group_pins,
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
.pin_dbg_show = pcs_pin_dbg_show,
.dt_node_to_map = pcs_dt_node_to_map,
.dt_free_map = pcs_dt_free_map,
@@ -685,7 +615,7 @@ static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned npins, old = 0;
int i, ret;
- ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
if (ret)
return ret;
for (i = 0; i < npins; i++) {
@@ -707,7 +637,7 @@ static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned npins;
int i, ret;
- ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+ ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
if (ret)
return ret;
for (i = 0; i < npins; i++) {
@@ -897,40 +827,6 @@ static void pcs_remove_function(struct pcs_device *pcs,
}
/**
- * pcs_add_pingroup() - add a pingroup to the pingroup list
- * @pcs: pcs driver instance
- * @np: device node of the mux entry
- * @name: name of the pingroup
- * @gpins: array of the pins that belong to the group
- * @ngpins: number of pins in the group
- */
-static int pcs_add_pingroup(struct pcs_device *pcs,
- struct device_node *np,
- const char *name,
- int *gpins,
- int ngpins)
-{
- struct pcs_pingroup *pingroup;
-
- pingroup = devm_kzalloc(pcs->dev, sizeof(*pingroup), GFP_KERNEL);
- if (!pingroup)
- return -ENOMEM;
-
- pingroup->name = name;
- pingroup->np = np;
- pingroup->gpins = gpins;
- pingroup->ngpins = ngpins;
-
- mutex_lock(&pcs->mutex);
- list_add_tail(&pingroup->node, &pcs->pingroups);
- radix_tree_insert(&pcs->pgtree, pcs->ngroups, pingroup);
- pcs->ngroups++;
- mutex_unlock(&pcs->mutex);
-
- return 0;
-}
-
-/**
* pcs_get_pin_by_offset() - get a pin index based on the register offset
* @pcs: pcs driver instance
* @offset: register offset from the base
@@ -1100,10 +996,9 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
return 0;
}
-static void pcs_free_pingroups(struct pcs_device *pcs);
-
/**
* smux_parse_one_pinctrl_entry() - parses a device tree mux entry
+ * @pctldev: pin controller device
* @pcs: pinctrl driver instance
* @np: device node of the mux entry
* @map: map entry
@@ -1186,7 +1081,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
goto free_pins;
}
- res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+ res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
if (res < 0)
goto free_function;
@@ -1205,7 +1100,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
return 0;
free_pingroups:
- pcs_free_pingroups(pcs);
+ pinctrl_generic_remove_last_group(pcs->pctl);
*num_maps = 1;
free_function:
pcs_remove_function(pcs, function);
@@ -1320,7 +1215,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
goto free_pins;
}
- res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+ res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
if (res < 0)
goto free_function;
@@ -1337,7 +1232,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
return 0;
free_pingroups:
- pcs_free_pingroups(pcs);
+ pinctrl_generic_remove_last_group(pcs->pctl);
*num_maps = 1;
free_function:
pcs_remove_function(pcs, function);
@@ -1436,33 +1331,6 @@ static void pcs_free_funcs(struct pcs_device *pcs)
}
/**
- * pcs_free_pingroups() - free memory used by pingroups
- * @pcs: pcs driver instance
- */
-static void pcs_free_pingroups(struct pcs_device *pcs)
-{
- struct list_head *pos, *tmp;
- int i;
-
- mutex_lock(&pcs->mutex);
- for (i = 0; i < pcs->ngroups; i++) {
- struct pcs_pingroup *pingroup;
-
- pingroup = radix_tree_lookup(&pcs->pgtree, i);
- if (!pingroup)
- continue;
- radix_tree_delete(&pcs->pgtree, i);
- }
- list_for_each_safe(pos, tmp, &pcs->pingroups) {
- struct pcs_pingroup *pingroup;
-
- pingroup = list_entry(pos, struct pcs_pingroup, node);
- list_del(&pingroup->node);
- }
- mutex_unlock(&pcs->mutex);
-}
-
-/**
* pcs_irq_free() - free interrupt
* @pcs: pcs driver instance
*/
@@ -1491,7 +1359,7 @@ static void pcs_free_resources(struct pcs_device *pcs)
pcs_irq_free(pcs);
pinctrl_unregister(pcs->pctl);
pcs_free_funcs(pcs);
- pcs_free_pingroups(pcs);
+
#if IS_BUILTIN(CONFIG_PINCTRL_SINGLE)
if (pcs->missing_nr_pinctrl_cells)
of_remove_property(pcs->np, pcs->missing_nr_pinctrl_cells);
@@ -1885,7 +1753,6 @@ static int pcs_probe(struct platform_device *pdev)
pcs->np = np;
raw_spin_lock_init(&pcs->lock);
mutex_init(&pcs->mutex);
- INIT_LIST_HEAD(&pcs->pingroups);
INIT_LIST_HEAD(&pcs->functions);
INIT_LIST_HEAD(&pcs->gpiofuncs);
soc = match->data;
@@ -1947,7 +1814,6 @@ static int pcs_probe(struct platform_device *pdev)
return -ENODEV;
}
- INIT_RADIX_TREE(&pcs->pgtree, GFP_KERNEL);
INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL);
platform_set_drvdata(pdev, pcs);
--
2.11.0
^ permalink raw reply
* [PATCH 5/5] pinctrl: single: Use generic pinmux helpers for managing functions
From: Tony Lindgren @ 2016-12-27 17:20 UTC (permalink / raw)
To: Linus Walleij
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio, devicetree, linux-kernel, linux-omap
In-Reply-To: <20161227172003.6517-1-tony@atomide.com>
We can now drop the driver specific code for managing functions.
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/pinctrl/Kconfig | 2 +-
drivers/pinctrl/pinctrl-single.c | 134 ++++++---------------------------------
2 files changed, 19 insertions(+), 117 deletions(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -167,7 +167,7 @@ config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
select GENERIC_PINCTRL
- select PINMUX
+ select GENERIC_PINMUX
select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -33,6 +33,7 @@
#include "core.h"
#include "devicetree.h"
#include "pinconf.h"
+#include "pinmux.h"
#define DRIVER_NAME "pinctrl-single"
#define PCS_OFF_DISABLED ~0U
@@ -160,13 +161,10 @@ struct pcs_soc_data {
* @bits_per_mux: number of bits per mux
* @bits_per_pin: number of bits per pin
* @pins: physical pins on the SoC
- * @ftree: function index radix tree
- * @functions: list of functions
* @gpiofuncs: list of gpio functions
* @irqs: list of interrupt registers
* @chip: chip container for this instance
* @domain: IRQ domain for this instance
- * @nfuncs: number of functions
* @desc: pin controller descriptor
* @read: register read function to use
* @write: register write function to use
@@ -194,13 +192,10 @@ struct pcs_device {
bool bits_per_mux;
unsigned bits_per_pin;
struct pcs_data pins;
- struct radix_tree_root ftree;
- struct list_head functions;
struct list_head gpiofuncs;
struct list_head irqs;
struct irq_chip chip;
struct irq_domain *domain;
- unsigned nfuncs;
struct pinctrl_desc desc;
unsigned (*read)(void __iomem *reg);
void (*write)(unsigned val, void __iomem *reg);
@@ -307,59 +302,13 @@ static const struct pinctrl_ops pcs_pinctrl_ops = {
.dt_free_map = pcs_dt_free_map,
};
-static int pcs_get_functions_count(struct pinctrl_dev *pctldev)
-{
- struct pcs_device *pcs;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
-
- return pcs->nfuncs;
-}
-
-static const char *pcs_get_function_name(struct pinctrl_dev *pctldev,
- unsigned fselector)
-{
- struct pcs_device *pcs;
- struct pcs_function *func;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
- func = radix_tree_lookup(&pcs->ftree, fselector);
- if (!func) {
- dev_err(pcs->dev, "%s could not find function%i\n",
- __func__, fselector);
- return NULL;
- }
-
- return func->name;
-}
-
-static int pcs_get_function_groups(struct pinctrl_dev *pctldev,
- unsigned fselector,
- const char * const **groups,
- unsigned * const ngroups)
-{
- struct pcs_device *pcs;
- struct pcs_function *func;
-
- pcs = pinctrl_dev_get_drvdata(pctldev);
- func = radix_tree_lookup(&pcs->ftree, fselector);
- if (!func) {
- dev_err(pcs->dev, "%s could not find function%i\n",
- __func__, fselector);
- return -EINVAL;
- }
- *groups = func->pgnames;
- *ngroups = func->npgnames;
-
- return 0;
-}
-
static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
struct pcs_function **func)
{
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
struct pin_desc *pdesc = pin_desc_get(pctldev, pin);
const struct pinctrl_setting_mux *setting;
+ struct function_desc *function;
unsigned fselector;
/* If pin is not described in DTS & enabled, mux_setting is NULL. */
@@ -367,7 +316,8 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
if (!setting)
return -ENOTSUPP;
fselector = setting->func;
- *func = radix_tree_lookup(&pcs->ftree, fselector);
+ function = pinmux_generic_get_function(pctldev, fselector);
+ *func = function->data;
if (!(*func)) {
dev_err(pcs->dev, "%s could not find function%i\n",
__func__, fselector);
@@ -380,6 +330,7 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
unsigned group)
{
struct pcs_device *pcs;
+ struct function_desc *function;
struct pcs_function *func;
int i;
@@ -387,7 +338,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
/* If function mask is null, needn't enable it. */
if (!pcs->fmask)
return 0;
- func = radix_tree_lookup(&pcs->ftree, fselector);
+ function = pinmux_generic_get_function(pctldev, fselector);
+ func = function->data;
if (!func)
return -EINVAL;
@@ -445,9 +397,9 @@ static int pcs_request_gpio(struct pinctrl_dev *pctldev,
}
static const struct pinmux_ops pcs_pinmux_ops = {
- .get_functions_count = pcs_get_functions_count,
- .get_function_name = pcs_get_function_name,
- .get_function_groups = pcs_get_function_groups,
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
.set_mux = pcs_set_mux,
.gpio_request_enable = pcs_request_gpio,
};
@@ -789,43 +741,24 @@ static struct pcs_function *pcs_add_function(struct pcs_device *pcs,
unsigned npgnames)
{
struct pcs_function *function;
+ int res;
function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL);
if (!function)
return NULL;
- function->name = name;
function->vals = vals;
function->nvals = nvals;
- function->pgnames = pgnames;
- function->npgnames = npgnames;
- mutex_lock(&pcs->mutex);
- list_add_tail(&function->node, &pcs->functions);
- radix_tree_insert(&pcs->ftree, pcs->nfuncs, function);
- pcs->nfuncs++;
- mutex_unlock(&pcs->mutex);
+ res = pinmux_generic_add_function(pcs->pctl, name,
+ pgnames, npgnames,
+ function);
+ if (res)
+ return NULL;
return function;
}
-static void pcs_remove_function(struct pcs_device *pcs,
- struct pcs_function *function)
-{
- int i;
-
- mutex_lock(&pcs->mutex);
- for (i = 0; i < pcs->nfuncs; i++) {
- struct pcs_function *found;
-
- found = radix_tree_lookup(&pcs->ftree, i);
- if (found == function)
- radix_tree_delete(&pcs->ftree, i);
- }
- list_del(&function->node);
- mutex_unlock(&pcs->mutex);
-}
-
/**
* pcs_get_pin_by_offset() - get a pin index based on the register offset
* @pcs: pcs driver instance
@@ -1103,7 +1036,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
pinctrl_generic_remove_last_group(pcs->pctl);
*num_maps = 1;
free_function:
- pcs_remove_function(pcs, function);
+ pinmux_generic_remove_last_function(pcs->pctl);
free_pins:
devm_kfree(pcs->dev, pins);
@@ -1235,8 +1168,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
pinctrl_generic_remove_last_group(pcs->pctl);
*num_maps = 1;
free_function:
- pcs_remove_function(pcs, function);
-
+ pinmux_generic_remove_last_function(pcs->pctl);
free_pins:
devm_kfree(pcs->dev, pins);
@@ -1304,33 +1236,6 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
}
/**
- * pcs_free_funcs() - free memory used by functions
- * @pcs: pcs driver instance
- */
-static void pcs_free_funcs(struct pcs_device *pcs)
-{
- struct list_head *pos, *tmp;
- int i;
-
- mutex_lock(&pcs->mutex);
- for (i = 0; i < pcs->nfuncs; i++) {
- struct pcs_function *func;
-
- func = radix_tree_lookup(&pcs->ftree, i);
- if (!func)
- continue;
- radix_tree_delete(&pcs->ftree, i);
- }
- list_for_each_safe(pos, tmp, &pcs->functions) {
- struct pcs_function *function;
-
- function = list_entry(pos, struct pcs_function, node);
- list_del(&function->node);
- }
- mutex_unlock(&pcs->mutex);
-}
-
-/**
* pcs_irq_free() - free interrupt
* @pcs: pcs driver instance
*/
@@ -1358,7 +1263,6 @@ static void pcs_free_resources(struct pcs_device *pcs)
{
pcs_irq_free(pcs);
pinctrl_unregister(pcs->pctl);
- pcs_free_funcs(pcs);
#if IS_BUILTIN(CONFIG_PINCTRL_SINGLE)
if (pcs->missing_nr_pinctrl_cells)
@@ -1753,7 +1657,6 @@ static int pcs_probe(struct platform_device *pdev)
pcs->np = np;
raw_spin_lock_init(&pcs->lock);
mutex_init(&pcs->mutex);
- INIT_LIST_HEAD(&pcs->functions);
INIT_LIST_HEAD(&pcs->gpiofuncs);
soc = match->data;
pcs->flags = soc->flags;
@@ -1814,7 +1717,6 @@ static int pcs_probe(struct platform_device *pdev)
return -ENODEV;
}
- INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL);
platform_set_drvdata(pdev, pcs);
switch (pcs->width) {
--
2.11.0
^ permalink raw reply
* Re: [PATCH 0/9] ARM: omap: Add empty chosen node in SoCs top level DTSI
From: Tony Lindgren @ 2016-12-27 17:30 UTC (permalink / raw)
To: Javier Martinez Canillas
Cc: linux-kernel, Pali Rohar, Benoît Cousson, devicetree,
Rob Herring, Mark Rutland, linux-omap, Russell King,
linux-arm-kernel
In-Reply-To: <1482158681-4530-1-git-send-email-javier@osg.samsung.com>
* Javier Martinez Canillas <javier@osg.samsung.com> [161219 06:45]:
> Hello Tony,
>
> As discussed in [0], there's a regression when booting a kernel with a DTB
> that doesn't have a pre-existing chosen node. This is usually not an issue
> for most boards since u-boot creates an empty chosen node if isn't present
> in the DTB.
>
> But it can be an issue for others bootloaders as Pali pointed out with the
> N9/900/950 phones and the Nokia Loader (NoLo).
>
> This patch series add chosen nodes in the top level DTSI for all OMAP SoCs.
>
> [0]: http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1294379.html
Applying these into omap-for-v4.10/fixes thanks.
Tony
^ permalink raw reply
* Re: [PATCH 0/4] dt-bindings: mfd: Update TPS65217 interrupts
From: Tony Lindgren @ 2016-12-27 17:52 UTC (permalink / raw)
To: Milo Kim
Cc: bcousson-rdvid1DuHRBWk0Htik3J/w, Arnd Bergmann, Lee Jones,
Sebastian Reichel, Dmitry Torokhov,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161209062833.5768-1-woogyom.kim-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
* Milo Kim <woogyom.kim-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> [161208 22:29]:
> This patch-set fixes wrong property name and uses TPS65217 HW interrupt
> number from the datasheet instead of the DT ABI. DT bindings are also
> updated.
Applying into omap-for-v4.10/fixes before this usage pops up on other
am335x boards.
Regards,
Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] ARM: dts: dra72-evm-tps65917: Add voltage supplies to usb_phy, mmc, dss
From: Tony Lindgren @ 2016-12-27 17:56 UTC (permalink / raw)
To: Roger Quadros
Cc: Lokesh Vutla, Linux OMAP Mailing List, Tero Kristo, Sekhar Nori,
Carlos Hernandez, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA, Linux ARM Mailing List
In-Reply-To: <0ebffa34-c095-46f7-431e-a8886b33a468-l0cyMroinI0@public.gmane.org>
* Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> [161214 04:46]:
> On 14/12/16 14:35, Lokesh Vutla wrote:
> >
> >
> > On Wednesday 14 December 2016 04:30 PM, Roger Quadros wrote:
> >> Lokesh,
> >>
> >> On 14/12/16 10:57, Lokesh Vutla wrote:
> >>> Commit 5d080aa30681 ("ARM: dts: dra72: Add separate dtsi for tps65917")
> >>> added a separate dtsi for dra72-evm-tps65917 moving all the voltage supplies
> >>> to this file. But it missed adding voltage supplies to usb_phy, mmc,
> >>> dss and deleted from dra72-evm-common.dtsi. Adding the voltage supply
> >>> phandles to these nodes in dra72-evm-tps65917.dtsi
> >>>
> >>> Fixes: 5d080aa30681 ("ARM: dts: dra72: Add separate dtsi for tps65917")
> >>> Reported-by: Carlos Hernandez <ceh-l0cyMroinI0@public.gmane.org>
> >>> Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org>
> >>> Signed-off-by: Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org>
> >>> ---
> >>> Logs:
> >>> - DRA72-evm revC: http://pastebin.ubuntu.com/23627665/
> >>> - DRA72-evm revB: http://pastebin.ubuntu.com/23627658/
> >>> arch/arm/boot/dts/dra72-evm-tps65917.dtsi | 16 ++++++++++++++++
> >>> 1 file changed, 16 insertions(+)
> >>>
> >>> diff --git a/arch/arm/boot/dts/dra72-evm-tps65917.dtsi b/arch/arm/boot/dts/dra72-evm-tps65917.dtsi
> >>> index ee6dac44edf1..e6df676886c0 100644
> >>> --- a/arch/arm/boot/dts/dra72-evm-tps65917.dtsi
> >>> +++ b/arch/arm/boot/dts/dra72-evm-tps65917.dtsi
> >>> @@ -132,3 +132,19 @@
> >>> ti,palmas-long-press-seconds = <6>;
> >>> };
> >>> };
> >>> +
> >>> +&usb2_phy1 {
> >>> + phy-supply = <&ldo4_reg>;
> >>> +};
> >>> +
> >>> +&usb2_phy2 {
> >>> + phy-supply = <&ldo4_reg>;
> >>> +};
> >>> +
> >>> +&dss {
> >>> + vdda_video-supply = <&ldo5_reg>;
> >>> +};
> >>> +
> >>> +&mmc1 {
> >>> + vmmc_aux-supply = <&ldo1_reg>;
> >>> +};
> >>>
> >>
> >> Are you sure that all future users of dra72-evm-tps65917.dtsi will use this same configuration?
> >> If not I'd rather put this in the board dts files.
> >
> > hmm..This debate already happened when creating dra72-evm-tps65917 file
> > and concluded that all the common regulator stuff on dra72 evm revA,B,C
> > should go in this file. Any new board which is not similar to dra72-evm
> > will not be using this file.
>
> OK, then it is fine. Thanks for clarifying.
Applying into omap-for-v4.10/fixes thanks.
Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] ARM: dts: n900: Mark eMMC slot with no-sdio and no-sd flags
From: Tony Lindgren @ 2016-12-27 17:57 UTC (permalink / raw)
To: Pavel Machek
Cc: Pali Rohár, Benoît Cousson, Rob Herring, Mark Rutland,
Russell King, Aaro Koskinen, Chris Ball, Ulf Hansson,
Ivaylo Dimitrov, Sebastian Reichel, linux-omap, devicetree,
linux-arm-kernel, linux-kernel, linux-mmc
In-Reply-To: <20161214213445.GD28424@amd>
* Pavel Machek <pavel@ucw.cz> [161214 13:34]:
> On Wed 2016-12-14 22:29:44, Pali Rohár wrote:
> > Trying to initialize eMMC slot as SDIO or SD cause failure in n900 port of
> > qemu. eMMC itself is not detected and is not working.
> >
> > Real Nokia N900 harware does not have this problem. As eMMC is really not
> > SDIO or SD based such change is harmless and will fix support for qemu.
> >
> > Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
>
> Acked-by: Pavel Machek <pavel@ucw.cz>
Applying into omap-for-v4.10/fixes thanks.
Tony
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox