mirror of https://gitee.com/openkylin/linux.git
pinctrl: add TB10x pin control driver
The pinmux driver of the Abilis Systems TB10x platform based on ARC700 CPUs. Used to control the pinmux and is a prerequisite for the GPIO driver. Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com> Signed-off-by: Pierrick Hascoet <pierrick.hascoet@abilis.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
586a87e6ed
commit
5aad0db1c1
|
@ -0,0 +1,80 @@
|
|||
Abilis Systems TB10x pin controller
|
||||
===================================
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
||||
- compatible: should be "abilis,tb10x-iomux";
|
||||
- reg: should contain the physical address and size of the pin controller's
|
||||
register range.
|
||||
|
||||
|
||||
Function definitions
|
||||
--------------------
|
||||
|
||||
Functions are defined (and referenced) by sub-nodes of the pin controller.
|
||||
Every sub-node defines exactly one function (implying a set of pins).
|
||||
Every function is associated to one named pin group inside the pin controller
|
||||
driver and these names are used to associate pin group predefinitions to pin
|
||||
controller sub-nodes.
|
||||
|
||||
Required function definition subnode properties:
|
||||
- abilis,function: should be set to the name of the function's pin group.
|
||||
|
||||
The following pin groups are available:
|
||||
- GPIO ports: gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog,
|
||||
gpioh, gpioi, gpioj, gpiok, gpiol, gpiom, gpion
|
||||
- Serial TS input ports: mis0, mis1, mis2, mis3, mis4, mis5, mis6, mis7
|
||||
- Parallel TS input ports: mip1, mip3, mip5, mip7
|
||||
- Serial TS output ports: mos0, mos1, mos2, mos3
|
||||
- Parallel TS output port: mop
|
||||
- CI+ port: ciplus
|
||||
- CableCard (Mcard) port: mcard
|
||||
- Smart card ports: stc0, stc1
|
||||
- UART ports: uart0, uart1
|
||||
- SPI ports: spi1, spi3
|
||||
- JTAG: jtag
|
||||
|
||||
All other ports of the chip are not multiplexed and thus not managed by this
|
||||
driver.
|
||||
|
||||
|
||||
GPIO ranges definition
|
||||
----------------------
|
||||
|
||||
The named pin groups of GPIO ports can be used to define GPIO ranges as
|
||||
explained in Documentation/devicetree/bindings/gpio/gpio.txt.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
iomux: iomux@FF10601c {
|
||||
compatible = "abilis,tb10x-iomux";
|
||||
reg = <0xFF10601c 0x4>;
|
||||
pctl_gpio_a: pctl-gpio-a {
|
||||
abilis,function = "gpioa";
|
||||
};
|
||||
pctl_uart0: pctl-uart0 {
|
||||
abilis,function = "uart0";
|
||||
};
|
||||
};
|
||||
uart@FF100000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0xFF100000 0x100>;
|
||||
clock-frequency = <166666666>;
|
||||
interrupts = <25 1>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pctl_uart0>;
|
||||
};
|
||||
gpioa: gpio@FF140000 {
|
||||
compatible = "abilis,tb10x-gpio";
|
||||
reg = <0xFF140000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpio = <3>;
|
||||
gpio-ranges = <&iomux 0 0>;
|
||||
gpio-ranges-group-names = "gpioa";
|
||||
};
|
|
@ -321,6 +321,10 @@ config PINCTRL_XWAY
|
|||
depends on SOC_TYPE_XWAY
|
||||
depends on PINCTRL_LANTIQ
|
||||
|
||||
config PINCTRL_TB10X
|
||||
bool
|
||||
depends on ARC_PLAT_TB10X
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
@ -56,6 +56,7 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o
|
|||
obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
|
||||
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
|
||||
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
|
||||
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
|
||||
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
|
||||
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
|
||||
|
||||
|
|
|
@ -0,0 +1,886 @@
|
|||
/*
|
||||
* Abilis Systems TB10x pin control driver
|
||||
*
|
||||
* Copyright (C) Abilis Systems 2012
|
||||
*
|
||||
* Author: Christian Ruppert <christian.ruppert@abilis.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "pinctrl-utils.h"
|
||||
|
||||
#define TB10X_PORT1 (0)
|
||||
#define TB10X_PORT2 (16)
|
||||
#define TB10X_PORT3 (32)
|
||||
#define TB10X_PORT4 (48)
|
||||
#define TB10X_PORT5 (128)
|
||||
#define TB10X_PORT6 (64)
|
||||
#define TB10X_PORT7 (80)
|
||||
#define TB10X_PORT8 (96)
|
||||
#define TB10X_PORT9 (112)
|
||||
#define TB10X_GPIOS (256)
|
||||
|
||||
#define PCFG_PORT_BITWIDTH (2)
|
||||
#define PCFG_PORT_MASK(PORT) \
|
||||
(((1 << PCFG_PORT_BITWIDTH) - 1) << (PCFG_PORT_BITWIDTH * (PORT)))
|
||||
|
||||
static const struct pinctrl_pin_desc tb10x_pins[] = {
|
||||
/* Port 1 */
|
||||
PINCTRL_PIN(TB10X_PORT1 + 0, "MICLK_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 1, "MISTRT_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 2, "MIVAL_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 3, "MDI_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 4, "GPIOA0"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 5, "GPIOA1"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 6, "GPIOA2"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 7, "MDI_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 8, "MIVAL_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 9, "MISTRT_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT1 + 10, "MICLK_S1"),
|
||||
/* Port 2 */
|
||||
PINCTRL_PIN(TB10X_PORT2 + 0, "MICLK_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 1, "MISTRT_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 2, "MIVAL_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 3, "MDI_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 4, "GPIOC0"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 5, "GPIOC1"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 6, "GPIOC2"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 7, "MDI_S3"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 8, "MIVAL_S3"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 9, "MISTRT_S3"),
|
||||
PINCTRL_PIN(TB10X_PORT2 + 10, "MICLK_S3"),
|
||||
/* Port 3 */
|
||||
PINCTRL_PIN(TB10X_PORT3 + 0, "MICLK_S4"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 1, "MISTRT_S4"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 2, "MIVAL_S4"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 3, "MDI_S4"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 4, "GPIOE0"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 5, "GPIOE1"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 6, "GPIOE2"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 7, "MDI_S5"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 8, "MIVAL_S5"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 9, "MISTRT_S5"),
|
||||
PINCTRL_PIN(TB10X_PORT3 + 10, "MICLK_S5"),
|
||||
/* Port 4 */
|
||||
PINCTRL_PIN(TB10X_PORT4 + 0, "MICLK_S6"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 1, "MISTRT_S6"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 2, "MIVAL_S6"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 3, "MDI_S6"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 4, "GPIOG0"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 5, "GPIOG1"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 6, "GPIOG2"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 7, "MDI_S7"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 8, "MIVAL_S7"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 9, "MISTRT_S7"),
|
||||
PINCTRL_PIN(TB10X_PORT4 + 10, "MICLK_S7"),
|
||||
/* Port 5 */
|
||||
PINCTRL_PIN(TB10X_PORT5 + 0, "PC_CE1N"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 1, "PC_CE2N"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 2, "PC_REGN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 3, "PC_INPACKN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 4, "PC_OEN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 5, "PC_WEN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 6, "PC_IORDN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 7, "PC_IOWRN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 8, "PC_RDYIRQN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 9, "PC_WAITN"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 10, "PC_A0"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 11, "PC_A1"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 12, "PC_A2"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 13, "PC_A3"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 14, "PC_A4"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 15, "PC_A5"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 16, "PC_A6"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 17, "PC_A7"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 18, "PC_A8"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 19, "PC_A9"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 20, "PC_A10"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 21, "PC_A11"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 22, "PC_A12"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 23, "PC_A13"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 24, "PC_A14"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 25, "PC_D0"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 26, "PC_D1"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 27, "PC_D2"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 28, "PC_D3"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 29, "PC_D4"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 30, "PC_D5"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 31, "PC_D6"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 32, "PC_D7"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 33, "PC_MOSTRT"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 34, "PC_MOVAL"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 35, "PC_MDO0"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 36, "PC_MDO1"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 37, "PC_MDO2"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 38, "PC_MDO3"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 39, "PC_MDO4"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 40, "PC_MDO5"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 41, "PC_MDO6"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 42, "PC_MDO7"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 43, "PC_MISTRT"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 44, "PC_MIVAL"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 45, "PC_MDI0"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 46, "PC_MDI1"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 47, "PC_MDI2"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 48, "PC_MDI3"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 49, "PC_MDI4"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 50, "PC_MDI5"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 51, "PC_MDI6"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 52, "PC_MDI7"),
|
||||
PINCTRL_PIN(TB10X_PORT5 + 53, "PC_MICLK"),
|
||||
/* Port 6 */
|
||||
PINCTRL_PIN(TB10X_PORT6 + 0, "T_MOSTRT_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 1, "T_MOVAL_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 2, "T_MDO_S0"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 3, "T_MOSTRT_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 4, "T_MOVAL_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 5, "T_MDO_S1"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 6, "T_MOSTRT_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 7, "T_MOVAL_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 8, "T_MDO_S2"),
|
||||
PINCTRL_PIN(TB10X_PORT6 + 9, "T_MOSTRT_S3"),
|
||||
/* Port 7 */
|
||||
PINCTRL_PIN(TB10X_PORT7 + 0, "UART0_TXD"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 1, "UART0_RXD"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 2, "UART0_CTS"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 3, "UART0_RTS"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 4, "UART1_TXD"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 5, "UART1_RXD"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 6, "UART1_CTS"),
|
||||
PINCTRL_PIN(TB10X_PORT7 + 7, "UART1_RTS"),
|
||||
/* Port 8 */
|
||||
PINCTRL_PIN(TB10X_PORT8 + 0, "SPI3_CLK"),
|
||||
PINCTRL_PIN(TB10X_PORT8 + 1, "SPI3_MISO"),
|
||||
PINCTRL_PIN(TB10X_PORT8 + 2, "SPI3_MOSI"),
|
||||
PINCTRL_PIN(TB10X_PORT8 + 3, "SPI3_SSN"),
|
||||
/* Port 9 */
|
||||
PINCTRL_PIN(TB10X_PORT9 + 0, "SPI1_CLK"),
|
||||
PINCTRL_PIN(TB10X_PORT9 + 1, "SPI1_MISO"),
|
||||
PINCTRL_PIN(TB10X_PORT9 + 2, "SPI1_MOSI"),
|
||||
PINCTRL_PIN(TB10X_PORT9 + 3, "SPI1_SSN0"),
|
||||
PINCTRL_PIN(TB10X_PORT9 + 4, "SPI1_SSN1"),
|
||||
/* Unmuxed GPIOs */
|
||||
PINCTRL_PIN(TB10X_GPIOS + 0, "GPIOB0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 1, "GPIOB1"),
|
||||
|
||||
PINCTRL_PIN(TB10X_GPIOS + 2, "GPIOD0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 3, "GPIOD1"),
|
||||
|
||||
PINCTRL_PIN(TB10X_GPIOS + 4, "GPIOF0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 5, "GPIOF1"),
|
||||
|
||||
PINCTRL_PIN(TB10X_GPIOS + 6, "GPIOH0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 7, "GPIOH1"),
|
||||
|
||||
PINCTRL_PIN(TB10X_GPIOS + 8, "GPIOI0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 9, "GPIOI1"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 10, "GPIOI2"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 11, "GPIOI3"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 12, "GPIOI4"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 13, "GPIOI5"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 14, "GPIOI6"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 15, "GPIOI7"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 16, "GPIOI8"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 17, "GPIOI9"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 18, "GPIOI10"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 19, "GPIOI11"),
|
||||
|
||||
PINCTRL_PIN(TB10X_GPIOS + 20, "GPION0"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 21, "GPION1"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 22, "GPION2"),
|
||||
PINCTRL_PIN(TB10X_GPIOS + 23, "GPION3"),
|
||||
#define MAX_PIN (TB10X_GPIOS + 24)
|
||||
PINCTRL_PIN(MAX_PIN, "GPION4"),
|
||||
};
|
||||
|
||||
|
||||
/* Port 1 */
|
||||
static const unsigned mis0_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1,
|
||||
TB10X_PORT1 + 2, TB10X_PORT1 + 3};
|
||||
static const unsigned gpioa_pins[] = { TB10X_PORT1 + 4, TB10X_PORT1 + 5,
|
||||
TB10X_PORT1 + 6};
|
||||
static const unsigned mis1_pins[] = { TB10X_PORT1 + 7, TB10X_PORT1 + 8,
|
||||
TB10X_PORT1 + 9, TB10X_PORT1 + 10};
|
||||
static const unsigned mip1_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1,
|
||||
TB10X_PORT1 + 2, TB10X_PORT1 + 3,
|
||||
TB10X_PORT1 + 4, TB10X_PORT1 + 5,
|
||||
TB10X_PORT1 + 6, TB10X_PORT1 + 7,
|
||||
TB10X_PORT1 + 8, TB10X_PORT1 + 9,
|
||||
TB10X_PORT1 + 10};
|
||||
|
||||
/* Port 2 */
|
||||
static const unsigned mis2_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1,
|
||||
TB10X_PORT2 + 2, TB10X_PORT2 + 3};
|
||||
static const unsigned gpioc_pins[] = { TB10X_PORT2 + 4, TB10X_PORT2 + 5,
|
||||
TB10X_PORT2 + 6};
|
||||
static const unsigned mis3_pins[] = { TB10X_PORT2 + 7, TB10X_PORT2 + 8,
|
||||
TB10X_PORT2 + 9, TB10X_PORT2 + 10};
|
||||
static const unsigned mip3_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1,
|
||||
TB10X_PORT2 + 2, TB10X_PORT2 + 3,
|
||||
TB10X_PORT2 + 4, TB10X_PORT2 + 5,
|
||||
TB10X_PORT2 + 6, TB10X_PORT2 + 7,
|
||||
TB10X_PORT2 + 8, TB10X_PORT2 + 9,
|
||||
TB10X_PORT2 + 10};
|
||||
|
||||
/* Port 3 */
|
||||
static const unsigned mis4_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1,
|
||||
TB10X_PORT3 + 2, TB10X_PORT3 + 3};
|
||||
static const unsigned gpioe_pins[] = { TB10X_PORT3 + 4, TB10X_PORT3 + 5,
|
||||
TB10X_PORT3 + 6};
|
||||
static const unsigned mis5_pins[] = { TB10X_PORT3 + 7, TB10X_PORT3 + 8,
|
||||
TB10X_PORT3 + 9, TB10X_PORT3 + 10};
|
||||
static const unsigned mip5_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1,
|
||||
TB10X_PORT3 + 2, TB10X_PORT3 + 3,
|
||||
TB10X_PORT3 + 4, TB10X_PORT3 + 5,
|
||||
TB10X_PORT3 + 6, TB10X_PORT3 + 7,
|
||||
TB10X_PORT3 + 8, TB10X_PORT3 + 9,
|
||||
TB10X_PORT3 + 10};
|
||||
|
||||
/* Port 4 */
|
||||
static const unsigned mis6_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1,
|
||||
TB10X_PORT4 + 2, TB10X_PORT4 + 3};
|
||||
static const unsigned gpiog_pins[] = { TB10X_PORT4 + 4, TB10X_PORT4 + 5,
|
||||
TB10X_PORT4 + 6};
|
||||
static const unsigned mis7_pins[] = { TB10X_PORT4 + 7, TB10X_PORT4 + 8,
|
||||
TB10X_PORT4 + 9, TB10X_PORT4 + 10};
|
||||
static const unsigned mip7_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1,
|
||||
TB10X_PORT4 + 2, TB10X_PORT4 + 3,
|
||||
TB10X_PORT4 + 4, TB10X_PORT4 + 5,
|
||||
TB10X_PORT4 + 6, TB10X_PORT4 + 7,
|
||||
TB10X_PORT4 + 8, TB10X_PORT4 + 9,
|
||||
TB10X_PORT4 + 10};
|
||||
|
||||
/* Port 6 */
|
||||
static const unsigned mop_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1,
|
||||
TB10X_PORT6 + 2, TB10X_PORT6 + 3,
|
||||
TB10X_PORT6 + 4, TB10X_PORT6 + 5,
|
||||
TB10X_PORT6 + 6, TB10X_PORT6 + 7,
|
||||
TB10X_PORT6 + 8, TB10X_PORT6 + 9};
|
||||
static const unsigned mos0_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1,
|
||||
TB10X_PORT6 + 2};
|
||||
static const unsigned mos1_pins[] = { TB10X_PORT6 + 3, TB10X_PORT6 + 4,
|
||||
TB10X_PORT6 + 5};
|
||||
static const unsigned mos2_pins[] = { TB10X_PORT6 + 6, TB10X_PORT6 + 7,
|
||||
TB10X_PORT6 + 8};
|
||||
static const unsigned mos3_pins[] = { TB10X_PORT6 + 9};
|
||||
|
||||
/* Port 7 */
|
||||
static const unsigned uart0_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1,
|
||||
TB10X_PORT7 + 2, TB10X_PORT7 + 3};
|
||||
static const unsigned uart1_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5,
|
||||
TB10X_PORT7 + 6, TB10X_PORT7 + 7};
|
||||
static const unsigned gpiol_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1,
|
||||
TB10X_PORT7 + 2, TB10X_PORT7 + 3};
|
||||
static const unsigned gpiom_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5,
|
||||
TB10X_PORT7 + 6, TB10X_PORT7 + 7};
|
||||
|
||||
/* Port 8 */
|
||||
static const unsigned spi3_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1,
|
||||
TB10X_PORT8 + 2, TB10X_PORT8 + 3};
|
||||
static const unsigned jtag_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1,
|
||||
TB10X_PORT8 + 2, TB10X_PORT8 + 3};
|
||||
|
||||
/* Port 9 */
|
||||
static const unsigned spi1_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1,
|
||||
TB10X_PORT9 + 2, TB10X_PORT9 + 3,
|
||||
TB10X_PORT9 + 4};
|
||||
static const unsigned gpion_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1,
|
||||
TB10X_PORT9 + 2, TB10X_PORT9 + 3,
|
||||
TB10X_PORT9 + 4};
|
||||
|
||||
/* Port 5 */
|
||||
static const unsigned gpioj_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1,
|
||||
TB10X_PORT5 + 2, TB10X_PORT5 + 3,
|
||||
TB10X_PORT5 + 4, TB10X_PORT5 + 5,
|
||||
TB10X_PORT5 + 6, TB10X_PORT5 + 7,
|
||||
TB10X_PORT5 + 8, TB10X_PORT5 + 9,
|
||||
TB10X_PORT5 + 10, TB10X_PORT5 + 11,
|
||||
TB10X_PORT5 + 12, TB10X_PORT5 + 13,
|
||||
TB10X_PORT5 + 14, TB10X_PORT5 + 15,
|
||||
TB10X_PORT5 + 16, TB10X_PORT5 + 17,
|
||||
TB10X_PORT5 + 18, TB10X_PORT5 + 19,
|
||||
TB10X_PORT5 + 20, TB10X_PORT5 + 21,
|
||||
TB10X_PORT5 + 22, TB10X_PORT5 + 23,
|
||||
TB10X_PORT5 + 24, TB10X_PORT5 + 25,
|
||||
TB10X_PORT5 + 26, TB10X_PORT5 + 27,
|
||||
TB10X_PORT5 + 28, TB10X_PORT5 + 29,
|
||||
TB10X_PORT5 + 30, TB10X_PORT5 + 31};
|
||||
static const unsigned gpiok_pins[] = { TB10X_PORT5 + 32, TB10X_PORT5 + 33,
|
||||
TB10X_PORT5 + 34, TB10X_PORT5 + 35,
|
||||
TB10X_PORT5 + 36, TB10X_PORT5 + 37,
|
||||
TB10X_PORT5 + 38, TB10X_PORT5 + 39,
|
||||
TB10X_PORT5 + 40, TB10X_PORT5 + 41,
|
||||
TB10X_PORT5 + 42, TB10X_PORT5 + 43,
|
||||
TB10X_PORT5 + 44, TB10X_PORT5 + 45,
|
||||
TB10X_PORT5 + 46, TB10X_PORT5 + 47,
|
||||
TB10X_PORT5 + 48, TB10X_PORT5 + 49,
|
||||
TB10X_PORT5 + 50, TB10X_PORT5 + 51,
|
||||
TB10X_PORT5 + 52, TB10X_PORT5 + 53};
|
||||
static const unsigned ciplus_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1,
|
||||
TB10X_PORT5 + 2, TB10X_PORT5 + 3,
|
||||
TB10X_PORT5 + 4, TB10X_PORT5 + 5,
|
||||
TB10X_PORT5 + 6, TB10X_PORT5 + 7,
|
||||
TB10X_PORT5 + 8, TB10X_PORT5 + 9,
|
||||
TB10X_PORT5 + 10, TB10X_PORT5 + 11,
|
||||
TB10X_PORT5 + 12, TB10X_PORT5 + 13,
|
||||
TB10X_PORT5 + 14, TB10X_PORT5 + 15,
|
||||
TB10X_PORT5 + 16, TB10X_PORT5 + 17,
|
||||
TB10X_PORT5 + 18, TB10X_PORT5 + 19,
|
||||
TB10X_PORT5 + 20, TB10X_PORT5 + 21,
|
||||
TB10X_PORT5 + 22, TB10X_PORT5 + 23,
|
||||
TB10X_PORT5 + 24, TB10X_PORT5 + 25,
|
||||
TB10X_PORT5 + 26, TB10X_PORT5 + 27,
|
||||
TB10X_PORT5 + 28, TB10X_PORT5 + 29,
|
||||
TB10X_PORT5 + 30, TB10X_PORT5 + 31,
|
||||
TB10X_PORT5 + 32, TB10X_PORT5 + 33,
|
||||
TB10X_PORT5 + 34, TB10X_PORT5 + 35,
|
||||
TB10X_PORT5 + 36, TB10X_PORT5 + 37,
|
||||
TB10X_PORT5 + 38, TB10X_PORT5 + 39,
|
||||
TB10X_PORT5 + 40, TB10X_PORT5 + 41,
|
||||
TB10X_PORT5 + 42, TB10X_PORT5 + 43,
|
||||
TB10X_PORT5 + 44, TB10X_PORT5 + 45,
|
||||
TB10X_PORT5 + 46, TB10X_PORT5 + 47,
|
||||
TB10X_PORT5 + 48, TB10X_PORT5 + 49,
|
||||
TB10X_PORT5 + 50, TB10X_PORT5 + 51,
|
||||
TB10X_PORT5 + 52, TB10X_PORT5 + 53};
|
||||
static const unsigned mcard_pins[] = { TB10X_PORT5 + 3, TB10X_PORT5 + 10,
|
||||
TB10X_PORT5 + 11, TB10X_PORT5 + 12,
|
||||
TB10X_PORT5 + 22, TB10X_PORT5 + 23,
|
||||
TB10X_PORT5 + 33, TB10X_PORT5 + 35,
|
||||
TB10X_PORT5 + 36, TB10X_PORT5 + 37,
|
||||
TB10X_PORT5 + 38, TB10X_PORT5 + 39,
|
||||
TB10X_PORT5 + 40, TB10X_PORT5 + 41,
|
||||
TB10X_PORT5 + 42, TB10X_PORT5 + 43,
|
||||
TB10X_PORT5 + 45, TB10X_PORT5 + 46,
|
||||
TB10X_PORT5 + 47, TB10X_PORT5 + 48,
|
||||
TB10X_PORT5 + 49, TB10X_PORT5 + 50,
|
||||
TB10X_PORT5 + 51, TB10X_PORT5 + 52,
|
||||
TB10X_PORT5 + 53};
|
||||
static const unsigned stc0_pins[] = { TB10X_PORT5 + 34, TB10X_PORT5 + 35,
|
||||
TB10X_PORT5 + 36, TB10X_PORT5 + 37,
|
||||
TB10X_PORT5 + 38, TB10X_PORT5 + 39,
|
||||
TB10X_PORT5 + 40};
|
||||
static const unsigned stc1_pins[] = { TB10X_PORT5 + 25, TB10X_PORT5 + 26,
|
||||
TB10X_PORT5 + 27, TB10X_PORT5 + 28,
|
||||
TB10X_PORT5 + 29, TB10X_PORT5 + 30,
|
||||
TB10X_PORT5 + 44};
|
||||
|
||||
/* Unmuxed GPIOs */
|
||||
static const unsigned gpiob_pins[] = { TB10X_GPIOS + 0, TB10X_GPIOS + 1};
|
||||
static const unsigned gpiod_pins[] = { TB10X_GPIOS + 2, TB10X_GPIOS + 3};
|
||||
static const unsigned gpiof_pins[] = { TB10X_GPIOS + 4, TB10X_GPIOS + 5};
|
||||
static const unsigned gpioh_pins[] = { TB10X_GPIOS + 6, TB10X_GPIOS + 7};
|
||||
static const unsigned gpioi_pins[] = { TB10X_GPIOS + 8, TB10X_GPIOS + 9,
|
||||
TB10X_GPIOS + 10, TB10X_GPIOS + 11,
|
||||
TB10X_GPIOS + 12, TB10X_GPIOS + 13,
|
||||
TB10X_GPIOS + 14, TB10X_GPIOS + 15,
|
||||
TB10X_GPIOS + 16, TB10X_GPIOS + 17,
|
||||
TB10X_GPIOS + 18, TB10X_GPIOS + 19};
|
||||
|
||||
struct tb10x_pinfuncgrp {
|
||||
const char *name;
|
||||
const unsigned int *pins;
|
||||
const unsigned int pincnt;
|
||||
const int port;
|
||||
const unsigned int mode;
|
||||
const int isgpio;
|
||||
};
|
||||
#define DEFPINFUNCGRP(NAME, PORT, MODE, ISGPIO) { \
|
||||
.name = __stringify(NAME), \
|
||||
.pins = NAME##_pins, .pincnt = ARRAY_SIZE(NAME##_pins), \
|
||||
.port = (PORT), .mode = (MODE), \
|
||||
.isgpio = (ISGPIO), \
|
||||
}
|
||||
static const struct tb10x_pinfuncgrp tb10x_pingroups[] = {
|
||||
DEFPINFUNCGRP(mis0, 0, 0, 0),
|
||||
DEFPINFUNCGRP(gpioa, 0, 0, 1),
|
||||
DEFPINFUNCGRP(mis1, 0, 0, 0),
|
||||
DEFPINFUNCGRP(mip1, 0, 1, 0),
|
||||
DEFPINFUNCGRP(mis2, 1, 0, 0),
|
||||
DEFPINFUNCGRP(gpioc, 1, 0, 1),
|
||||
DEFPINFUNCGRP(mis3, 1, 0, 0),
|
||||
DEFPINFUNCGRP(mip3, 1, 1, 0),
|
||||
DEFPINFUNCGRP(mis4, 2, 0, 0),
|
||||
DEFPINFUNCGRP(gpioe, 2, 0, 1),
|
||||
DEFPINFUNCGRP(mis5, 2, 0, 0),
|
||||
DEFPINFUNCGRP(mip5, 2, 1, 0),
|
||||
DEFPINFUNCGRP(mis6, 3, 0, 0),
|
||||
DEFPINFUNCGRP(gpiog, 3, 0, 1),
|
||||
DEFPINFUNCGRP(mis7, 3, 0, 0),
|
||||
DEFPINFUNCGRP(mip7, 3, 1, 0),
|
||||
DEFPINFUNCGRP(gpioj, 4, 0, 1),
|
||||
DEFPINFUNCGRP(gpiok, 4, 0, 1),
|
||||
DEFPINFUNCGRP(ciplus, 4, 1, 0),
|
||||
DEFPINFUNCGRP(mcard, 4, 2, 0),
|
||||
DEFPINFUNCGRP(stc0, 4, 3, 0),
|
||||
DEFPINFUNCGRP(stc1, 4, 3, 0),
|
||||
DEFPINFUNCGRP(mop, 5, 0, 0),
|
||||
DEFPINFUNCGRP(mos0, 5, 1, 0),
|
||||
DEFPINFUNCGRP(mos1, 5, 1, 0),
|
||||
DEFPINFUNCGRP(mos2, 5, 1, 0),
|
||||
DEFPINFUNCGRP(mos3, 5, 1, 0),
|
||||
DEFPINFUNCGRP(uart0, 6, 0, 0),
|
||||
DEFPINFUNCGRP(uart1, 6, 0, 0),
|
||||
DEFPINFUNCGRP(gpiol, 6, 1, 1),
|
||||
DEFPINFUNCGRP(gpiom, 6, 1, 1),
|
||||
DEFPINFUNCGRP(spi3, 7, 0, 0),
|
||||
DEFPINFUNCGRP(jtag, 7, 1, 0),
|
||||
DEFPINFUNCGRP(spi1, 8, 0, 0),
|
||||
DEFPINFUNCGRP(gpion, 8, 1, 1),
|
||||
DEFPINFUNCGRP(gpiob, -1, 0, 1),
|
||||
DEFPINFUNCGRP(gpiod, -1, 0, 1),
|
||||
DEFPINFUNCGRP(gpiof, -1, 0, 1),
|
||||
DEFPINFUNCGRP(gpioh, -1, 0, 1),
|
||||
DEFPINFUNCGRP(gpioi, -1, 0, 1),
|
||||
};
|
||||
#undef DEFPINFUNCGRP
|
||||
|
||||
struct tb10x_of_pinfunc {
|
||||
const char *name;
|
||||
const char *group;
|
||||
};
|
||||
|
||||
#define TB10X_PORTS (9)
|
||||
|
||||
/**
|
||||
* struct tb10x_port - state of an I/O port
|
||||
* @mode: Node this port is currently in.
|
||||
* @count: Number of enabled functions which require this port to be
|
||||
* configured in @mode.
|
||||
*/
|
||||
struct tb10x_port {
|
||||
unsigned int mode;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tb10x_pinctrl - TB10x pin controller internal state
|
||||
* @pctl: pointer to the pinctrl_dev structure of this pin controller.
|
||||
* @base: register set base address.
|
||||
* @pingroups: pointer to an array of the pin groups this driver manages.
|
||||
* @pinfuncgrpcnt: number of pingroups in @pingroups.
|
||||
* @pinfuncs: pointer to an array of pin functions this driver manages.
|
||||
* @pinfuncnt: number of pin functions in @pinfuncs.
|
||||
* @mutex: mutex for exclusive access to a pin controller's state.
|
||||
* @ports: current state of each port.
|
||||
* @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0).
|
||||
*/
|
||||
struct tb10x_pinctrl {
|
||||
struct pinctrl_dev *pctl;
|
||||
void *base;
|
||||
const struct tb10x_pinfuncgrp *pingroups;
|
||||
unsigned int pinfuncgrpcnt;
|
||||
struct tb10x_of_pinfunc *pinfuncs;
|
||||
unsigned int pinfuncnt;
|
||||
struct mutex mutex;
|
||||
struct tb10x_port ports[TB10X_PORTS];
|
||||
DECLARE_BITMAP(gpios, MAX_PIN + 1);
|
||||
};
|
||||
|
||||
static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state,
|
||||
unsigned int port, unsigned int mode)
|
||||
{
|
||||
u32 pcfg;
|
||||
|
||||
if (state->ports[port].count)
|
||||
return;
|
||||
|
||||
state->ports[port].mode = mode;
|
||||
|
||||
pcfg = ioread32(state->base) & ~(PCFG_PORT_MASK(port));
|
||||
pcfg |= (mode << (PCFG_PORT_BITWIDTH * port)) & PCFG_PORT_MASK(port);
|
||||
iowrite32(pcfg, state->base);
|
||||
}
|
||||
|
||||
static inline unsigned int tb10x_pinctrl_get_config(
|
||||
struct tb10x_pinctrl *state,
|
||||
unsigned int port)
|
||||
{
|
||||
return (ioread32(state->base) & PCFG_PORT_MASK(port))
|
||||
>> (PCFG_PORT_BITWIDTH * port);
|
||||
}
|
||||
|
||||
static int tb10x_get_groups_count(struct pinctrl_dev *pctl)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
return state->pinfuncgrpcnt;
|
||||
}
|
||||
|
||||
static const char *tb10x_get_group_name(struct pinctrl_dev *pctl, unsigned n)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
return state->pingroups[n].name;
|
||||
}
|
||||
|
||||
static int tb10x_get_group_pins(struct pinctrl_dev *pctl, unsigned n,
|
||||
unsigned const **pins,
|
||||
unsigned * const num_pins)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
|
||||
*pins = state->pingroups[n].pins;
|
||||
*num_pins = state->pingroups[n].pincnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tb10x_dt_node_to_map(struct pinctrl_dev *pctl,
|
||||
struct device_node *np_config,
|
||||
struct pinctrl_map **map, unsigned *num_maps)
|
||||
{
|
||||
const char *string;
|
||||
unsigned reserved_maps = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (of_property_read_string(np_config, "abilis,function", &string)) {
|
||||
pr_err("%s: No abilis,function property in device tree.\n",
|
||||
np_config->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*map = NULL;
|
||||
*num_maps = 0;
|
||||
|
||||
ret = pinctrl_utils_reserve_map(pctl, map, &reserved_maps,
|
||||
num_maps, 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = pinctrl_utils_add_map_mux(pctl, map, &reserved_maps,
|
||||
num_maps, string, np_config->name);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops tb10x_pinctrl_ops = {
|
||||
.get_groups_count = tb10x_get_groups_count,
|
||||
.get_group_name = tb10x_get_group_name,
|
||||
.get_group_pins = tb10x_get_group_pins,
|
||||
.dt_node_to_map = tb10x_dt_node_to_map,
|
||||
.dt_free_map = pinctrl_utils_dt_free_map,
|
||||
};
|
||||
|
||||
static int tb10x_get_functions_count(struct pinctrl_dev *pctl)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
return state->pinfuncnt;
|
||||
}
|
||||
|
||||
static const char *tb10x_get_function_name(struct pinctrl_dev *pctl,
|
||||
unsigned n)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
return state->pinfuncs[n].name;
|
||||
}
|
||||
|
||||
static int tb10x_get_function_groups(struct pinctrl_dev *pctl,
|
||||
unsigned n, const char * const **groups,
|
||||
unsigned * const num_groups)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
|
||||
*groups = &state->pinfuncs[n].group;
|
||||
*num_groups = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tb10x_gpio_request_enable(struct pinctrl_dev *pctl,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned pin)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
int muxport = -1;
|
||||
int muxmode = -1;
|
||||
int i;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
/*
|
||||
* Figure out to which port the requested GPIO belongs and how to
|
||||
* configure that port.
|
||||
* This loop also checks for pin conflicts between GPIOs and other
|
||||
* functions.
|
||||
*/
|
||||
for (i = 0; i < state->pinfuncgrpcnt; i++) {
|
||||
const struct tb10x_pinfuncgrp *pfg = &state->pingroups[i];
|
||||
unsigned int port = pfg->port;
|
||||
unsigned int mode = pfg->mode;
|
||||
int j;
|
||||
|
||||
/*
|
||||
* Skip pin groups which are always mapped and don't need
|
||||
* to be configured.
|
||||
*/
|
||||
if (port < 0)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < pfg->pincnt; j++) {
|
||||
if (pin == pfg->pins[j]) {
|
||||
if (pfg->isgpio) {
|
||||
/*
|
||||
* Remember the GPIO-only setting of
|
||||
* the port this pin belongs to.
|
||||
*/
|
||||
muxport = port;
|
||||
muxmode = mode;
|
||||
} else if (state->ports[port].count
|
||||
&& (state->ports[port].mode == mode)) {
|
||||
/*
|
||||
* Error: The requested pin is already
|
||||
* used for something else.
|
||||
*/
|
||||
mutex_unlock(&state->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we haven't returned an error at this point, the GPIO pin is not
|
||||
* used by another function and the GPIO request can be granted:
|
||||
* Register pin as being used as GPIO so we don't allocate it to
|
||||
* another function later.
|
||||
*/
|
||||
set_bit(pin, state->gpios);
|
||||
|
||||
/*
|
||||
* Potential conflicts between GPIOs and pin functions were caught
|
||||
* earlier in this function and tb10x_pinctrl_set_config will do the
|
||||
* Right Thing, either configure the port in GPIO only mode or leave
|
||||
* another mode compatible with this GPIO request untouched.
|
||||
*/
|
||||
if (muxport >= 0)
|
||||
tb10x_pinctrl_set_config(state, muxport, muxmode);
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tb10x_gpio_disable_free(struct pinctrl_dev *pctl,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned pin)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
clear_bit(pin, state->gpios);
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
}
|
||||
|
||||
static int tb10x_pctl_enable(struct pinctrl_dev *pctl,
|
||||
unsigned func_selector, unsigned group_selector)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector];
|
||||
int i;
|
||||
|
||||
if (grp->port < 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
/*
|
||||
* Check if the requested function is compatible with previously
|
||||
* requested functions.
|
||||
*/
|
||||
if (state->ports[grp->port].count
|
||||
&& (state->ports[grp->port].mode != grp->mode)) {
|
||||
mutex_unlock(&state->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the requested function is compatible with previously
|
||||
* requested GPIOs.
|
||||
*/
|
||||
for (i = 0; i < grp->pincnt; i++)
|
||||
if (test_bit(grp->pins[i], state->gpios)) {
|
||||
mutex_unlock(&state->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
tb10x_pinctrl_set_config(state, grp->port, grp->mode);
|
||||
|
||||
state->ports[grp->port].count++;
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tb10x_pctl_disable(struct pinctrl_dev *pctl,
|
||||
unsigned func_selector, unsigned group_selector)
|
||||
{
|
||||
struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl);
|
||||
const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector];
|
||||
|
||||
if (grp->port < 0)
|
||||
return;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
state->ports[grp->port].count--;
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
}
|
||||
|
||||
static struct pinmux_ops tb10x_pinmux_ops = {
|
||||
.get_functions_count = tb10x_get_functions_count,
|
||||
.get_function_name = tb10x_get_function_name,
|
||||
.get_function_groups = tb10x_get_function_groups,
|
||||
.gpio_request_enable = tb10x_gpio_request_enable,
|
||||
.gpio_disable_free = tb10x_gpio_disable_free,
|
||||
.enable = tb10x_pctl_enable,
|
||||
.disable = tb10x_pctl_disable,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc tb10x_pindesc = {
|
||||
.name = "TB10x",
|
||||
.pins = tb10x_pins,
|
||||
.npins = ARRAY_SIZE(tb10x_pins),
|
||||
.owner = THIS_MODULE,
|
||||
.pctlops = &tb10x_pinctrl_ops,
|
||||
.pmxops = &tb10x_pinmux_ops,
|
||||
};
|
||||
|
||||
static int tb10x_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *of_node = dev->of_node;
|
||||
struct device_node *child;
|
||||
struct tb10x_pinctrl *state;
|
||||
int i;
|
||||
|
||||
if (!of_node) {
|
||||
dev_err(dev, "No device tree node found.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!mem) {
|
||||
dev_err(dev, "No memory resource defined.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) +
|
||||
of_get_child_count(of_node)
|
||||
* sizeof(struct tb10x_of_pinfunc),
|
||||
GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, state);
|
||||
state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1);
|
||||
mutex_init(&state->mutex);
|
||||
|
||||
state->base = devm_ioremap_resource(dev, mem);
|
||||
if (!state->base) {
|
||||
dev_err(dev, "Request register region failed.\n");
|
||||
ret = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
state->pingroups = tb10x_pingroups;
|
||||
state->pinfuncgrpcnt = ARRAY_SIZE(tb10x_pingroups);
|
||||
|
||||
for (i = 0; i < TB10X_PORTS; i++)
|
||||
state->ports[i].mode = tb10x_pinctrl_get_config(state, i);
|
||||
|
||||
for_each_child_of_node(of_node, child) {
|
||||
const char *name;
|
||||
|
||||
if (!of_property_read_string(child, "abilis,function",
|
||||
&name)) {
|
||||
state->pinfuncs[state->pinfuncnt].name = child->name;
|
||||
state->pinfuncs[state->pinfuncnt].group = name;
|
||||
state->pinfuncnt++;
|
||||
}
|
||||
}
|
||||
|
||||
state->pctl = pinctrl_register(&tb10x_pindesc, dev, state);
|
||||
if (IS_ERR(state->pctl)) {
|
||||
dev_err(dev, "could not register TB10x pin driver\n");
|
||||
ret = PTR_ERR(state->pctl);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
mutex_destroy(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tb10x_pinctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tb10x_pinctrl *state = platform_get_drvdata(pdev);
|
||||
|
||||
pinctrl_unregister(state->pctl);
|
||||
mutex_destroy(&state->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id tb10x_pinctrl_dt_ids[] = {
|
||||
{ .compatible = "abilis,tb10x-iomux" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tb10x_pinctrl_dt_ids);
|
||||
|
||||
static struct platform_driver tb10x_pinctrl_pdrv = {
|
||||
.probe = tb10x_pinctrl_probe,
|
||||
.remove = tb10x_pinctrl_remove,
|
||||
.driver = {
|
||||
.name = "tb10x_pinctrl",
|
||||
.of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids),
|
||||
.owner = THIS_MODULE
|
||||
}
|
||||
};
|
||||
|
||||
static int __init tb10x_iopinctrl_init(void)
|
||||
{
|
||||
return platform_driver_register(&tb10x_pinctrl_pdrv);
|
||||
}
|
||||
|
||||
static void __exit tb10x_iopinctrl_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tb10x_pinctrl_pdrv);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Christian Ruppert <christian.ruppert@abilis.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_init(tb10x_iopinctrl_init);
|
||||
module_exit(tb10x_iopinctrl_exit);
|
Loading…
Reference in New Issue