* [PATCH] ARM: dts: introduce the sama5d2 ptc ek board
From: Ludovic Desroches @ 2017-12-05 14:23 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: nicolas.ferre-UWL1GkI3JZL3oGB3hsPCZA,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ludovic Desroches
Add the official SAMA5D2 Peripheral Touch Controller Evaluation
Kit board.
Signed-off-by: Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts | 442 ++++++++++++++++++++++++++++++
2 files changed, 443 insertions(+)
create mode 100644 arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 043d7c720d0c..ed60582eb1da 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -48,6 +48,7 @@ dtb-$(CONFIG_SOC_AT91SAM9) += \
dtb-$(CONFIG_SOC_SAM_V7) += \
at91-kizbox2.dtb \
at91-sama5d27_som1_ek.dtb \
+ at91-sama5d2_ptc_ek.dtb \
at91-sama5d2_xplained.dtb \
at91-sama5d3_xplained.dtb \
at91-tse850-3.dtb \
diff --git a/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
new file mode 100644
index 000000000000..46e8bb668546
--- /dev/null
+++ b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
@@ -0,0 +1,442 @@
+/*
+ * at91-sama5d2_ptc_ek.dts - Device Tree file for SAMA5D2 PTC EK board
+ *
+ * Copyright (C) 2017 Microchip/Atmel,
+ * 2017 Wenyou Yang <wenyou.yang-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ * 2017 Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/dts-v1/;
+#include "sama5d2.dtsi"
+#include "sama5d2-pinfunc.h"
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Atmel SAMA5D2 PTC EK";
+ compatible = "atmel,sama5d2-ptc_ek", "atmel,sama5d2", "atmel,sama5";
+
+ aliases {
+ serial0 = &uart0;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x20000000 0x80000>;
+ };
+
+ clocks {
+ slow_xtal {
+ clock-frequency = <32768>;
+ };
+
+ main_xtal {
+ clock-frequency = <24000000>;
+ };
+ };
+
+ ahb {
+ usb0: gadget@300000 {
+ atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usba_vbus>;
+ status = "okay";
+ };
+
+ usb1: ohci@400000 {
+ num-ports = <3>;
+ atmel,vbus-gpio = <0
+ &pioA PIN_PB12 GPIO_ACTIVE_HIGH
+ 0
+ >;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb_default>;
+ status = "okay";
+ };
+
+ usb2: ehci@500000 {
+ status = "okay";
+ };
+
+ ebi: ebi@10000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand_default>;
+ status = "okay"; /* conflicts with sdmmc1 and qspi0 */
+
+ nand_controller: nand-controller {
+ status = "okay";
+
+ nand@3 {
+ reg = <0x3 0x0 0x2>;
+ atmel,rb = <0>;
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ nand-on-flash-bbt;
+ label = "atmel_nand";
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ at91bootstrap@0 {
+ label = "bootstrap";
+ reg = <0x0 0x40000>;
+ };
+
+ bootloader@40000 {
+ label = "bootloader";
+ reg = <0x40000 0xc0000>;
+ };
+
+ bootloaderenv@0x100000 {
+ label = "bootloader env";
+ reg = <0x100000 0x40000>;
+ };
+
+ bootloaderenvred@0x140000 {
+ label = "bootloader env redundant";
+ reg = <0x140000 0x40000>;
+ };
+
+ dtb@180000 {
+ label = "device tree";
+ reg = <0x180000 0x80000>;
+ };
+
+ kernel@200000 {
+ label = "kernel";
+ reg = <0x200000 0x600000>;
+ };
+
+ rootfs@800000 {
+ label = "rootfs";
+ reg = <0x800000 0x1f800000>;
+ };
+ };
+ };
+ };
+ };
+
+ sdmmc0: sdio-host@a0000000 {
+ bus-width = <8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sdmmc0_default>;
+ non-removable;
+ mmc-ddr-1_8v;
+ status = "okay";
+ };
+
+ apb {
+ spi0: spi@f8000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0_default>;
+ status = "okay";
+ };
+
+ macb0: ethernet@f8008000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
+ phy-mode = "rmii";
+ status = "okay";
+
+ ethernet-phy@1 {
+ reg = <0x1>;
+ interrupt-parent = <&pioA>;
+ interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
+
+ uart0: serial@f801c000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0_default>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "okay";
+ };
+
+ uart2: serial@f8024000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2_default>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "okay";
+ };
+
+ i2c0: i2c@f8028000 {
+ dmas = <0>, <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0_default>;
+ status = "okay";
+ };
+
+ flx0: flexcom@f8034000 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+ status = "okay";
+
+ i2c2: i2c@600 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <0>, <0>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&flx0_clk>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flx0_default>;
+ atmel,fifo-size = <16>;
+ status = "okay";
+ };
+ };
+
+ shdwc@f8048010 {
+ atmel,shdwc-debouncer = <976>;
+
+ input@0 {
+ reg = <0>;
+ atmel,wakeup-type = "low";
+ };
+ };
+
+ watchdog@f8048040 {
+ status = "okay";
+ };
+
+ spi1: spi@fc000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
+ status = "okay";
+ };
+
+ i2c1: i2c@fc028000 {
+ dmas = <0>, <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1_default>;
+ status = "okay";
+
+ at24@50 {
+ compatible = "24c02";
+ reg = <0x50>;
+ pagesize = <8>;
+ };
+ };
+
+ pinctrl@fc038000 {
+ pinctrl_flx0_default: flx0_default {
+ pinmux = <PIN_PB28__FLEXCOM0_IO0>,
+ <PIN_PB29__FLEXCOM0_IO1>;
+ bias-disable;
+ };
+
+ pinctrl_i2c0_default: i2c0_default {
+ pinmux = <PIN_PD21__TWD0>,
+ <PIN_PD22__TWCK0>;
+ bias-disable;
+ };
+
+ pinctrl_i2c1_default: i2c1_default {
+ pinmux = <PIN_PC6__TWD1>,
+ <PIN_PC7__TWCK1>;
+ bias-disable;
+ };
+
+ pinctrl_key_gpio_default: key_gpio_default {
+ pinmux = <PIN_PA10__GPIO>;
+ bias-pull-up;
+ };
+
+ pinctrl_led_gpio_default: led_gpio_default {
+ pinmux = <PIN_PB6__GPIO>,
+ <PIN_PB8__GPIO>,
+ <PIN_PB10__GPIO>;
+ bias-pull-up;
+ };
+
+ pinctrl_macb0_default: macb0_default {
+ pinmux = <PIN_PB14__GTXCK>,
+ <PIN_PB15__GTXEN>,
+ <PIN_PB16__GRXDV>,
+ <PIN_PB17__GRXER>,
+ <PIN_PB18__GRX0>,
+ <PIN_PB19__GRX1>,
+ <PIN_PB20__GTX0>,
+ <PIN_PB21__GTX1>,
+ <PIN_PB22__GMDC>,
+ <PIN_PB23__GMDIO>;
+ bias-disable;
+ };
+
+ pinctrl_macb0_phy_irq: macb0_phy_irq {
+ pinmux = <PIN_PB24__GPIO>;
+ bias-disable;
+ };
+
+ pinctrl_nand_default: nand_default {
+ re_we_data {
+ pinmux = <PIN_PA22__D0>,
+ <PIN_PA23__D1>,
+ <PIN_PA24__D2>,
+ <PIN_PA25__D3>,
+ <PIN_PA26__D4>,
+ <PIN_PA27__D5>,
+ <PIN_PA28__D6>,
+ <PIN_PA29__D7>,
+ <PIN_PA30__NWE_NANDWE>,
+ <PIN_PB2__NRD_NANDOE>;
+ bias-pull-up;
+ };
+
+ ale_cle_rdy_cs {
+ pinmux = <PIN_PB0__A21_NANDALE>,
+ <PIN_PB1__A22_NANDCLE>,
+ <PIN_PC8__NANDRDY>,
+ <PIN_PA31__NCS3>;
+ bias-pull-up;
+ };
+ };
+
+ pinctrl_sdmmc0_default: sdmmc0_default {
+ cmd_data {
+ pinmux = <PIN_PA1__SDMMC0_CMD>,
+ <PIN_PA2__SDMMC0_DAT0>,
+ <PIN_PA3__SDMMC0_DAT1>,
+ <PIN_PA4__SDMMC0_DAT2>,
+ <PIN_PA5__SDMMC0_DAT3>,
+ <PIN_PA6__SDMMC0_DAT4>,
+ <PIN_PA7__SDMMC0_DAT5>,
+ <PIN_PA8__SDMMC0_DAT6>,
+ <PIN_PA9__SDMMC0_DAT7>;
+ bias-pull-up;
+ };
+
+ ck_cd_vddsel {
+ pinmux = <PIN_PA0__SDMMC0_CK>,
+ <PIN_PA11__SDMMC0_VDDSEL>,
+ <PIN_PA13__SDMMC0_CD>;
+ bias-disable;
+ };
+ };
+
+ pinctrl_spi0_default: spi0_default {
+ pinmux = <PIN_PA14__SPI0_SPCK>,
+ <PIN_PA15__SPI0_MOSI>,
+ <PIN_PA16__SPI0_MISO>,
+ <PIN_PA17__SPI0_NPCS0>;
+ bias-disable;
+ };
+
+ pinctrl_spi1_default: spi1_default {
+ pinmux = <PIN_PC1__SPI1_SPCK>,
+ <PIN_PC2__SPI1_MOSI>,
+ <PIN_PC3__SPI1_MISO>,
+ <PIN_PC4__SPI1_NPCS0>;
+ bias-disable;
+ };
+
+ pinctrl_uart0_default: uart0_default {
+ pinmux = <PIN_PB26__URXD0>,
+ <PIN_PB27__UTXD0>;
+ bias-disable;
+ };
+
+ pinctrl_uart2_default: uart2_default {
+ pinmux = <PIN_PD23__URXD2>,
+ <PIN_PD24__UTXD2>;
+ bias-disable;
+ };
+
+ pinctrl_usb_default: usb_default {
+ pinmux = <PIN_PB12__GPIO>;
+ bias-disable;
+ };
+
+ pinctrl_usba_vbus: usba_vbus {
+ pinmux = <PIN_PB11__GPIO>;
+ bias-disable;
+ };
+
+ };
+
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_key_gpio_default>;
+
+ bp1 {
+ label = "PB_USER";
+ gpios = <&pioA PIN_PA10 GPIO_ACTIVE_LOW>;
+ linux,code = <0x104>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_led_gpio_default>;
+ status = "okay";
+
+ red {
+ label = "red";
+ gpios = <&pioA PIN_PB10 GPIO_ACTIVE_HIGH>;
+ };
+
+ green {
+ label = "green";
+ gpios = <&pioA PIN_PB8 GPIO_ACTIVE_HIGH>;
+ };
+
+ blue {
+ label = "blue";
+ gpios = <&pioA PIN_PB6 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
--
2.12.2
--
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 related
* [PATCH v5 00/11] add pinmuxing support for pins in AXP209 and AXP813 PMICs
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij, robh+dt, mark.rutland, wens, linux, maxime.ripard,
lee.jones
Cc: linux-gpio, devicetree, linux-kernel, linux-arm-kernel,
thomas.petazzoni, linux-sunxi, Quentin Schulz
The AXP209 and AXP813 PMICs have several pins (respectively 3 and 2) that can
be used either as GPIOs or for other purposes (ADC or LDO here).
We already have a GPIO driver for the GPIO use of those pins on the AXP209.
Let's "upgrade" this driver to support all the functions these pins can have.
Then we add support to this driver for the AXP813 which is slighlty different
(basically a different offset in two registers and one less pin).
I suggest patches 1 to 8 go through Linus's tree and 9 via Lee's.
v5:
- add reference to pinctrl dt-bindings in driver's dt-binding,
- add statement that this driver employs per-pin muxing pattern,
- add a patch on top of the patch series to fix checkpatch warnings,
- add a few information to the Kconfig to make checkpatch happy,
v4:
- separate dt-binding patch when adding pinctrl feature,
- use - instead of _ in DT node name,
- remove muxing operation from pinctrl driver when choosing LDO mux in order
to not interfere with the regulator framework,
- add adc_mux to specify specific mux value for ADC (different between AXP209
and AXP813),
- misc modifications (header include reordering, unsigned int -> u8,
new line removal),
v3:
- add defines for GPIO funcs,
- use again get_regs function instead of drv_data (which was implemented in
v2),
- use of_device_id data for device specific data (gpio_status_offset and pins
description),
- change compatible from axp813-pctl to axp813-gpio,
- use axp81x DT label instead of axp813 since AXP813 and AXP818 are similar,
- add dtsi include for all boards embedding axp813/axp818,
v2:
- add support for AXP813 pins,
- split into more patches so it is easier to follow the modifications,
- reorder of some patches,
- register all pins within the same range instead of a range per pin,
Thanks,
Quentin
Quentin Schulz (9):
gpio: axp209: switch unsigned variables to unsigned int
pinctrl: move gpio-axp209 to pinctrl
pinctrl: axp209: add pinctrl features
dt-bindings: gpio: gpio-axp209: add pinctrl features
pinctrl: axp209: rename everything from gpio to pctl
pinctrl: axp209: add programmable gpio_status_offset
pinctrl: axp209: add programmable ADC muxing value
pinctrl: axp209: add support for AXP813 GPIOs
mfd: axp20x: add pinctrl cell for AXP813
.../devicetree/bindings/gpio/gpio-axp209.txt | 49 ++-
drivers/gpio/Kconfig | 6 -
drivers/gpio/Makefile | 1 -
drivers/gpio/gpio-axp209.c | 188 --------
drivers/mfd/axp20x.c | 3 +
drivers/pinctrl/Kconfig | 10 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-axp209.c | 476 +++++++++++++++++++++
8 files changed, 537 insertions(+), 197 deletions(-)
delete mode 100644 drivers/gpio/gpio-axp209.c
create mode 100644 drivers/pinctrl/pinctrl-axp209.c
--
2.14.1
^ permalink raw reply
* [PATCH v5 1/9] gpio: axp209: switch unsigned variables to unsigned int
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Checkpatch complains with the following message:
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
Let's make it happy by switching over to unsigned int.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/gpio/gpio-axp209.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c
index 4a346b7b4172..6ee7dc1418fa 100644
--- a/drivers/gpio/gpio-axp209.c
+++ b/drivers/gpio/gpio-axp209.c
@@ -32,7 +32,7 @@ struct axp20x_gpio {
struct regmap *regmap;
};
-static int axp20x_gpio_get_reg(unsigned offset)
+static int axp20x_gpio_get_reg(unsigned int offset)
{
switch (offset) {
case 0:
@@ -46,7 +46,7 @@ static int axp20x_gpio_get_reg(unsigned offset)
return -EINVAL;
}
-static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
+static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset)
{
struct axp20x_gpio *gpio = gpiochip_get_data(chip);
int reg;
@@ -60,7 +60,7 @@ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
AXP20X_GPIO_FUNCTION_INPUT);
}
-static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct axp20x_gpio *gpio = gpiochip_get_data(chip);
unsigned int val;
@@ -73,7 +73,8 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset + 4));
}
-static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int axp20x_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
{
struct axp20x_gpio *gpio = gpiochip_get_data(chip);
unsigned int val;
@@ -102,7 +103,7 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
return val & 2;
}
-static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
+static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct axp20x_gpio *gpio = gpiochip_get_data(chip);
@@ -118,7 +119,7 @@ static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
: AXP20X_GPIO_FUNCTION_OUT_LOW);
}
-static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
+static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
axp20x_gpio_output(chip, offset, value);
--
2.14.1
^ permalink raw reply related
* [PATCH v5 2/9] pinctrl: move gpio-axp209 to pinctrl
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij, robh+dt, mark.rutland, wens, linux, maxime.ripard,
lee.jones
Cc: linux-gpio, devicetree, linux-kernel, linux-arm-kernel,
thomas.petazzoni, linux-sunxi, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz@free-electrons.com>
To prepare the driver for the upcoming pinctrl features, move the GPIO
driver AXP209 from GPIO to pinctrl subsystem.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/gpio/Kconfig | 6 ------
drivers/gpio/Makefile | 1 -
drivers/pinctrl/Kconfig | 10 ++++++++++
drivers/pinctrl/Makefile | 1 +
drivers/{gpio/gpio-axp209.c => pinctrl/pinctrl-axp209.c} | 0
5 files changed, 11 insertions(+), 7 deletions(-)
rename drivers/{gpio/gpio-axp209.c => pinctrl/pinctrl-axp209.c} (100%)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d6a8e851ad13..395669bfcc26 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -122,12 +122,6 @@ config GPIO_ATH79
Select this option to enable GPIO driver for
Atheros AR71XX/AR724X/AR913X SoC devices.
-config GPIO_AXP209
- tristate "X-Powers AXP209 PMIC GPIO Support"
- depends on MFD_AXP20X
- help
- Say yes to enable GPIO support for the AXP209 PMIC
-
config GPIO_BCM_KONA
bool "Broadcom Kona GPIO"
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4bc24febb889..bc5dd673fa11 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
-obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 4571cc098b76..ce126955212c 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -63,6 +63,16 @@ config PINCTRL_AS3722
open drain configuration for the GPIO pins of AS3722 devices. It also
supports the GPIO functionality through gpiolib.
+config PINCTRL_AXP209
+ tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support"
+ depends on MFD_AXP20X
+ help
+ AXP PMICs provides multiple GPIOs that can be muxed for different
+ functions. This driver bundles a pinctrl driver to select the function
+ muxing and a GPIO driver to handle the GPIO when the GPIO function is
+ selected.
+ Say yes to enable pinctrl and GPIO support for the AXP209 PMIC
+
config PINCTRL_BF54x
def_bool y if BF54x
select PINCTRL_ADI2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index d0d4844f8022..4777f1595ce2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o
obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o
obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o
+obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o
obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o
obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
similarity index 100%
rename from drivers/gpio/gpio-axp209.c
rename to drivers/pinctrl/pinctrl-axp209.c
--
2.14.1
^ permalink raw reply related
* [PATCH v5 3/9] pinctrl: axp209: add pinctrl features
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO,
an ADC or a LDO regulator. GPIO2 can only act as a GPIO.
This adds the pinctrl features to the driver so GPIO0/1 can be used as
ADC or LDO regulator.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/pinctrl/pinctrl-axp209.c | 304 ++++++++++++++++++++++++++++++++++++---
1 file changed, 284 insertions(+), 20 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 6ee7dc1418fa..48cb57dcc575 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -1,7 +1,8 @@
/*
- * AXP20x GPIO driver
+ * AXP20x pinctrl and GPIO driver
*
* Copyright (C) 2016 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ * Copyright (C) 2017 Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@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 as published by the
@@ -18,6 +19,9 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -27,9 +31,52 @@
#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1
#define AXP20X_GPIO_FUNCTION_INPUT 2
+#define AXP20X_FUNC_GPIO_OUT 0
+#define AXP20X_FUNC_GPIO_IN 1
+#define AXP20X_FUNC_LDO 2
+#define AXP20X_FUNC_ADC 3
+#define AXP20X_FUNCS_NB 4
+
+#define AXP20X_MUX_GPIO_OUT 0
+#define AXP20X_MUX_GPIO_IN BIT(1)
+#define AXP20X_MUX_ADC BIT(2)
+
+struct axp20x_pctrl_desc {
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ /* Stores the pins supporting LDO function. Bit offset is pin number. */
+ u8 ldo_mask;
+ /* Stores the pins supporting ADC function. Bit offset is pin number. */
+ u8 adc_mask;
+};
+
+struct axp20x_pinctrl_function {
+ const char *name;
+ unsigned int muxval;
+ const char **groups;
+ unsigned int ngroups;
+};
+
struct axp20x_gpio {
struct gpio_chip chip;
struct regmap *regmap;
+ struct pinctrl_dev *pctl_dev;
+ struct device *dev;
+ const struct axp20x_pctrl_desc *desc;
+ struct axp20x_pinctrl_function funcs[AXP20X_FUNCS_NB];
+};
+
+static const struct pinctrl_pin_desc axp209_pins[] = {
+ PINCTRL_PIN(0, "GPIO0"),
+ PINCTRL_PIN(1, "GPIO1"),
+ PINCTRL_PIN(2, "GPIO2"),
+};
+
+static const struct axp20x_pctrl_desc axp20x_data = {
+ .pins = axp209_pins,
+ .npins = ARRAY_SIZE(axp209_pins),
+ .ldo_mask = BIT(0) | BIT(1),
+ .adc_mask = BIT(0) | BIT(1),
};
static int axp20x_gpio_get_reg(unsigned int offset)
@@ -48,16 +95,7 @@ static int axp20x_gpio_get_reg(unsigned int offset)
static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset)
{
- struct axp20x_gpio *gpio = gpiochip_get_data(chip);
- int reg;
-
- reg = axp20x_gpio_get_reg(offset);
- if (reg < 0)
- return reg;
-
- return regmap_update_bits(gpio->regmap, reg,
- AXP20X_GPIO_FUNCTIONS,
- AXP20X_GPIO_FUNCTION_INPUT);
+ return pinctrl_gpio_direction_input(chip->base + offset);
}
static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
@@ -105,30 +143,221 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip,
static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset,
int value)
+{
+ chip->set(chip, offset, value);
+
+ return 0;
+}
+
+static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct axp20x_gpio *gpio = gpiochip_get_data(chip);
int reg;
+ reg = axp20x_gpio_get_reg(offset);
+ if (reg < 0)
+ return;
+
+ regmap_update_bits(gpio->regmap, reg,
+ AXP20X_GPIO_FUNCTIONS,
+ value ? AXP20X_GPIO_FUNCTION_OUT_HIGH :
+ AXP20X_GPIO_FUNCTION_OUT_LOW);
+}
+
+static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset,
+ u8 config)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ int reg;
+
reg = axp20x_gpio_get_reg(offset);
if (reg < 0)
return reg;
- return regmap_update_bits(gpio->regmap, reg,
- AXP20X_GPIO_FUNCTIONS,
- value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
- : AXP20X_GPIO_FUNCTION_OUT_LOW);
+ return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS,
+ config);
}
-static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ return ARRAY_SIZE(gpio->funcs);
+}
+
+static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ return gpio->funcs[selector].name;
+}
+
+static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int *num_groups)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = gpio->funcs[selector].groups;
+ *num_groups = gpio->funcs[selector].ngroups;
+
+ return 0;
+}
+
+static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int group)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ unsigned int mask;
+
+ /* Every pin supports GPIO_OUT and GPIO_IN functions */
+ if (function <= AXP20X_FUNC_GPIO_IN)
+ return axp20x_pmx_set(pctldev, group,
+ gpio->funcs[function].muxval);
+
+ if (function == AXP20X_FUNC_LDO)
+ mask = gpio->desc->ldo_mask;
+ else
+ mask = gpio->desc->adc_mask;
+
+ if (!(BIT(group) & mask))
+ return -EINVAL;
+
+ /*
+ * We let the regulator framework handle the LDO muxing as muxing bits
+ * are basically also regulators on/off bits. It's better not to enforce
+ * any state of the regulator when selecting LDO mux so that we don't
+ * interfere with the regulator driver.
+ */
+ if (function == AXP20X_FUNC_LDO)
+ return 0;
+
+ return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval);
+}
+
+static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset, bool input)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ if (input)
+ return axp20x_pmx_set(pctldev, offset,
+ gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval);
+
+ return axp20x_pmx_set(pctldev, offset,
+ gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
+}
+
+static const struct pinmux_ops axp20x_pmx_ops = {
+ .get_functions_count = axp20x_pmx_func_cnt,
+ .get_function_name = axp20x_pmx_func_name,
+ .get_function_groups = axp20x_pmx_func_groups,
+ .set_mux = axp20x_pmx_set_mux,
+ .gpio_set_direction = axp20x_pmx_gpio_set_direction,
+ .strict = true,
+};
+
+static int axp20x_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ return gpio->desc->npins;
+}
+
+static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
+ const unsigned int **pins, unsigned int *num_pins)
+{
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = (unsigned int *)&gpio->desc->pins[selector];
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const char *axp20x_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
{
- axp20x_gpio_output(chip, offset, value);
+ struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+ return gpio->desc->pins[selector].name;
+}
+
+static const struct pinctrl_ops axp20x_pctrl_ops = {
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinconf_generic_dt_free_map,
+ .get_groups_count = axp20x_groups_cnt,
+ .get_group_name = axp20x_group_name,
+ .get_group_pins = axp20x_group_pins,
+};
+
+static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask,
+ unsigned int mask_len,
+ struct axp20x_pinctrl_function *func,
+ const struct pinctrl_pin_desc *pins)
+{
+ unsigned long int mask_cpy = mask;
+ const char **group;
+ unsigned int ngroups = hweight8(mask);
+ int bit;
+
+ func->ngroups = ngroups;
+ if (func->ngroups > 0) {
+ func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *),
+ GFP_KERNEL);
+ group = func->groups;
+ for_each_set_bit(bit, &mask_cpy, mask_len) {
+ *group = pins[bit].name;
+ group++;
+ }
+ }
+}
+
+static void axp20x_build_funcs_groups(struct platform_device *pdev)
+{
+ struct axp20x_gpio *gpio = platform_get_drvdata(pdev);
+ int i, pin, npins = gpio->desc->npins;
+
+ gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
+ gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
+ gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
+ gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
+ gpio->funcs[AXP20X_FUNC_LDO].name = "ldo";
+ /*
+ * Muxval for LDO is useless as we won't use it.
+ * See comment in axp20x_pmx_set_mux.
+ */
+ gpio->funcs[AXP20X_FUNC_ADC].name = "adc";
+ gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+
+ /* Every pin supports GPIO_OUT and GPIO_IN functions */
+ for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
+ gpio->funcs[i].ngroups = npins;
+ gpio->funcs[i].groups = devm_kzalloc(&pdev->dev,
+ npins * sizeof(char *),
+ GFP_KERNEL);
+ for (pin = 0; pin < npins; pin++)
+ gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name;
+ }
+
+ axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask,
+ npins, &gpio->funcs[AXP20X_FUNC_LDO],
+ gpio->desc->pins);
+
+ axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask,
+ npins, &gpio->funcs[AXP20X_FUNC_ADC],
+ gpio->desc->pins);
}
static int axp20x_gpio_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
struct axp20x_gpio *gpio;
+ struct pinctrl_desc *pctrl_desc;
int ret;
if (!of_device_is_available(pdev->dev.of_node))
@@ -145,6 +374,8 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
gpio->chip.base = -1;
gpio->chip.can_sleep = true;
+ gpio->chip.request = gpiochip_generic_request;
+ gpio->chip.free = gpiochip_generic_free;
gpio->chip.parent = &pdev->dev;
gpio->chip.label = dev_name(&pdev->dev);
gpio->chip.owner = THIS_MODULE;
@@ -155,7 +386,30 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
gpio->chip.direction_output = axp20x_gpio_output;
gpio->chip.ngpio = 3;
+ gpio->desc = &axp20x_data;
gpio->regmap = axp20x->regmap;
+ gpio->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, gpio);
+
+ axp20x_build_funcs_groups(pdev);
+
+ pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL);
+ if (!pctrl_desc)
+ return -ENOMEM;
+
+ pctrl_desc->name = dev_name(&pdev->dev);
+ pctrl_desc->owner = THIS_MODULE;
+ pctrl_desc->pins = gpio->desc->pins;
+ pctrl_desc->npins = gpio->desc->npins;
+ pctrl_desc->pctlops = &axp20x_pctrl_ops;
+ pctrl_desc->pmxops = &axp20x_pmx_ops;
+
+ gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio);
+ if (IS_ERR(gpio->pctl_dev)) {
+ dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+ return PTR_ERR(gpio->pctl_dev);
+ }
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
if (ret) {
@@ -163,7 +417,16 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
return ret;
}
- dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
+ ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev),
+ gpio->desc->pins->number,
+ gpio->desc->pins->number,
+ gpio->desc->npins);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add pin range\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n");
return 0;
}
@@ -185,5 +448,6 @@ static struct platform_driver axp20x_gpio_driver = {
module_platform_driver(axp20x_gpio_driver);
MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
-MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
+MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver");
MODULE_LICENSE("GPL");
--
2.14.1
^ permalink raw reply related
* [PATCH v5 4/9] dt-bindings: gpio: gpio-axp209: add pinctrl features
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO,
an ADC or a LDO regulator. GPIO2 can only act as a GPIO.
This adds the pinctrl features to the driver so GPIO0/1 can be used as
ADC or LDO regulator.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
.../devicetree/bindings/gpio/gpio-axp209.txt | 36 +++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
index a6611304dd3c..0d77597c3f92 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
@@ -1,8 +1,13 @@
-AXP209 GPIO controller
+AXP209 GPIO & pinctrl controller
This driver follows the usual GPIO bindings found in
Documentation/devicetree/bindings/gpio/gpio.txt
+This driver follows the usual pinctrl bindings found in
+Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+This driver employs the per-pin muxing pattern.
+
Required properties:
- compatible: Should be "x-powers,axp209-gpio"
- #gpio-cells: Should be two. The first cell is the pin number and the
@@ -28,3 +33,32 @@ axp209: pmic@34 {
#gpio-cells = <2>;
};
};
+
+The GPIOs can be muxed to other functions and therefore, must be a subnode of
+axp_gpio.
+
+Example:
+
+&axp_gpio {
+ gpio0_adc: gpio0-adc {
+ pins = "GPIO0";
+ function = "adc";
+ };
+};
+
+&example_node {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio0_adc>;
+};
+
+GPIOs and their functions
+-------------------------
+
+Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does
+not force GPIO1 and GPIO2 to be in gpio_in function as well).
+
+GPIO | Functions
+------------------------
+GPIO0 | gpio_in, gpio_out, ldo, adc
+GPIO1 | gpio_in, gpio_out, ldo, adc
+GPIO2 | gpio_in, gpio_out
--
2.14.1
^ permalink raw reply related
* [PATCH v5 5/9] pinctrl: axp209: rename everything from gpio to pctl
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
This driver used to do only GPIO features of the GPIOs in X-Powers
AXP20X. Now that we have migrated everything to the pinctrl subsystem
and added pinctrl features, rename everything related to pinctrl from
gpio to pctl to ease the understanding of differences between GPIO
and pinctrl features.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/pinctrl/pinctrl-axp209.c | 176 +++++++++++++++++++--------------------
1 file changed, 88 insertions(+), 88 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 48cb57dcc575..17eeb0410a5b 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -57,7 +57,7 @@ struct axp20x_pinctrl_function {
unsigned int ngroups;
};
-struct axp20x_gpio {
+struct axp20x_pctl {
struct gpio_chip chip;
struct regmap *regmap;
struct pinctrl_dev *pctl_dev;
@@ -100,11 +100,11 @@ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset)
static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
- struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+ struct axp20x_pctl *pctl = gpiochip_get_data(chip);
unsigned int val;
int ret;
- ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
+ ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val);
if (ret)
return ret;
@@ -114,7 +114,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
static int axp20x_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
- struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+ struct axp20x_pctl *pctl = gpiochip_get_data(chip);
unsigned int val;
int reg, ret;
@@ -122,7 +122,7 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip,
if (reg < 0)
return reg;
- ret = regmap_read(gpio->regmap, reg, &val);
+ ret = regmap_read(pctl->regmap, reg, &val);
if (ret)
return ret;
@@ -152,14 +152,14 @@ static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset,
static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
- struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+ struct axp20x_pctl *pctl = gpiochip_get_data(chip);
int reg;
reg = axp20x_gpio_get_reg(offset);
if (reg < 0)
return;
- regmap_update_bits(gpio->regmap, reg,
+ regmap_update_bits(pctl->regmap, reg,
AXP20X_GPIO_FUNCTIONS,
value ? AXP20X_GPIO_FUNCTION_OUT_HIGH :
AXP20X_GPIO_FUNCTION_OUT_LOW);
@@ -168,30 +168,30 @@ static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset,
static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset,
u8 config)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
int reg;
reg = axp20x_gpio_get_reg(offset);
if (reg < 0)
return reg;
- return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS,
+ return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS,
config);
}
static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- return ARRAY_SIZE(gpio->funcs);
+ return ARRAY_SIZE(pctl->funcs);
}
static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- return gpio->funcs[selector].name;
+ return pctl->funcs[selector].name;
}
static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
@@ -199,10 +199,10 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
const char * const **groups,
unsigned int *num_groups)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- *groups = gpio->funcs[selector].groups;
- *num_groups = gpio->funcs[selector].ngroups;
+ *groups = pctl->funcs[selector].groups;
+ *num_groups = pctl->funcs[selector].ngroups;
return 0;
}
@@ -210,18 +210,18 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
unsigned int function, unsigned int group)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
unsigned int mask;
/* Every pin supports GPIO_OUT and GPIO_IN functions */
if (function <= AXP20X_FUNC_GPIO_IN)
return axp20x_pmx_set(pctldev, group,
- gpio->funcs[function].muxval);
+ pctl->funcs[function].muxval);
if (function == AXP20X_FUNC_LDO)
- mask = gpio->desc->ldo_mask;
+ mask = pctl->desc->ldo_mask;
else
- mask = gpio->desc->adc_mask;
+ mask = pctl->desc->adc_mask;
if (!(BIT(group) & mask))
return -EINVAL;
@@ -235,21 +235,21 @@ static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
if (function == AXP20X_FUNC_LDO)
return 0;
- return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval);
+ return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval);
}
static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset, bool input)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
if (input)
return axp20x_pmx_set(pctldev, offset,
- gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval);
+ pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval);
return axp20x_pmx_set(pctldev, offset,
- gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
+ pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
}
static const struct pinmux_ops axp20x_pmx_ops = {
@@ -263,17 +263,17 @@ static const struct pinmux_ops axp20x_pmx_ops = {
static int axp20x_groups_cnt(struct pinctrl_dev *pctldev)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- return gpio->desc->npins;
+ return pctl->desc->npins;
}
static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
const unsigned int **pins, unsigned int *num_pins)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- *pins = (unsigned int *)&gpio->desc->pins[selector];
+ *pins = (unsigned int *)&pctl->desc->pins[selector];
*num_pins = 1;
return 0;
@@ -282,9 +282,9 @@ static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
static const char *axp20x_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
- struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+ struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
- return gpio->desc->pins[selector].name;
+ return pctl->desc->pins[selector].name;
}
static const struct pinctrl_ops axp20x_pctrl_ops = {
@@ -319,44 +319,44 @@ static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask,
static void axp20x_build_funcs_groups(struct platform_device *pdev)
{
- struct axp20x_gpio *gpio = platform_get_drvdata(pdev);
- int i, pin, npins = gpio->desc->npins;
-
- gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
- gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
- gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
- gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
- gpio->funcs[AXP20X_FUNC_LDO].name = "ldo";
+ struct axp20x_pctl *pctl = platform_get_drvdata(pdev);
+ int i, pin, npins = pctl->desc->npins;
+
+ pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
+ pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
+ pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
+ pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
+ pctl->funcs[AXP20X_FUNC_LDO].name = "ldo";
/*
* Muxval for LDO is useless as we won't use it.
* See comment in axp20x_pmx_set_mux.
*/
- gpio->funcs[AXP20X_FUNC_ADC].name = "adc";
- gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+ pctl->funcs[AXP20X_FUNC_ADC].name = "adc";
+ pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
/* Every pin supports GPIO_OUT and GPIO_IN functions */
for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
- gpio->funcs[i].ngroups = npins;
- gpio->funcs[i].groups = devm_kzalloc(&pdev->dev,
+ pctl->funcs[i].ngroups = npins;
+ pctl->funcs[i].groups = devm_kzalloc(&pdev->dev,
npins * sizeof(char *),
GFP_KERNEL);
for (pin = 0; pin < npins; pin++)
- gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name;
+ pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name;
}
- axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask,
- npins, &gpio->funcs[AXP20X_FUNC_LDO],
- gpio->desc->pins);
+ axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask,
+ npins, &pctl->funcs[AXP20X_FUNC_LDO],
+ pctl->desc->pins);
- axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask,
- npins, &gpio->funcs[AXP20X_FUNC_ADC],
- gpio->desc->pins);
+ axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask,
+ npins, &pctl->funcs[AXP20X_FUNC_ADC],
+ pctl->desc->pins);
}
-static int axp20x_gpio_probe(struct platform_device *pdev)
+static int axp20x_pctl_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
- struct axp20x_gpio *gpio;
+ struct axp20x_pctl *pctl;
struct pinctrl_desc *pctrl_desc;
int ret;
@@ -368,29 +368,29 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
return -EINVAL;
}
- gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
- if (!gpio)
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
return -ENOMEM;
- gpio->chip.base = -1;
- gpio->chip.can_sleep = true;
- gpio->chip.request = gpiochip_generic_request;
- gpio->chip.free = gpiochip_generic_free;
- gpio->chip.parent = &pdev->dev;
- gpio->chip.label = dev_name(&pdev->dev);
- gpio->chip.owner = THIS_MODULE;
- gpio->chip.get = axp20x_gpio_get;
- gpio->chip.get_direction = axp20x_gpio_get_direction;
- gpio->chip.set = axp20x_gpio_set;
- gpio->chip.direction_input = axp20x_gpio_input;
- gpio->chip.direction_output = axp20x_gpio_output;
- gpio->chip.ngpio = 3;
-
- gpio->desc = &axp20x_data;
- gpio->regmap = axp20x->regmap;
- gpio->dev = &pdev->dev;
-
- platform_set_drvdata(pdev, gpio);
+ pctl->chip.base = -1;
+ pctl->chip.can_sleep = true;
+ pctl->chip.request = gpiochip_generic_request;
+ pctl->chip.free = gpiochip_generic_free;
+ pctl->chip.parent = &pdev->dev;
+ pctl->chip.label = dev_name(&pdev->dev);
+ pctl->chip.owner = THIS_MODULE;
+ pctl->chip.get = axp20x_gpio_get;
+ pctl->chip.get_direction = axp20x_gpio_get_direction;
+ pctl->chip.set = axp20x_gpio_set;
+ pctl->chip.direction_input = axp20x_gpio_input;
+ pctl->chip.direction_output = axp20x_gpio_output;
+ pctl->chip.ngpio = 3;
+
+ pctl->desc = &axp20x_data;
+ pctl->regmap = axp20x->regmap;
+ pctl->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, pctl);
axp20x_build_funcs_groups(pdev);
@@ -400,27 +400,27 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
pctrl_desc->name = dev_name(&pdev->dev);
pctrl_desc->owner = THIS_MODULE;
- pctrl_desc->pins = gpio->desc->pins;
- pctrl_desc->npins = gpio->desc->npins;
+ pctrl_desc->pins = pctl->desc->pins;
+ pctrl_desc->npins = pctl->desc->npins;
pctrl_desc->pctlops = &axp20x_pctrl_ops;
pctrl_desc->pmxops = &axp20x_pmx_ops;
- gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio);
- if (IS_ERR(gpio->pctl_dev)) {
+ pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
+ if (IS_ERR(pctl->pctl_dev)) {
dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
- return PTR_ERR(gpio->pctl_dev);
+ return PTR_ERR(pctl->pctl_dev);
}
- ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+ ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl);
if (ret) {
dev_err(&pdev->dev, "Failed to register GPIO chip\n");
return ret;
}
- ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev),
- gpio->desc->pins->number,
- gpio->desc->pins->number,
- gpio->desc->npins);
+ ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev),
+ pctl->desc->pins->number,
+ pctl->desc->pins->number,
+ pctl->desc->npins);
if (ret) {
dev_err(&pdev->dev, "failed to add pin range\n");
return ret;
@@ -431,21 +431,21 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id axp20x_gpio_match[] = {
+static const struct of_device_id axp20x_pctl_match[] = {
{ .compatible = "x-powers,axp209-gpio" },
{ }
};
-MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
+MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
-static struct platform_driver axp20x_gpio_driver = {
- .probe = axp20x_gpio_probe,
+static struct platform_driver axp20x_pctl_driver = {
+ .probe = axp20x_pctl_probe,
.driver = {
.name = "axp20x-gpio",
- .of_match_table = axp20x_gpio_match,
+ .of_match_table = axp20x_pctl_match,
},
};
-module_platform_driver(axp20x_gpio_driver);
+module_platform_driver(axp20x_pctl_driver);
MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
MODULE_AUTHOR("Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>");
--
2.14.1
^ permalink raw reply related
* [PATCH v5 6/9] pinctrl: axp209: add programmable gpio_status_offset
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To prepare for patches that will add support for a new PMIC that has a
different GPIO input status register, add a gpio_status_offset within
axp20x_pctl structure and use it.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
drivers/pinctrl/pinctrl-axp209.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 17eeb0410a5b..db8e319b6e11 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -48,6 +48,7 @@ struct axp20x_pctrl_desc {
u8 ldo_mask;
/* Stores the pins supporting ADC function. Bit offset is pin number. */
u8 adc_mask;
+ u8 gpio_status_offset;
};
struct axp20x_pinctrl_function {
@@ -77,6 +78,7 @@ static const struct axp20x_pctrl_desc axp20x_data = {
.npins = ARRAY_SIZE(axp209_pins),
.ldo_mask = BIT(0) | BIT(1),
.adc_mask = BIT(0) | BIT(1),
+ .gpio_status_offset = 4,
};
static int axp20x_gpio_get_reg(unsigned int offset)
@@ -108,7 +110,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
if (ret)
return ret;
- return !!(val & BIT(offset + 4));
+ return !!(val & BIT(offset + pctl->desc->gpio_status_offset));
}
static int axp20x_gpio_get_direction(struct gpio_chip *chip,
--
2.14.1
^ permalink raw reply related
* [PATCH v5 7/9] pinctrl: axp209: add programmable ADC muxing value
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To prepare for patches that will add support for a new PMIC that has a
different GPIO adc muxing value, add an adc_mux within axp20x_pctl
structure and use it.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/pinctrl/pinctrl-axp209.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index db8e319b6e11..9bb8722ba90f 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -49,6 +49,7 @@ struct axp20x_pctrl_desc {
/* Stores the pins supporting ADC function. Bit offset is pin number. */
u8 adc_mask;
u8 gpio_status_offset;
+ u8 adc_mux;
};
struct axp20x_pinctrl_function {
@@ -79,6 +80,7 @@ static const struct axp20x_pctrl_desc axp20x_data = {
.ldo_mask = BIT(0) | BIT(1),
.adc_mask = BIT(0) | BIT(1),
.gpio_status_offset = 4,
+ .adc_mux = AXP20X_MUX_ADC,
};
static int axp20x_gpio_get_reg(unsigned int offset)
@@ -334,7 +336,7 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev)
* See comment in axp20x_pmx_set_mux.
*/
pctl->funcs[AXP20X_FUNC_ADC].name = "adc";
- pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+ pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux;
/* Every pin supports GPIO_OUT and GPIO_IN functions */
for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
--
2.14.1
^ permalink raw reply related
* [PATCH v5 8/9] pinctrl: axp209: add support for AXP813 GPIOs
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The AXP813 has only two GPIOs. GPIO0 can either be used as a GPIO, an
LDO regulator or an ADC. GPIO1 can be used either as a GPIO or an LDO
regulator.
Moreover, the status bit of the GPIOs when in input mode is not offset
by 4 unlike the AXP209.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/gpio/gpio-axp209.txt | 13 +++++++-
drivers/pinctrl/pinctrl-axp209.c | 35 +++++++++++++++++-----
2 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
index 0d77597c3f92..fc42b2caa06d 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
@@ -9,7 +9,9 @@ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
This driver employs the per-pin muxing pattern.
Required properties:
-- compatible: Should be "x-powers,axp209-gpio"
+- compatible: Should be one of:
+ - "x-powers,axp209-gpio"
+ - "x-powers,axp813-gpio"
- #gpio-cells: Should be two. The first cell is the pin number and the
second is the GPIO flags.
- gpio-controller: Marks the device node as a GPIO controller.
@@ -57,8 +59,17 @@ GPIOs and their functions
Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does
not force GPIO1 and GPIO2 to be in gpio_in function as well).
+axp209
+------
GPIO | Functions
------------------------
GPIO0 | gpio_in, gpio_out, ldo, adc
GPIO1 | gpio_in, gpio_out, ldo, adc
GPIO2 | gpio_in, gpio_out
+
+axp813
+------
+GPIO | Functions
+------------------------
+GPIO0 | gpio_in, gpio_out, ldo, adc
+GPIO1 | gpio_in, gpio_out, ldo
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 9bb8722ba90f..22d3bb0bf927 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -19,6 +19,7 @@
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -41,6 +42,8 @@
#define AXP20X_MUX_GPIO_IN BIT(1)
#define AXP20X_MUX_ADC BIT(2)
+#define AXP813_MUX_ADC (BIT(2) | BIT(0))
+
struct axp20x_pctrl_desc {
const struct pinctrl_pin_desc *pins;
unsigned int npins;
@@ -74,6 +77,11 @@ static const struct pinctrl_pin_desc axp209_pins[] = {
PINCTRL_PIN(2, "GPIO2"),
};
+static const struct pinctrl_pin_desc axp813_pins[] = {
+ PINCTRL_PIN(0, "GPIO0"),
+ PINCTRL_PIN(1, "GPIO1"),
+};
+
static const struct axp20x_pctrl_desc axp20x_data = {
.pins = axp209_pins,
.npins = ARRAY_SIZE(axp209_pins),
@@ -83,6 +91,15 @@ static const struct axp20x_pctrl_desc axp20x_data = {
.adc_mux = AXP20X_MUX_ADC,
};
+static const struct axp20x_pctrl_desc axp813_data = {
+ .pins = axp813_pins,
+ .npins = ARRAY_SIZE(axp813_pins),
+ .ldo_mask = BIT(0) | BIT(1),
+ .adc_mask = BIT(0),
+ .gpio_status_offset = 0,
+ .adc_mux = AXP813_MUX_ADC,
+};
+
static int axp20x_gpio_get_reg(unsigned int offset)
{
switch (offset) {
@@ -357,10 +374,18 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev)
pctl->desc->pins);
}
+static const struct of_device_id axp20x_pctl_match[] = {
+ { .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, },
+ { .compatible = "x-powers,axp813-gpio", .data = &axp813_data, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
+
static int axp20x_pctl_probe(struct platform_device *pdev)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
struct axp20x_pctl *pctl;
+ struct device *dev = &pdev->dev;
struct pinctrl_desc *pctrl_desc;
int ret;
@@ -388,9 +413,9 @@ static int axp20x_pctl_probe(struct platform_device *pdev)
pctl->chip.set = axp20x_gpio_set;
pctl->chip.direction_input = axp20x_gpio_input;
pctl->chip.direction_output = axp20x_gpio_output;
- pctl->chip.ngpio = 3;
+ pctl->chip.ngpio = pctl->desc->npins;
- pctl->desc = &axp20x_data;
+ pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev);
pctl->regmap = axp20x->regmap;
pctl->dev = &pdev->dev;
@@ -435,12 +460,6 @@ static int axp20x_pctl_probe(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id axp20x_pctl_match[] = {
- { .compatible = "x-powers,axp209-gpio" },
- { }
-};
-MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
-
static struct platform_driver axp20x_pctl_driver = {
.probe = axp20x_pctl_probe,
.driver = {
--
2.14.1
^ permalink raw reply related
* [PATCH v5 9/9] mfd: axp20x: add pinctrl cell for AXP813
From: Quentin Schulz @ 2017-12-05 14:46 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Quentin Schulz
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
As GPIO/pinctrl driver now supports AXP813, add a cell for it.
Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Acked-for-MFD-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/mfd/axp20x.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 2468b431bb22..d8c92fbbd170 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -878,6 +878,9 @@ static struct mfd_cell axp813_cells[] = {
.resources = axp803_pek_resources,
}, {
.name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-gpio",
+ .of_compatible = "x-powers,axp813-gpio",
}
};
--
2.14.1
^ permalink raw reply related
* Re: [PATCH v5 00/11] add pinmuxing support for pins in AXP209 and AXP813 PMICs
From: Quentin Schulz @ 2017-12-05 14:51 UTC (permalink / raw)
To: linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
lee.jones-QSEj5FYQhm4dnm+yROfE0A
Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <20171205144647.17594-1-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Hi all,
Copy pasting of the cover letter done wrong, there are only 9 patches in
this patch series unlike what's specified in the title of the cover
letter for this patch series.
Sorry for the noise.
Quentin
On 05/12/2017 15:46, Quentin Schulz wrote:
> The AXP209 and AXP813 PMICs have several pins (respectively 3 and 2) that can
> be used either as GPIOs or for other purposes (ADC or LDO here).
>
> We already have a GPIO driver for the GPIO use of those pins on the AXP209.
> Let's "upgrade" this driver to support all the functions these pins can have.
>
> Then we add support to this driver for the AXP813 which is slighlty different
> (basically a different offset in two registers and one less pin).
>
> I suggest patches 1 to 8 go through Linus's tree and 9 via Lee's.
>
> v5:
> - add reference to pinctrl dt-bindings in driver's dt-binding,
> - add statement that this driver employs per-pin muxing pattern,
> - add a patch on top of the patch series to fix checkpatch warnings,
> - add a few information to the Kconfig to make checkpatch happy,
>
> v4:
> - separate dt-binding patch when adding pinctrl feature,
> - use - instead of _ in DT node name,
> - remove muxing operation from pinctrl driver when choosing LDO mux in order
> to not interfere with the regulator framework,
> - add adc_mux to specify specific mux value for ADC (different between AXP209
> and AXP813),
> - misc modifications (header include reordering, unsigned int -> u8,
> new line removal),
>
> v3:
> - add defines for GPIO funcs,
> - use again get_regs function instead of drv_data (which was implemented in
> v2),
> - use of_device_id data for device specific data (gpio_status_offset and pins
> description),
> - change compatible from axp813-pctl to axp813-gpio,
> - use axp81x DT label instead of axp813 since AXP813 and AXP818 are similar,
> - add dtsi include for all boards embedding axp813/axp818,
>
> v2:
> - add support for AXP813 pins,
> - split into more patches so it is easier to follow the modifications,
> - reorder of some patches,
> - register all pins within the same range instead of a range per pin,
>
> Thanks,
> Quentin
>
> Quentin Schulz (9):
> gpio: axp209: switch unsigned variables to unsigned int
> pinctrl: move gpio-axp209 to pinctrl
> pinctrl: axp209: add pinctrl features
> dt-bindings: gpio: gpio-axp209: add pinctrl features
> pinctrl: axp209: rename everything from gpio to pctl
> pinctrl: axp209: add programmable gpio_status_offset
> pinctrl: axp209: add programmable ADC muxing value
> pinctrl: axp209: add support for AXP813 GPIOs
> mfd: axp20x: add pinctrl cell for AXP813
>
> .../devicetree/bindings/gpio/gpio-axp209.txt | 49 ++-
> drivers/gpio/Kconfig | 6 -
> drivers/gpio/Makefile | 1 -
> drivers/gpio/gpio-axp209.c | 188 --------
> drivers/mfd/axp20x.c | 3 +
> drivers/pinctrl/Kconfig | 10 +
> drivers/pinctrl/Makefile | 1 +
> drivers/pinctrl/pinctrl-axp209.c | 476 +++++++++++++++++++++
> 8 files changed, 537 insertions(+), 197 deletions(-)
> delete mode 100644 drivers/gpio/gpio-axp209.c
> create mode 100644 drivers/pinctrl/pinctrl-axp209.c
>
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH net-next v3 1/4] phylib: Add device reset delay support
From: Richard Leitner @ 2017-12-05 14:56 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Richard Leitner, Rob Herring, Mark Rutland, Fugang Duan,
Andrew Lunn, Florian Fainelli, Frank Rowand, David S. Miller,
Geert Uytterhoeven, Sergei Shtylyov, Baruch Siach, David Wu,
lukma-ynQEQJNshbs, netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMuHMdX70yuEfoDL+Y4TZ-6zjyW9BqvKOU6UxbHTKGNcgfGrow-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Geert,
On 12/05/2017 02:54 PM, Geert Uytterhoeven wrote:
> Hi Richard,
>
> On Tue, Dec 5, 2017 at 2:25 PM, Richard Leitner <dev-M/VWbR8SM2SsTnJN9+BGXg@public.gmane.org> wrote:
>> From: Richard Leitner <richard.leitner-WcANXNA0UjBBDgjK7y7TUQ@public.gmane.org>
>>
>> Some PHYs need a minimum time after the reset gpio was asserted and/or
>> deasserted. To ensure we meet these timing requirements add two new
>> optional devicetree parameters for the phy: reset-delay-us and
>> reset-post-delay-us.
>
> Thanks for your patch!
>
>> This patch depends on the "phylib: Add device reset GPIO support" patch
>> submitted by Geert Uytterhoeven/Sergei Shtylyov, see:
>> https://patchwork.kernel.org/patch/10090149/
>
> The above paragraph belongs under the "---" line below, as it is not intended
> to be preserved in the eternal git history.
Ok. Thanks. That makes sense. I'll take it into account for v4.
>
>> Signed-off-by: Richard Leitner <richard.leitner-WcANXNA0UjBBDgjK7y7TUQ@public.gmane.org>
>
> Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>
>
> Although I have a few suggestions below:
Thank you for your review and suggestions (they make the code look way
more neater). I'll adapt v4 accordingly.
>
>> --- a/drivers/net/phy/mdio_device.c
>> +++ b/drivers/net/phy/mdio_device.c
>> @@ -118,8 +119,16 @@ EXPORT_SYMBOL(mdio_device_remove);
>>
>> void mdio_device_reset(struct mdio_device *mdiodev, int value)
>> {
>> - if (mdiodev->reset)
>> - gpiod_set_value(mdiodev->reset, value);
>> + if (!mdiodev->reset)
>> + return;
>> +
>> + gpiod_set_value(mdiodev->reset, value);
>> +
>> + if (value && mdiodev->reset_delay)
>> + usleep_range(mdiodev->reset_delay, mdiodev->reset_delay + 100);
>> + else if (!value && mdiodev->reset_post_delay)
>> + usleep_range(mdiodev->reset_post_delay,
>> + mdiodev->reset_post_delay + 100);
>
> I think this can be written simpler using e.g.:
>
> unsigned int delay;
>
> ...
> delay = value ? mdiodev->reset_delay : mdiodev->reset_post_delay;
> if (delay)
> usleep_range(delay, delay + 100);
>
> Perhaps the range extension should be relative, e.g.
> "delay + min(delay / 10, 100)"?
>
>> --- a/drivers/of/of_mdio.c
>> +++ b/drivers/of/of_mdio.c
>> @@ -77,6 +77,14 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio,
>> if (of_property_read_bool(child, "broken-turn-around"))
>> mdio->phy_ignore_ta_mask |= 1 << addr;
>>
>> + if (of_property_read_u32(child, "reset-delay-us",
>> + &phy->mdio.reset_delay))
>> + phy->mdio.reset_delay = 0;
>> +
>> + if (of_property_read_u32(child, "reset-post-delay-us",
>> + &phy->mdio.reset_post_delay))
>> + phy->mdio.reset_post_delay = 0;
>
> If of_property_read_u32() fails, it doesn't write to its output parameter.
> As the structure should be zeroed during allocation, you can just write:
>
> of_property_read_u32(child, "reset-delay-us", &phy->mdio.reset_delay);
> of_property_read_u32(child, "reset-post-delay-us",
> &phy->mdio.reset_post_delay);
--
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 v3 00/15] drm/sun4i: Add A83t LVDS support
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
Hi,
Here is an attempt at supporting the LVDS output in our DRM driver. This
has been tested on the A83T (with DE2), but since everything is basically
in the TCON, it should also be usable on the older SoCs with minor
modifications.
This was the occasion to refactor a bunch of things. The most notable ones
would be the documentation, and split of the UI layers in the mixer code,
and the switch to kfifo for our endpoint parsing code in the driver that
fixes an issue introduced by the switch to BFS.
Let me know what you think,
Maxime
Changes from v2:
- Move the module clock rate to the mixer structure
- Adjusted the simple-panel documentation for power-supply
- Changed the compatible for the first A83t mixer to mixer 0
- Rebased on top of current drm-misc
- Split out the A83t bindings in its separate patch
Changes from v1:
- Added a fix for the error path handling in the TCON
- Enable the TCON by default
- Removed the patch that changes the channels offset but kept most of the
modifications as a cleanup
- Deal with the LVDS clock being able to have another PLL parent on some
SoCs
- Renamed the TCON compatible to TCON-TV, following the convention used
on newer SoCs
- Removed the hardcoded timings
- Moved LVDS enable quirks to a separate function
- Used clock indices define in the DT
- Removed the hardcoded clock rate in the DT and moved it to the driver
- Changed sun8i_mixer_planes to sun8i_mixer_ui_planes to be consistent
- Added the various tags collected
- Rebased on top of 4.15
Maxime Ripard (15):
dt-bindings: panel: lvds: Document power-supply property
drm/panel: lvds: Add support for the power-supply property
dt-bindings: display: sun4i-drm: Add LVDS properties
dt-bindings: display: sun4i-drm: Add A83T pipeline
drm/sun4i: Fix error path handling
drm/sun4i: Force the mixer rate at 150MHz
drm/sun4i: Create minimal multipliers and dividers
drm/sun4i: Add LVDS support
drm/sun4i: Add A83T support
ARM: dts: sun8i: a83t: Add display pipeline
ARM: dts: sun8i: a83t: Enable the PWM
ARM: dts: sun8i: a83t: Add LVDS pins group
ARM: dts: sun8i: a83t: Add the PWM pin group
ARM: dts: sun8i: a711: Reinstate the PMIC compatible
ARM: dts: sun8i: a711: Enable the LCD
Documentation/devicetree/bindings/display/panel/panel-common.txt | 6 ++-
Documentation/devicetree/bindings/display/panel/panel-lvds.txt | 1 +-
Documentation/devicetree/bindings/display/panel/simple-panel.txt | 2 +-
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 11 +++-
arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts | 62 ++++++++++++++++++-
arch/arm/boot/dts/sun8i-a83t.dtsi | 99 +++++++++++++++++++++++++++++-
drivers/gpu/drm/panel/panel-lvds.c | 23 +++++++-
drivers/gpu/drm/sun4i/Makefile | 1 +-
drivers/gpu/drm/sun4i/sun4i_dotclock.c | 10 ++-
drivers/gpu/drm/sun4i/sun4i_drv.c | 1 +-
drivers/gpu/drm/sun4i/sun4i_lvds.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_lvds.h | 18 +++++-
drivers/gpu/drm/sun4i/sun4i_tcon.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_tcon.h | 31 +++++++++-
drivers/gpu/drm/sun4i/sun8i_mixer.c | 18 +++++-
drivers/gpu/drm/sun4i/sun8i_mixer.h | 3 +-
16 files changed, 709 insertions(+), 7 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.c
create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.h
base-commit: 3b71239181e5429702387666f1ac70a9e6856cce
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [PATCH v3 01/15] dt-bindings: panel: lvds: Document power-supply property
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The power-supply property is used by a vast majority of panels, including
panel-simple. Let's document it as a common property
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Documentation/devicetree/bindings/display/panel/panel-common.txt | 6 ++++++
Documentation/devicetree/bindings/display/panel/panel-lvds.txt | 1 +
Documentation/devicetree/bindings/display/panel/simple-panel.txt | 2 +-
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.txt b/Documentation/devicetree/bindings/display/panel/panel-common.txt
index ec52c472c845..125ea68052af 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-common.txt
+++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt
@@ -78,6 +78,12 @@ used for panels that implement compatible control signals.
while active. Active high reset signals can be supported by inverting the
GPIO specifier polarity flag.
+Power
+-----
+
+- power-supply: many display panels need an additional power supply in
+ order to be fully powered-up. For such panels, power-supply contains
+ a phandle to the regulator powering the panel.
Backlight
---------
diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.txt b/Documentation/devicetree/bindings/display/panel/panel-lvds.txt
index b938269f841e..250850a2150b 100644
--- a/Documentation/devicetree/bindings/display/panel/panel-lvds.txt
+++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.txt
@@ -32,6 +32,7 @@ Optional properties:
- label: See panel-common.txt.
- gpios: See panel-common.txt.
- backlight: See panel-common.txt.
+- power-supply: See panel-common.txt.
- data-mirror: If set, reverse the bit order described in the data mappings
below on all data lanes, transmitting bits for slots 6 to 0 instead of
0 to 6.
diff --git a/Documentation/devicetree/bindings/display/panel/simple-panel.txt b/Documentation/devicetree/bindings/display/panel/simple-panel.txt
index 1341bbf4aa3d..16d8ff088b7d 100644
--- a/Documentation/devicetree/bindings/display/panel/simple-panel.txt
+++ b/Documentation/devicetree/bindings/display/panel/simple-panel.txt
@@ -1,7 +1,7 @@
Simple display panel
Required properties:
-- power-supply: regulator to provide the supply voltage
+- power-supply: See panel-common.txt
Optional properties:
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 02/15] drm/panel: lvds: Add support for the power-supply property
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mark Rutland, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
plaes-q/aMd4JkU83YtjvyW6yDsg, icenowy-h8G6r0blFSE,
Thomas Petazzoni, jernej.skrabec-gGgVlfcn5nU,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
A significant number of panels need to power up a regulator in order to
operate properly. Add support for the power-supply property to enable and
disable such a regulator whenever needed.
Reviewed-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/gpu/drm/panel/panel-lvds.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c
index e2d57c01200b..57e38a9e7ab4 100644
--- a/drivers/gpu/drm/panel/panel-lvds.c
+++ b/drivers/gpu/drm/panel/panel-lvds.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <drm/drmP.h>
@@ -39,6 +40,7 @@ struct panel_lvds {
bool data_mirror;
struct backlight_device *backlight;
+ struct regulator *supply;
struct gpio_desc *enable_gpio;
struct gpio_desc *reset_gpio;
@@ -69,6 +71,9 @@ static int panel_lvds_unprepare(struct drm_panel *panel)
if (lvds->enable_gpio)
gpiod_set_value_cansleep(lvds->enable_gpio, 0);
+ if (lvds->supply)
+ regulator_disable(lvds->supply);
+
return 0;
}
@@ -76,6 +81,17 @@ static int panel_lvds_prepare(struct drm_panel *panel)
{
struct panel_lvds *lvds = to_panel_lvds(panel);
+ if (lvds->supply) {
+ int err;
+
+ err = regulator_enable(lvds->supply);
+ if (err < 0) {
+ dev_err(lvds->dev, "failed to enable supply: %d\n",
+ err);
+ return err;
+ }
+ }
+
if (lvds->enable_gpio)
gpiod_set_value_cansleep(lvds->enable_gpio, 1);
@@ -196,6 +212,13 @@ static int panel_lvds_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ lvds->supply = devm_regulator_get_optional(lvds->dev, "power");
+ if (IS_ERR(lvds->supply)) {
+ ret = PTR_ERR(lvds->supply);
+ dev_err(lvds->dev, "failed to request regulator: %d\n", ret);
+ return ret;
+ }
+
/* Get GPIOs and backlight controller. */
lvds->enable_gpio = devm_gpiod_get_optional(lvds->dev, "enable",
GPIOD_OUT_LOW);
--
git-series 0.9.1
--
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 related
* [PATCH v3 03/15] dt-bindings: display: sun4i-drm: Add LVDS properties
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
Some clocks and resets supposed to drive the LVDS logic in the display
engine have been overlooked when the driver was first introduced.
Add those additional resources to the binding, and we'll deal with the ABI
stability in the code.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 8 +++++++-
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 50cc72ee1168..d4259a4f5171 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -121,6 +121,14 @@ Required properties:
On SoCs other than the A33 and V3s, there is one more clock required:
- 'tcon-ch1': The clock driving the TCON channel 1
+On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you
+need one more reset line:
+ - 'lvds': The reset line driving the LVDS logic
+
+And on the SoCs newer than the A31 (sun6i and sun8i families), you
+need one more clock line:
+ - 'lvds-pll': The PLL that can be used to drive the LVDS clock
+
DRC
---
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 04/15] dt-bindings: display: sun4i-drm: Add A83T pipeline
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The A83T has two video pipelines in parallel that looks quite similar to
the other SoCs.
The video planes are handled through a controller called the mixer, and the
video signal is then passed to the timing controller (TCON).
And while there is two instances of the mixers and TCONs, they have a
significant number of differences. The TCONs are quite easy to deal with,
one is supposed to generate TV (in the broader term, so including things
like HDMI) signals, the other one LCD (so RGB, LVDS, DSI) signals. And
while they are called TCON0 and TCON1 in the A83t datasheet, newer SoCs
call them TCON-TV and TCON-LCD, which seems more appropriate.
However, the mixers differ mostly by their capabilities, with some features
being available only in the first one, or the number of planes they expose,
but also through their register layout. And while the capabilities could be
represented as properties, the register layout differences would need to
express all the registers offsets as properties, which is usually quite
bad. Especially since documentation on that hardware block is close to
non-existant and we don't even have the list of all those registers in the
first place.
So let's call them mixer 0 and 1 in our compatibles, even though the name
is pretty bad...
At the moment, we only have tested the code on a board that has a single
display output, so we're leaving the tcon-tv and mixer1 out.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index d4259a4f5171..338cb6bbf25c 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -93,6 +93,7 @@ Required properties:
* allwinner,sun6i-a31s-tcon
* allwinner,sun7i-a20-tcon
* allwinner,sun8i-a33-tcon
+ * allwinner,sun8i-a83t-tcon-lcd
* allwinner,sun8i-v3s-tcon
- reg: base address and size of memory-mapped region
- interrupts: interrupt associated to this IP
@@ -224,6 +225,7 @@ supported.
Required properties:
- compatible: value must be one of:
+ * allwinner,sun8i-a83t-de2-mixer-0
* allwinner,sun8i-v3s-de2-mixer
- reg: base address and size of the memory-mapped region.
- clocks: phandles to the clocks feeding the mixer
@@ -253,6 +255,7 @@ Required properties:
* allwinner,sun6i-a31s-display-engine
* allwinner,sun7i-a20-display-engine
* allwinner,sun8i-a33-display-engine
+ * allwinner,sun8i-a83t-display-engine
* allwinner,sun8i-v3s-display-engine
- allwinner,pipelines: list of phandle to the display engine
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 05/15] drm/sun4i: Fix error path handling
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, stable, linux-arm-kernel,
icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The commit 4c7f16d14a33 ("drm/sun4i: Fix TCON clock and regmap
initialization sequence") moved a bunch of logic around, but forgot to
update the gotos after the introduction of the err_free_dotclock label.
It means that if we fail later that the one introduced in that commit,
we'll just to the old label which isn't free the clock we created. This
will result in a breakage as soon as someone tries to do something with
that clock, since its resources will have been long reclaimed.
Cc: <stable@vger.kernel.org>
Fixes: 4c7f16d14a33 ("drm/sun4i: Fix TCON clock and regmap initialization sequence")
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a1ed462c2430..ea056a3d2131 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -724,12 +724,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
if (IS_ERR(tcon->crtc)) {
dev_err(dev, "Couldn't create our CRTC\n");
ret = PTR_ERR(tcon->crtc);
- goto err_free_clocks;
+ goto err_free_dotclock;
}
ret = sun4i_rgb_init(drm, tcon);
if (ret < 0)
- goto err_free_clocks;
+ goto err_free_dotclock;
if (tcon->quirks->needs_de_be_mux) {
/*
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 06/15] drm/sun4i: Force the mixer rate at 150MHz
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
It seems like the mixer can only run properly when clocked at 150MHz. In
order to have something more robust than simply a fire-and-forget
assigned-clocks-rate, let's put that in the code.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 9 +++++++++
drivers/gpu/drm/sun4i/sun8i_mixer.h | 3 +++
2 files changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 29ceeb016d72..ff235e3228ce 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -400,6 +400,14 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
}
clk_prepare_enable(mixer->mod_clk);
+ /*
+ * It seems that we need to enforce that rate for whatever
+ * reason for the mixer to be functional. Make sure it's the
+ * case.
+ */
+ if (mixer->cfg->mod_rate)
+ clk_set_rate(mixer->mod_clk, mixer->cfg->mod_rate);
+
list_add_tail(&mixer->engine.list, &drv->engine_list);
/* Reset the registers */
@@ -474,6 +482,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.ui_num = 1,
.scaler_mask = 0x3,
.ccsc = 0,
+ .mod_rate = 150000000,
};
static const struct of_device_id sun8i_mixer_of_table[] = {
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index bc58040a88f9..f34e70c42adf 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -121,12 +121,15 @@ struct de2_fmt_info {
* Set value to 0 if this is first mixer or second mixer with VEP support.
* Set value to 1 if this is second mixer without VEP support. Other values
* are invalid.
+ * @mod_rate: module clock rate that needs to be set in order to have
+ * a functional block.
*/
struct sun8i_mixer_cfg {
int vi_num;
int ui_num;
int scaler_mask;
int ccsc;
+ unsigned long mod_rate;
};
struct sun8i_mixer {
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 07/15] drm/sun4i: Create minimal multipliers and dividers
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The various outputs the TCON can provide have different constraints on the
dotclock divider. Let's make them configurable by the various mode_set
functions.
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_dotclock.c | 10 +++++++---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 2 ++
drivers/gpu/drm/sun4i/sun4i_tcon.h | 2 ++
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
index d401156490f3..023f39bda633 100644
--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
+++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
@@ -17,8 +17,9 @@
#include "sun4i_dotclock.h"
struct sun4i_dclk {
- struct clk_hw hw;
- struct regmap *regmap;
+ struct clk_hw hw;
+ struct regmap *regmap;
+ struct sun4i_tcon *tcon;
};
static inline struct sun4i_dclk *hw_to_dclk(struct clk_hw *hw)
@@ -73,11 +74,13 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
+ struct sun4i_dclk *dclk = hw_to_dclk(hw);
+ struct sun4i_tcon *tcon = dclk->tcon;
unsigned long best_parent = 0;
u8 best_div = 1;
int i;
- for (i = 6; i <= 127; i++) {
+ for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) {
unsigned long ideal = rate * i;
unsigned long rounded;
@@ -167,6 +170,7 @@ int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon)
dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL);
if (!dclk)
return -ENOMEM;
+ dclk->tcon = tcon;
init.name = clk_name;
init.ops = &sun4i_dclk_ops;
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index ea056a3d2131..46e28ca1f676 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -177,6 +177,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
u8 clk_delay;
u32 val = 0;
+ tcon->dclk_min_div = 6;
+ tcon->dclk_max_div = 127;
sun4i_tcon0_mode_set_common(tcon, mode);
/* Adjust clock delay */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 839266a38505..bd3ad7684870 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -169,6 +169,8 @@ struct sun4i_tcon {
/* Pixel clock */
struct clk *dclk;
+ u8 dclk_max_div;
+ u8 dclk_min_div;
/* Reset control */
struct reset_control *lcd_rst;
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 08/15] drm/sun4i: Add LVDS support
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mark Rutland, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
plaes-q/aMd4JkU83YtjvyW6yDsg, icenowy-h8G6r0blFSE,
Thomas Petazzoni, jernej.skrabec-gGgVlfcn5nU,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The TCON supports the LVDS interface to output to a panel or a bridge.
Let's add support for it.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/gpu/drm/sun4i/Makefile | 1 +-
drivers/gpu/drm/sun4i/sun4i_lvds.c | 183 +++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_lvds.h | 18 ++-
drivers/gpu/drm/sun4i/sun4i_tcon.c | 238 +++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun4i_tcon.h | 29 ++++-
5 files changed, 467 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.c
create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.h
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 82a6ac57fbe3..2b37a6abbb1d 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -15,6 +15,7 @@ sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun4i-tcon-y += sun4i_crtc.o
sun4i-tcon-y += sun4i_dotclock.o
+sun4i-tcon-y += sun4i_lvds.o
sun4i-tcon-y += sun4i_tcon.o
sun4i-tcon-y += sun4i_rgb.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
new file mode 100644
index 000000000000..635a3f505ecb
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 NextThing Co
+ * Copyright (C) 2015-2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@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 as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+
+#include "sun4i_crtc.h"
+#include "sun4i_tcon.h"
+#include "sun4i_lvds.h"
+
+struct sun4i_lvds {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+
+ struct sun4i_tcon *tcon;
+};
+
+static inline struct sun4i_lvds *
+drm_connector_to_sun4i_lvds(struct drm_connector *connector)
+{
+ return container_of(connector, struct sun4i_lvds,
+ connector);
+}
+
+static inline struct sun4i_lvds *
+drm_encoder_to_sun4i_lvds(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct sun4i_lvds,
+ encoder);
+}
+
+static int sun4i_lvds_get_modes(struct drm_connector *connector)
+{
+ struct sun4i_lvds *lvds =
+ drm_connector_to_sun4i_lvds(connector);
+ struct sun4i_tcon *tcon = lvds->tcon;
+
+ return drm_panel_get_modes(tcon->panel);
+}
+
+static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = {
+ .get_modes = sun4i_lvds_get_modes,
+};
+
+static void
+sun4i_lvds_connector_destroy(struct drm_connector *connector)
+{
+ struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector);
+ struct sun4i_tcon *tcon = lvds->tcon;
+
+ drm_panel_detach(tcon->panel);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs sun4i_lvds_con_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = sun4i_lvds_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static void sun4i_lvds_encoder_enable(struct drm_encoder *encoder)
+{
+ struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(encoder);
+ struct sun4i_tcon *tcon = lvds->tcon;
+
+ DRM_DEBUG_DRIVER("Enabling LVDS output\n");
+
+ if (!IS_ERR(tcon->panel)) {
+ drm_panel_prepare(tcon->panel);
+ drm_panel_enable(tcon->panel);
+ }
+}
+
+static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder)
+{
+ struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(encoder);
+ struct sun4i_tcon *tcon = lvds->tcon;
+
+ DRM_DEBUG_DRIVER("Disabling LVDS output\n");
+
+ if (!IS_ERR(tcon->panel)) {
+ drm_panel_disable(tcon->panel);
+ drm_panel_unprepare(tcon->panel);
+ }
+}
+
+static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = {
+ .disable = sun4i_lvds_encoder_disable,
+ .enable = sun4i_lvds_encoder_enable,
+};
+
+static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon)
+{
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+ struct sun4i_lvds *lvds;
+ int ret;
+
+ lvds = devm_kzalloc(drm->dev, sizeof(*lvds), GFP_KERNEL);
+ if (!lvds)
+ return -ENOMEM;
+ lvds->tcon = tcon;
+ encoder = &lvds->encoder;
+
+ ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0,
+ &tcon->panel, &bridge);
+ if (ret) {
+ dev_info(drm->dev, "No panel or bridge found... LVDS output disabled\n");
+ return 0;
+ }
+
+ drm_encoder_helper_add(&lvds->encoder,
+ &sun4i_lvds_enc_helper_funcs);
+ ret = drm_encoder_init(drm,
+ &lvds->encoder,
+ &sun4i_lvds_enc_funcs,
+ DRM_MODE_ENCODER_LVDS,
+ NULL);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't initialise the lvds encoder\n");
+ goto err_out;
+ }
+
+ /* The LVDS encoder can only work with the TCON channel 0 */
+ lvds->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc));
+
+ if (tcon->panel) {
+ drm_connector_helper_add(&lvds->connector,
+ &sun4i_lvds_con_helper_funcs);
+ ret = drm_connector_init(drm, &lvds->connector,
+ &sun4i_lvds_con_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't initialise the lvds connector\n");
+ goto err_cleanup_connector;
+ }
+
+ drm_mode_connector_attach_encoder(&lvds->connector,
+ &lvds->encoder);
+
+ ret = drm_panel_attach(tcon->panel, &lvds->connector);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't attach our panel\n");
+ goto err_cleanup_connector;
+ }
+ }
+
+ if (bridge) {
+ ret = drm_bridge_attach(encoder, bridge, NULL);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't attach our bridge\n");
+ goto err_cleanup_connector;
+ }
+ }
+
+ return 0;
+
+err_cleanup_connector:
+ drm_encoder_cleanup(&lvds->encoder);
+err_out:
+ return ret;
+}
+EXPORT_SYMBOL(sun4i_lvds_init);
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.h b/drivers/gpu/drm/sun4i/sun4i_lvds.h
new file mode 100644
index 000000000000..1b8fad4b82c3
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_lvds.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 NextThing Co
+ * Copyright (C) 2015-2017 Free Electrons
+ *
+ * Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@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 as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_LVDS_H_
+#define _SUN4I_LVDS_H_
+
+int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon);
+
+#endif /* _SUN4I_LVDS_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 46e28ca1f676..92f4738101e6 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -31,10 +31,52 @@
#include "sun4i_crtc.h"
#include "sun4i_dotclock.h"
#include "sun4i_drv.h"
+#include "sun4i_lvds.h"
#include "sun4i_rgb.h"
#include "sun4i_tcon.h"
#include "sunxi_engine.h"
+static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
+{
+ struct drm_connector *connector;
+ struct drm_connector_list_iter iter;
+
+ drm_connector_list_iter_begin(encoder->dev, &iter);
+ drm_for_each_connector_iter(connector, &iter)
+ if (connector->encoder == encoder) {
+ drm_connector_list_iter_end(&iter);
+ return connector;
+ }
+ drm_connector_list_iter_end(&iter);
+
+ return NULL;
+}
+
+static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)
+{
+ struct drm_connector *connector;
+ struct drm_display_info *info;
+
+ connector = sun4i_tcon_get_connector(encoder);
+ if (!connector)
+ return -EINVAL;
+
+ info = &connector->display_info;
+ if (info->num_bus_formats != 1)
+ return -EINVAL;
+
+ switch (info->bus_formats[0]) {
+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
+ return 18;
+
+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
+ return 24;
+ }
+
+ return -EINVAL;
+}
+
static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
bool enabled)
{
@@ -65,13 +107,58 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
clk_disable_unprepare(clk);
}
+static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
+ const struct drm_encoder *encoder,
+ bool enabled)
+{
+ if (enabled) {
+ u8 val;
+
+ regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
+ SUN4I_TCON0_LVDS_IF_EN,
+ SUN4I_TCON0_LVDS_IF_EN);
+
+ regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
+ SUN4I_TCON0_LVDS_ANA0_C(2) |
+ SUN4I_TCON0_LVDS_ANA0_V(3) |
+ SUN4I_TCON0_LVDS_ANA0_PD(2) |
+ SUN4I_TCON0_LVDS_ANA0_EN_LDO);
+ udelay(2);
+
+ regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
+ SUN4I_TCON0_LVDS_ANA0_EN_MB,
+ SUN4I_TCON0_LVDS_ANA0_EN_MB);
+ udelay(2);
+
+ regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
+ SUN4I_TCON0_LVDS_ANA0_EN_DRVC,
+ SUN4I_TCON0_LVDS_ANA0_EN_DRVC);
+
+ if (sun4i_tcon_get_pixel_depth(encoder) == 18)
+ val = 7;
+ else
+ val = 0xf;
+
+ regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
+ SUN4I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
+ SUN4I_TCON0_LVDS_ANA0_EN_DRVD(val));
+ } else {
+ regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
+ SUN4I_TCON0_LVDS_IF_EN, 0);
+ }
+}
+
void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
const struct drm_encoder *encoder,
bool enabled)
{
+ bool is_lvds = false;
int channel;
switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_LVDS:
+ is_lvds = true;
+ /* Fallthrough */
case DRM_MODE_ENCODER_NONE:
channel = 0;
break;
@@ -84,10 +171,16 @@ void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
return;
}
+ if (is_lvds && !enabled)
+ sun4i_tcon_lvds_set_status(tcon, encoder, false);
+
regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
SUN4I_TCON_GCTL_TCON_ENABLE,
enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
+ if (is_lvds && enabled)
+ sun4i_tcon_lvds_set_status(tcon, encoder, true);
+
sun4i_tcon_channel_set_status(tcon, channel, enabled);
}
@@ -170,6 +263,78 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
}
+static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
+ const struct drm_encoder *encoder,
+ const struct drm_display_mode *mode)
+{
+ unsigned int bp;
+ u8 clk_delay;
+ u32 reg, val = 0;
+
+ tcon->dclk_min_div = 7;
+ tcon->dclk_max_div = 7;
+ sun4i_tcon0_mode_set_common(tcon, mode);
+
+ /* Adjust clock delay */
+ clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
+ regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
+ SUN4I_TCON0_CTL_CLK_DELAY_MASK,
+ SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
+
+ /*
+ * This is called a backporch in the register documentation,
+ * but it really is the back porch + hsync
+ */
+ bp = mode->crtc_htotal - mode->crtc_hsync_start;
+ DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
+ mode->crtc_htotal, bp);
+
+ /* Set horizontal display timings */
+ regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
+ SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |
+ SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
+
+ /*
+ * This is called a backporch in the register documentation,
+ * but it really is the back porch + hsync
+ */
+ bp = mode->crtc_vtotal - mode->crtc_vsync_start;
+ DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
+ mode->crtc_vtotal, bp);
+
+ /* Set vertical display timings */
+ regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
+ SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
+ SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
+
+ reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 |
+ SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL |
+ SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL;
+ if (sun4i_tcon_get_pixel_depth(encoder) == 24)
+ reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;
+ else
+ reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;
+
+ regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);
+
+ /* Setup the polarity of the various signals */
+ if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+ val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
+
+ if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+ val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
+
+ regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
+
+ /* Map output pins to channel 0 */
+ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+ SUN4I_TCON_GCTL_IOMAP_MASK,
+ SUN4I_TCON_GCTL_IOMAP_TCON0);
+
+ /* Enable the output on the pins */
+ regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);
+}
+
static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
const struct drm_display_mode *mode)
{
@@ -336,6 +501,9 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
const struct drm_display_mode *mode)
{
switch (encoder->encoder_type) {
+ case DRM_MODE_ENCODER_LVDS:
+ sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
+ break;
case DRM_MODE_ENCODER_NONE:
sun4i_tcon0_mode_set_rgb(tcon, mode);
sun4i_tcon_set_mux(tcon, 0, encoder);
@@ -667,7 +835,9 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct sun4i_drv *drv = drm->dev_private;
struct sunxi_engine *engine;
+ struct device_node *remote;
struct sun4i_tcon *tcon;
+ bool has_lvds_rst, has_lvds_pll, can_lvds;
int ret;
engine = sun4i_tcon_find_engine(drv, dev->of_node);
@@ -698,6 +868,54 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
return ret;
}
+ /*
+ * This can only be made optional since we've had DT nodes
+ * without the LVDS reset properties.
+ *
+ * If the property is missing, just disable LVDS, and print a
+ * warning.
+ */
+ tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
+ if (IS_ERR(tcon->lvds_rst)) {
+ dev_err(dev, "Couldn't get our reset line\n");
+ return PTR_ERR(tcon->lvds_rst);
+ } else if (tcon->lvds_rst) {
+ has_lvds_rst = true;
+ reset_control_reset(tcon->lvds_rst);
+ } else {
+ has_lvds_rst = false;
+ }
+
+ /*
+ * This can only be made optional since we've had DT nodes
+ * without the LVDS reset properties.
+ *
+ * If the property is missing, just disable LVDS, and print a
+ * warning.
+ */
+ if (tcon->quirks->has_lvds_pll) {
+ tcon->lvds_pll = devm_clk_get(dev, "pll-lvds");
+ if (IS_ERR(tcon->lvds_pll)) {
+ if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
+ has_lvds_pll = false;
+ } else {
+ dev_err(dev, "Couldn't get the LVDS PLL\n");
+ return PTR_ERR(tcon->lvds_rst);
+ }
+ } else {
+ has_lvds_pll = true;
+ }
+ }
+
+ if (!has_lvds_rst || (tcon->quirks->has_lvds_pll && !has_lvds_pll)) {
+ dev_warn(dev,
+ "Missing LVDS properties, Please upgrade your DT\n");
+ dev_warn(dev, "LVDS output disabled\n");
+ can_lvds = false;
+ } else {
+ can_lvds = true;
+ }
+
ret = sun4i_tcon_init_clocks(dev, tcon);
if (ret) {
dev_err(dev, "Couldn't init our TCON clocks\n");
@@ -729,7 +947,21 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
goto err_free_dotclock;
}
- ret = sun4i_rgb_init(drm, tcon);
+ /*
+ * If we have an LVDS panel connected to the TCON, we should
+ * just probe the LVDS connector. Otherwise, just probe RGB as
+ * we used to.
+ */
+ remote = of_graph_get_remote_node(dev->of_node, 1, 0);
+ if (of_device_is_compatible(remote, "panel-lvds"))
+ if (can_lvds)
+ ret = sun4i_lvds_init(drm, tcon);
+ else
+ ret = -EINVAL;
+ else
+ ret = sun4i_rgb_init(drm, tcon);
+ of_node_put(remote);
+
if (ret < 0)
goto err_free_dotclock;
@@ -879,12 +1111,14 @@ static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
.has_channel_1 = true,
+ .has_lvds_pll = true,
.needs_de_be_mux = true,
.set_mux = sun6i_tcon_set_mux,
};
static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
.has_channel_1 = true,
+ .has_lvds_pll = true,
.needs_de_be_mux = true,
};
@@ -895,7 +1129,7 @@ static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
};
static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
- /* nothing is supported */
+ .has_lvds_pll = true,
};
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index bd3ad7684870..6e801a6325a1 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -70,7 +70,21 @@
#define SUN4I_TCON0_TTL2_REG 0x78
#define SUN4I_TCON0_TTL3_REG 0x7c
#define SUN4I_TCON0_TTL4_REG 0x80
+
#define SUN4I_TCON0_LVDS_IF_REG 0x84
+#define SUN4I_TCON0_LVDS_IF_EN BIT(31)
+#define SUN4I_TCON0_LVDS_IF_BITWIDTH_MASK BIT(26)
+#define SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS (1 << 26)
+#define SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS (0 << 26)
+#define SUN4I_TCON0_LVDS_IF_CLK_SEL_MASK BIT(20)
+#define SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 (1 << 20)
+#define SUN4I_TCON0_LVDS_IF_CLK_POL_MASK BIT(4)
+#define SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL (1 << 4)
+#define SUN4I_TCON0_LVDS_IF_CLK_POL_INV (0 << 4)
+#define SUN4I_TCON0_LVDS_IF_DATA_POL_MASK GENMASK(3, 0)
+#define SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL (0xf)
+#define SUN4I_TCON0_LVDS_IF_DATA_POL_INV (0)
+
#define SUN4I_TCON0_IO_POL_REG 0x88
#define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase) ((phase & 3) << 28)
#define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE BIT(25)
@@ -131,6 +145,16 @@
#define SUN4I_TCON_CEU_RANGE_G_REG 0x144
#define SUN4I_TCON_CEU_RANGE_B_REG 0x148
#define SUN4I_TCON_MUX_CTRL_REG 0x200
+
+#define SUN4I_TCON0_LVDS_ANA0_REG 0x220
+#define SUN4I_TCON0_LVDS_ANA0_EN_MB BIT(31)
+#define SUN4I_TCON0_LVDS_ANA0_EN_LDO BIT(30)
+#define SUN4I_TCON0_LVDS_ANA0_EN_DRVC BIT(24)
+#define SUN4I_TCON0_LVDS_ANA0_EN_DRVD(x) (((x) & 0xf) << 20)
+#define SUN4I_TCON0_LVDS_ANA0_C(x) (((x) & 3) << 17)
+#define SUN4I_TCON0_LVDS_ANA0_V(x) (((x) & 3) << 8)
+#define SUN4I_TCON0_LVDS_ANA0_PD(x) (((x) & 3) << 4)
+
#define SUN4I_TCON1_FILL_CTL_REG 0x300
#define SUN4I_TCON1_FILL_BEG0_REG 0x304
#define SUN4I_TCON1_FILL_END0_REG 0x308
@@ -149,6 +173,7 @@ struct sun4i_tcon;
struct sun4i_tcon_quirks {
bool has_channel_1; /* a33 does not have channel 1 */
+ bool has_lvds_pll; /* Can we mux the LVDS clock to a PLL? */
bool needs_de_be_mux; /* sun6i needs mux to select backend */
/* callback to handle tcon muxing options */
@@ -167,6 +192,9 @@ struct sun4i_tcon {
struct clk *sclk0;
struct clk *sclk1;
+ /* Possible mux for the LVDS clock */
+ struct clk *lvds_pll;
+
/* Pixel clock */
struct clk *dclk;
u8 dclk_max_div;
@@ -174,6 +202,7 @@ struct sun4i_tcon {
/* Reset control */
struct reset_control *lcd_rst;
+ struct reset_control *lvds_rst;
struct drm_panel *panel;
--
git-series 0.9.1
--
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 related
* [PATCH v3 09/15] drm/sun4i: Add A83T support
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
Add support for the A83T display pipeline.
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/sun4i/sun4i_drv.c | 1 +
drivers/gpu/drm/sun4i/sun4i_tcon.c | 5 +++++
drivers/gpu/drm/sun4i/sun8i_mixer.c | 9 +++++++++
3 files changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 49215d91c853..6f5e721b545e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -347,6 +347,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,sun6i-a31s-display-engine" },
{ .compatible = "allwinner,sun7i-a20-display-engine" },
{ .compatible = "allwinner,sun8i-a33-display-engine" },
+ { .compatible = "allwinner,sun8i-a83t-display-engine" },
{ .compatible = "allwinner,sun8i-v3s-display-engine" },
{ }
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 92f4738101e6..9b757450555f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -1132,6 +1132,10 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
.has_lvds_pll = true,
};
+static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
+ /* nothing is supported */
+};
+
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
/* nothing is supported */
};
@@ -1144,6 +1148,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
+ { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
{ }
};
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index ff235e3228ce..6829bec4ba68 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -477,6 +477,11 @@ static int sun8i_mixer_remove(struct platform_device *pdev)
return 0;
}
+static const struct sun8i_mixer_cfg sun8i_a83t_mixer_cfg = {
+ .vi_num = 1,
+ .ui_num = 3,
+};
+
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
@@ -487,6 +492,10 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
static const struct of_device_id sun8i_mixer_of_table[] = {
{
+ .compatible = "allwinner,sun8i-a83t-de2-mixer-0",
+ .data = &sun8i_a83t_mixer_cfg,
+ },
+ {
.compatible = "allwinner,sun8i-v3s-de2-mixer",
.data = &sun8i_v3s_mixer_cfg,
},
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 10/15] ARM: dts: sun8i: a83t: Add display pipeline
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The display pipeline on the A83T is mainly composed of the mixers and
TCONs, plus various encoders.
Let's add the first mixer and TCON to the DTSI since the only board I have
can use only the LVDS output on the first TCON. The other parts will be
added eventually.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 79 ++++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 19acae1b4089..e4db38c717d9 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -45,8 +45,10 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/sun8i-a83t-ccu.h>
+#include <dt-bindings/clock/sun8i-de2.h>
#include <dt-bindings/clock/sun8i-r-ccu.h>
#include <dt-bindings/reset/sun8i-a83t-ccu.h>
+#include <dt-bindings/reset/sun8i-de2.h>
#include <dt-bindings/reset/sun8i-r-ccu.h>
/ {
@@ -151,6 +153,12 @@
};
};
+ de: display-engine {
+ compatible = "allwinner,sun8i-a83t-display-engine";
+ allwinner,pipelines = <&mixer0>;
+ status = "disabled";
+ };
+
memory {
reg = <0x40000000 0x80000000>;
device_type = "memory";
@@ -162,6 +170,44 @@
#size-cells = <1>;
ranges;
+ display_clocks: clock@1000000 {
+ compatible = "allwinner,sun8i-a83t-de2-clk";
+ reg = <0x01000000 0x100000>;
+ clocks = <&ccu CLK_PLL_DE>,
+ <&ccu CLK_BUS_DE>;
+ clock-names = "mod",
+ "bus";
+ resets = <&ccu RST_BUS_DE>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ mixer0: mixer@1100000 {
+ compatible = "allwinner,sun8i-a83t-de2-mixer-0";
+ reg = <0x01100000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER0>,
+ <&display_clocks CLK_MIXER0>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_MIXER0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ mixer0_out_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_in_mixer0>;
+ };
+ };
+ };
+ };
+
syscon: syscon@1c00000 {
compatible = "allwinner,sun8i-a83t-system-controller",
"syscon";
@@ -177,6 +223,39 @@
#dma-cells = <1>;
};
+ tcon0: lcd-controller@1c0c000 {
+ compatible = "allwinner,sun8i-a83t-tcon-lcd";
+ reg = <0x01c0c000 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
+ clock-names = "ahb", "tcon-ch0";
+ clock-output-names = "tcon-pixel-clock";
+ resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>;
+ reset-names = "lcd", "lvds";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon0_in: port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tcon0_in_mixer0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&mixer0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
+ };
+
mmc0: mmc@1c0f000 {
compatible = "allwinner,sun8i-a83t-mmc",
"allwinner,sun7i-a20-mmc";
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v3 11/15] ARM: dts: sun8i: a83t: Enable the PWM
From: Maxime Ripard @ 2017-12-05 15:10 UTC (permalink / raw)
To: Daniel Vetter, David Airlie, Chen-Yu Tsai, Maxime Ripard
Cc: Mark Rutland, Thomas Petazzoni, jernej.skrabec, plaes, devicetree,
linux-kernel, dri-devel, Rob Herring, linux-arm-kernel, icenowy
In-Reply-To: <cover.825a49a4c1c565a548f3de0375e7537e7e8fd3a4.1512486553.git-series.maxime.ripard@free-electrons.com>
The A83T has the same PWM block than the H3. Add it to our DT.
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index e4db38c717d9..7a49b9f085eb 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -497,6 +497,15 @@
status = "disabled";
};
+ pwm: pwm@1c21400 {
+ compatible = "allwinner,sun8i-a83t-pwm",
+ "allwinner,sun8i-h3-pwm";
+ reg = <0x01c21400 0x400>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart0: serial@1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
--
git-series 0.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
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