Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
7bc8c4c3
Commit
7bc8c4c3
authored
Jun 30, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/field' into regmap-next
parents
ad4f496b
539fde59
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1689 additions
and
0 deletions
+1689
-0
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
+110
-0
drivers/base/regmap/internal.h
drivers/base/regmap/internal.h
+8
-0
drivers/base/regmap/regmap.c
drivers/base/regmap/regmap.c
+130
-0
drivers/pinctrl/Kconfig
drivers/pinctrl/Kconfig
+6
-0
drivers/pinctrl/Makefile
drivers/pinctrl/Makefile
+1
-0
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-st.c
+1403
-0
include/linux/regmap.h
include/linux/regmap.h
+31
-0
No files found.
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
0 → 100644
View file @
7bc8c4c3
*ST pin controller.
Each multi-function pin is controlled, driven and routed through the
PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
and multiple alternate functions(ALT1 - ALTx) that directly connect
the pin to different hardware blocks.
When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
Pull Up (PU) are driven by the related PIO block.
ST pinctrl driver controls PIO multiplexing block and also interacts with
gpio driver to configure a pin.
Required properties: (PIO multiplexing block)
- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
- gpio-controller : Indicates this device is a GPIO controller
- #gpio-cells : Should be one. The first cell is the pin number.
- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
If the property is not present, it is assumed that all the pins in the
bank are capable of retiming. Retiming is mainly used to improve the
IO timing margins of external synchronous interfaces.
- st,bank-name : Should be a name string for this bank as
specified in datasheet.
- st,syscfg : Should be a phandle of the syscfg node.
Example:
pin-controller-sbc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stih415-sbc-pinctrl";
st,syscfg = <&syscfg_sbc>;
ranges = <0 0xfe610000 0x5000>;
PIO0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
reg = <0 0x100>;
st,bank-name = "PIO0";
};
...
pin-functions nodes follow...
};
Contents of function subnode node:
----------------------
Required properties for pin configuration node:
- st,pins : Child node with list of pins with configuration.
Below is the format of how each pin conf should look like.
<bank offset mux mode rt_type rt_delay rt_clk>
Every PIO is represented with 4-7 parameters depending on retime configuration.
Each parameter is explained as below.
-bank : Should be bank phandle to which this PIO belongs.
-offset : Offset in the PIO bank.
-mux : Should be alternate function number associated this pin.
Use same numbers from datasheet.
-mode :pin configuration is selected from one of the below values.
IN
IN_PU
OUT
BIDIR
BIDIR_PU
-rt_type Retiming Configuration for the pin.
Possible retime configuration are:
------- -------------
value args
------- -------------
NICLK <delay> <clk>
ICLK_IO <delay> <clk>
BYPASS <delay>
DE_IO <delay> <clk>
SE_ICLK_IO <delay> <clk>
SE_NICLK_IO <delay> <clk>
- delay is retime delay in pico seconds as mentioned in data sheet.
- rt_clk :clk to be use for retime.
Possible values are:
CLK_A
CLK_B
CLK_C
CLK_D
Example of mmcclk pin which is a bi-direction pull pu with retime config
as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
pin-controller {
...
mmc0 {
pinctrl_mmc: mmc {
st,pins {
mmcclk = <&PIO13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
...
};
};
...
};
};
sdhci0:sdhci@fe810000{
...
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc>;
};
drivers/base/regmap/internal.h
View file @
7bc8c4c3
...
...
@@ -176,6 +176,14 @@ struct regmap_range_node {
unsigned
int
window_len
;
};
struct
regmap_field
{
struct
regmap
*
regmap
;
unsigned
int
mask
;
/* lsb */
unsigned
int
shift
;
unsigned
int
reg
;
};
#ifdef CONFIG_DEBUG_FS
extern
void
regmap_debugfs_initcall
(
void
);
extern
void
regmap_debugfs_init
(
struct
regmap
*
map
,
const
char
*
name
);
...
...
drivers/base/regmap/regmap.c
View file @
7bc8c4c3
...
...
@@ -807,6 +807,95 @@ struct regmap *devm_regmap_init(struct device *dev,
}
EXPORT_SYMBOL_GPL
(
devm_regmap_init
);
static
void
regmap_field_init
(
struct
regmap_field
*
rm_field
,
struct
regmap
*
regmap
,
struct
reg_field
reg_field
)
{
int
field_bits
=
reg_field
.
msb
-
reg_field
.
lsb
+
1
;
rm_field
->
regmap
=
regmap
;
rm_field
->
reg
=
reg_field
.
reg
;
rm_field
->
shift
=
reg_field
.
lsb
;
rm_field
->
mask
=
((
BIT
(
field_bits
)
-
1
)
<<
reg_field
.
lsb
);
}
/**
* devm_regmap_field_alloc(): Allocate and initialise a register field
* in a register map.
*
* @dev: Device that will be interacted with
* @regmap: regmap bank in which this register field is located.
* @reg_field: Register field with in the bank.
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap_field. The regmap_field will be automatically freed
* by the device management code.
*/
struct
regmap_field
*
devm_regmap_field_alloc
(
struct
device
*
dev
,
struct
regmap
*
regmap
,
struct
reg_field
reg_field
)
{
struct
regmap_field
*
rm_field
=
devm_kzalloc
(
dev
,
sizeof
(
*
rm_field
),
GFP_KERNEL
);
if
(
!
rm_field
)
return
ERR_PTR
(
-
ENOMEM
);
regmap_field_init
(
rm_field
,
regmap
,
reg_field
);
return
rm_field
;
}
EXPORT_SYMBOL_GPL
(
devm_regmap_field_alloc
);
/**
* devm_regmap_field_free(): Free register field allocated using
* devm_regmap_field_alloc. Usally drivers need not call this function,
* as the memory allocated via devm will be freed as per device-driver
* life-cyle.
*
* @dev: Device that will be interacted with
* @field: regmap field which should be freed.
*/
void
devm_regmap_field_free
(
struct
device
*
dev
,
struct
regmap_field
*
field
)
{
devm_kfree
(
dev
,
field
);
}
EXPORT_SYMBOL_GPL
(
devm_regmap_field_free
);
/**
* regmap_field_alloc(): Allocate and initialise a register field
* in a register map.
*
* @regmap: regmap bank in which this register field is located.
* @reg_field: Register field with in the bank.
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap_field. The regmap_field should be freed by the
* user once its finished working with it using regmap_field_free().
*/
struct
regmap_field
*
regmap_field_alloc
(
struct
regmap
*
regmap
,
struct
reg_field
reg_field
)
{
struct
regmap_field
*
rm_field
=
kzalloc
(
sizeof
(
*
rm_field
),
GFP_KERNEL
);
if
(
!
rm_field
)
return
ERR_PTR
(
-
ENOMEM
);
regmap_field_init
(
rm_field
,
regmap
,
reg_field
);
return
rm_field
;
}
EXPORT_SYMBOL_GPL
(
regmap_field_alloc
);
/**
* regmap_field_free(): Free register field allocated using regmap_field_alloc
*
* @field: regmap field which should be freed.
*/
void
regmap_field_free
(
struct
regmap_field
*
field
)
{
kfree
(
field
);
}
EXPORT_SYMBOL_GPL
(
regmap_field_free
);
/**
* regmap_reinit_cache(): Reinitialise the current register cache
*
...
...
@@ -1255,6 +1344,22 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL
(
regmap_raw_write
);
/**
* regmap_field_write(): Write a value to a single register field
*
* @field: Register field to write to
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int
regmap_field_write
(
struct
regmap_field
*
field
,
unsigned
int
val
)
{
return
regmap_update_bits
(
field
->
regmap
,
field
->
reg
,
field
->
mask
,
val
<<
field
->
shift
);
}
EXPORT_SYMBOL_GPL
(
regmap_field_write
);
/*
* regmap_bulk_write(): Write multiple registers to the device
*
...
...
@@ -1537,6 +1642,31 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
}
EXPORT_SYMBOL_GPL
(
regmap_raw_read
);
/**
* regmap_field_read(): Read a value to a single register field
*
* @field: Register field to read from
* @val: Pointer to store read value
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int
regmap_field_read
(
struct
regmap_field
*
field
,
unsigned
int
*
val
)
{
int
ret
;
unsigned
int
reg_val
;
ret
=
regmap_read
(
field
->
regmap
,
field
->
reg
,
&
reg_val
);
if
(
ret
!=
0
)
return
ret
;
reg_val
&=
field
->
mask
;
reg_val
>>=
field
->
shift
;
*
val
=
reg_val
;
return
ret
;
}
EXPORT_SYMBOL_GPL
(
regmap_field_read
);
/**
* regmap_bulk_read(): Read multiple registers from the device
*
...
...
drivers/pinctrl/Kconfig
View file @
7bc8c4c3
...
...
@@ -169,6 +169,12 @@ config PINCTRL_SUNXI
select PINMUX
select GENERIC_PINCONF
config PINCTRL_ST
bool
depends on OF
select PINMUX
select PINCONF
config PINCTRL_TEGRA
bool
select PINMUX
...
...
drivers/pinctrl/Makefile
View file @
7bc8c4c3
...
...
@@ -45,6 +45,7 @@ obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.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_ST)
+=
pinctrl-st.o
obj-$(CONFIG_PLAT_ORION)
+=
mvebu/
obj-$(CONFIG_ARCH_SHMOBILE)
+=
sh-pfc/
...
...
drivers/pinctrl/pinctrl-st.c
0 → 100644
View file @
7bc8c4c3
/*
* Copyright (C) 2013 STMicroelectronics (R&D) Limited.
* Authors:
* Srinivas Kandagatla <srinivas.kandagatla@st.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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/platform_device.h>
#include "core.h"
/* PIO Block registers */
/* PIO output */
#define REG_PIO_POUT 0x00
/* Set bits of POUT */
#define REG_PIO_SET_POUT 0x04
/* Clear bits of POUT */
#define REG_PIO_CLR_POUT 0x08
/* PIO input */
#define REG_PIO_PIN 0x10
/* PIO configuration */
#define REG_PIO_PC(n) (0x20 + (n) * 0x10)
/* Set bits of PC[2:0] */
#define REG_PIO_SET_PC(n) (0x24 + (n) * 0x10)
/* Clear bits of PC[2:0] */
#define REG_PIO_CLR_PC(n) (0x28 + (n) * 0x10)
/* PIO input comparison */
#define REG_PIO_PCOMP 0x50
/* Set bits of PCOMP */
#define REG_PIO_SET_PCOMP 0x54
/* Clear bits of PCOMP */
#define REG_PIO_CLR_PCOMP 0x58
/* PIO input comparison mask */
#define REG_PIO_PMASK 0x60
/* Set bits of PMASK */
#define REG_PIO_SET_PMASK 0x64
/* Clear bits of PMASK */
#define REG_PIO_CLR_PMASK 0x68
#define ST_GPIO_DIRECTION_BIDIR 0x1
#define ST_GPIO_DIRECTION_OUT 0x2
#define ST_GPIO_DIRECTION_IN 0x4
/**
* Packed style retime configuration.
* There are two registers cfg0 and cfg1 in this style for each bank.
* Each field in this register is 8 bit corresponding to 8 pins in the bank.
*/
#define RT_P_CFGS_PER_BANK 2
#define RT_P_CFG0_CLK1NOTCLK0_FIELD(reg) REG_FIELD(reg, 0, 7)
#define RT_P_CFG0_DELAY_0_FIELD(reg) REG_FIELD(reg, 16, 23)
#define RT_P_CFG0_DELAY_1_FIELD(reg) REG_FIELD(reg, 24, 31)
#define RT_P_CFG1_INVERTCLK_FIELD(reg) REG_FIELD(reg, 0, 7)
#define RT_P_CFG1_RETIME_FIELD(reg) REG_FIELD(reg, 8, 15)
#define RT_P_CFG1_CLKNOTDATA_FIELD(reg) REG_FIELD(reg, 16, 23)
#define RT_P_CFG1_DOUBLE_EDGE_FIELD(reg) REG_FIELD(reg, 24, 31)
/**
* Dedicated style retime Configuration register
* each register is dedicated per pin.
*/
#define RT_D_CFGS_PER_BANK 8
#define RT_D_CFG_CLK_SHIFT 0
#define RT_D_CFG_CLK_MASK (0x3 << 0)
#define RT_D_CFG_CLKNOTDATA_SHIFT 2
#define RT_D_CFG_CLKNOTDATA_MASK BIT(2)
#define RT_D_CFG_DELAY_SHIFT 3
#define RT_D_CFG_DELAY_MASK (0xf << 3)
#define RT_D_CFG_DELAY_INNOTOUT_SHIFT 7
#define RT_D_CFG_DELAY_INNOTOUT_MASK BIT(7)
#define RT_D_CFG_DOUBLE_EDGE_SHIFT 8
#define RT_D_CFG_DOUBLE_EDGE_MASK BIT(8)
#define RT_D_CFG_INVERTCLK_SHIFT 9
#define RT_D_CFG_INVERTCLK_MASK BIT(9)
#define RT_D_CFG_RETIME_SHIFT 10
#define RT_D_CFG_RETIME_MASK BIT(10)
/*
* Pinconf is represented in an opaque unsigned long variable.
* Below is the bit allocation details for each possible configuration.
* All the bit fields can be encapsulated into four variables
* (direction, retime-type, retime-clk, retime-delay)
*
* +----------------+
*[31:28]| reserved-3 |
* +----------------+-------------
*[27] | oe | |
* +----------------+ v
*[26] | pu | [Direction ]
* +----------------+ ^
*[25] | od | |
* +----------------+-------------
*[24] | reserved-2 |
* +----------------+-------------
*[23] | retime | |
* +----------------+ |
*[22] | retime-invclk | |
* +----------------+ v
*[21] |retime-clknotdat| [Retime-type ]
* +----------------+ ^
*[20] | retime-de | |
* +----------------+-------------
*[19:18]| retime-clk |------>[Retime-Clk ]
* +----------------+
*[17:16]| reserved-1 |
* +----------------+
*[15..0]| retime-delay |------>[Retime Delay]
* +----------------+
*/
#define ST_PINCONF_UNPACK(conf, param)\
((conf >> ST_PINCONF_ ##param ##_SHIFT) \
& ST_PINCONF_ ##param ##_MASK)
#define ST_PINCONF_PACK(conf, val, param) (conf |=\
((val & ST_PINCONF_ ##param ##_MASK) << \
ST_PINCONF_ ##param ##_SHIFT))
/* Output enable */
#define ST_PINCONF_OE_MASK 0x1
#define ST_PINCONF_OE_SHIFT 27
#define ST_PINCONF_OE BIT(27)
#define ST_PINCONF_UNPACK_OE(conf) ST_PINCONF_UNPACK(conf, OE)
#define ST_PINCONF_PACK_OE(conf) ST_PINCONF_PACK(conf, 1, OE)
/* Pull Up */
#define ST_PINCONF_PU_MASK 0x1
#define ST_PINCONF_PU_SHIFT 26
#define ST_PINCONF_PU BIT(26)
#define ST_PINCONF_UNPACK_PU(conf) ST_PINCONF_UNPACK(conf, PU)
#define ST_PINCONF_PACK_PU(conf) ST_PINCONF_PACK(conf, 1, PU)
/* Open Drain */
#define ST_PINCONF_OD_MASK 0x1
#define ST_PINCONF_OD_SHIFT 25
#define ST_PINCONF_OD BIT(25)
#define ST_PINCONF_UNPACK_OD(conf) ST_PINCONF_UNPACK(conf, OD)
#define ST_PINCONF_PACK_OD(conf) ST_PINCONF_PACK(conf, 1, OD)
#define ST_PINCONF_RT_MASK 0x1
#define ST_PINCONF_RT_SHIFT 23
#define ST_PINCONF_RT BIT(23)
#define ST_PINCONF_UNPACK_RT(conf) ST_PINCONF_UNPACK(conf, RT)
#define ST_PINCONF_PACK_RT(conf) ST_PINCONF_PACK(conf, 1, RT)
#define ST_PINCONF_RT_INVERTCLK_MASK 0x1
#define ST_PINCONF_RT_INVERTCLK_SHIFT 22
#define ST_PINCONF_RT_INVERTCLK BIT(22)
#define ST_PINCONF_UNPACK_RT_INVERTCLK(conf) \
ST_PINCONF_UNPACK(conf, RT_INVERTCLK)
#define ST_PINCONF_PACK_RT_INVERTCLK(conf) \
ST_PINCONF_PACK(conf, 1, RT_INVERTCLK)
#define ST_PINCONF_RT_CLKNOTDATA_MASK 0x1
#define ST_PINCONF_RT_CLKNOTDATA_SHIFT 21
#define ST_PINCONF_RT_CLKNOTDATA BIT(21)
#define ST_PINCONF_UNPACK_RT_CLKNOTDATA(conf) \
ST_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
#define ST_PINCONF_PACK_RT_CLKNOTDATA(conf) \
ST_PINCONF_PACK(conf, 1, RT_CLKNOTDATA)
#define ST_PINCONF_RT_DOUBLE_EDGE_MASK 0x1
#define ST_PINCONF_RT_DOUBLE_EDGE_SHIFT 20
#define ST_PINCONF_RT_DOUBLE_EDGE BIT(20)
#define ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
ST_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
#define ST_PINCONF_PACK_RT_DOUBLE_EDGE(conf) \
ST_PINCONF_PACK(conf, 1, RT_DOUBLE_EDGE)
#define ST_PINCONF_RT_CLK_MASK 0x3
#define ST_PINCONF_RT_CLK_SHIFT 18
#define ST_PINCONF_RT_CLK BIT(18)
#define ST_PINCONF_UNPACK_RT_CLK(conf) ST_PINCONF_UNPACK(conf, RT_CLK)
#define ST_PINCONF_PACK_RT_CLK(conf, val) ST_PINCONF_PACK(conf, val, RT_CLK)
/* RETIME_DELAY in Pico Secs */
#define ST_PINCONF_RT_DELAY_MASK 0xffff
#define ST_PINCONF_RT_DELAY_SHIFT 0
#define ST_PINCONF_UNPACK_RT_DELAY(conf) ST_PINCONF_UNPACK(conf, RT_DELAY)
#define ST_PINCONF_PACK_RT_DELAY(conf, val) \
ST_PINCONF_PACK(conf, val, RT_DELAY)
#define ST_GPIO_PINS_PER_BANK (8)
#define OF_GPIO_ARGS_MIN (4)
#define OF_RT_ARGS_MIN (2)
#define gpio_range_to_bank(chip) \
container_of(chip, struct st_gpio_bank, range)
#define gpio_chip_to_bank(chip) \
container_of(chip, struct st_gpio_bank, gpio_chip)
enum
st_retime_style
{
st_retime_style_none
,
st_retime_style_packed
,
st_retime_style_dedicated
,
};
struct
st_retime_dedicated
{
struct
regmap_field
*
rt
[
ST_GPIO_PINS_PER_BANK
];
};
struct
st_retime_packed
{
struct
regmap_field
*
clk1notclk0
;
struct
regmap_field
*
delay_0
;
struct
regmap_field
*
delay_1
;
struct
regmap_field
*
invertclk
;
struct
regmap_field
*
retime
;
struct
regmap_field
*
clknotdata
;
struct
regmap_field
*
double_edge
;
};
struct
st_pio_control
{
u32
rt_pin_mask
;
struct
regmap_field
*
alt
,
*
oe
,
*
pu
,
*
od
;
/* retiming */
union
{
struct
st_retime_packed
rt_p
;
struct
st_retime_dedicated
rt_d
;
}
rt
;
};
struct
st_pctl_data
{
enum
st_retime_style
rt_style
;
unsigned
int
*
input_delays
;
int
ninput_delays
;
unsigned
int
*
output_delays
;
int
noutput_delays
;
/* register offset information */
int
alt
,
oe
,
pu
,
od
,
rt
;
};
struct
st_pinconf
{
int
pin
;
const
char
*
name
;
unsigned
long
config
;
int
altfunc
;
};
struct
st_pmx_func
{
const
char
*
name
;
const
char
**
groups
;
unsigned
ngroups
;
};
struct
st_pctl_group
{
const
char
*
name
;
unsigned
int
*
pins
;
unsigned
npins
;
struct
st_pinconf
*
pin_conf
;
};
struct
st_gpio_bank
{
struct
gpio_chip
gpio_chip
;
struct
pinctrl_gpio_range
range
;
void
__iomem
*
base
;
struct
st_pio_control
pc
;
};
struct
st_pinctrl
{
struct
device
*
dev
;
struct
pinctrl_dev
*
pctl
;
struct
st_gpio_bank
*
banks
;
int
nbanks
;
struct
st_pmx_func
*
functions
;
int
nfunctions
;
struct
st_pctl_group
*
groups
;
int
ngroups
;
struct
regmap
*
regmap
;
const
struct
st_pctl_data
*
data
;
};
/* SOC specific data */
/* STiH415 data */
unsigned
int
stih415_input_delays
[]
=
{
0
,
500
,
1000
,
1500
};
unsigned
int
stih415_output_delays
[]
=
{
0
,
1000
,
2000
,
3000
};
#define STIH415_PCTRL_COMMON_DATA \
.rt_style = st_retime_style_packed, \
.input_delays = stih415_input_delays, \
.ninput_delays = 4, \
.output_delays = stih415_output_delays, \
.noutput_delays = 4
static
const
struct
st_pctl_data
stih415_sbc_data
=
{
STIH415_PCTRL_COMMON_DATA
,
.
alt
=
0
,
.
oe
=
5
,
.
pu
=
7
,
.
od
=
9
,
.
rt
=
16
,
};
static
const
struct
st_pctl_data
stih415_front_data
=
{
STIH415_PCTRL_COMMON_DATA
,
.
alt
=
0
,
.
oe
=
8
,
.
pu
=
10
,
.
od
=
12
,
.
rt
=
16
,
};
static
const
struct
st_pctl_data
stih415_rear_data
=
{
STIH415_PCTRL_COMMON_DATA
,
.
alt
=
0
,
.
oe
=
6
,
.
pu
=
8
,
.
od
=
10
,
.
rt
=
38
,
};
static
const
struct
st_pctl_data
stih415_left_data
=
{
STIH415_PCTRL_COMMON_DATA
,
.
alt
=
0
,
.
oe
=
3
,
.
pu
=
4
,
.
od
=
5
,
.
rt
=
6
,
};
static
const
struct
st_pctl_data
stih415_right_data
=
{
STIH415_PCTRL_COMMON_DATA
,
.
alt
=
0
,
.
oe
=
5
,
.
pu
=
7
,
.
od
=
9
,
.
rt
=
11
,
};
/* STiH416 data */
unsigned
int
stih416_delays
[]
=
{
0
,
300
,
500
,
750
,
1000
,
1250
,
1500
,
1750
,
2000
,
2250
,
2500
,
2750
,
3000
,
3250
};
static
const
struct
st_pctl_data
stih416_data
=
{
.
rt_style
=
st_retime_style_dedicated
,
.
input_delays
=
stih416_delays
,
.
ninput_delays
=
14
,
.
output_delays
=
stih416_delays
,
.
noutput_delays
=
14
,
.
alt
=
0
,
.
oe
=
40
,
.
pu
=
50
,
.
od
=
60
,
.
rt
=
100
,
};
/* Low level functions.. */
static
inline
int
st_gpio_bank
(
int
gpio
)
{
return
gpio
/
ST_GPIO_PINS_PER_BANK
;
}
static
inline
int
st_gpio_pin
(
int
gpio
)
{
return
gpio
%
ST_GPIO_PINS_PER_BANK
;
}
static
void
st_pinconf_set_config
(
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
config
)
{
struct
regmap_field
*
output_enable
=
pc
->
oe
;
struct
regmap_field
*
pull_up
=
pc
->
pu
;
struct
regmap_field
*
open_drain
=
pc
->
od
;
unsigned
int
oe_value
,
pu_value
,
od_value
;
unsigned
long
mask
=
BIT
(
pin
);
regmap_field_read
(
output_enable
,
&
oe_value
);
regmap_field_read
(
pull_up
,
&
pu_value
);
regmap_field_read
(
open_drain
,
&
od_value
);
/* Clear old values */
oe_value
&=
~
mask
;
pu_value
&=
~
mask
;
od_value
&=
~
mask
;
if
(
config
&
ST_PINCONF_OE
)
oe_value
|=
mask
;
if
(
config
&
ST_PINCONF_PU
)
pu_value
|=
mask
;
if
(
config
&
ST_PINCONF_OD
)
od_value
|=
mask
;
regmap_field_write
(
output_enable
,
oe_value
);
regmap_field_write
(
pull_up
,
pu_value
);
regmap_field_write
(
open_drain
,
od_value
);
}
static
void
st_pctl_set_function
(
struct
st_pio_control
*
pc
,
int
pin_id
,
int
function
)
{
struct
regmap_field
*
alt
=
pc
->
alt
;
unsigned
int
val
;
int
pin
=
st_gpio_pin
(
pin_id
);
int
offset
=
pin
*
4
;
regmap_field_read
(
alt
,
&
val
);
val
&=
~
(
0xf
<<
offset
);
val
|=
function
<<
offset
;
regmap_field_write
(
alt
,
val
);
}
static
unsigned
long
st_pinconf_delay_to_bit
(
unsigned
int
delay
,
const
struct
st_pctl_data
*
data
,
unsigned
long
config
)
{
unsigned
int
*
delay_times
;
int
num_delay_times
,
i
,
closest_index
=
-
1
;
unsigned
int
closest_divergence
=
UINT_MAX
;
if
(
ST_PINCONF_UNPACK_OE
(
config
))
{
delay_times
=
data
->
output_delays
;
num_delay_times
=
data
->
noutput_delays
;
}
else
{
delay_times
=
data
->
input_delays
;
num_delay_times
=
data
->
ninput_delays
;
}
for
(
i
=
0
;
i
<
num_delay_times
;
i
++
)
{
unsigned
int
divergence
=
abs
(
delay
-
delay_times
[
i
]);
if
(
divergence
==
0
)
return
i
;
if
(
divergence
<
closest_divergence
)
{
closest_divergence
=
divergence
;
closest_index
=
i
;
}
}
pr_warn
(
"Attempt to set delay %d, closest available %d
\n
"
,
delay
,
delay_times
[
closest_index
]);
return
closest_index
;
}
static
unsigned
long
st_pinconf_bit_to_delay
(
unsigned
int
index
,
const
struct
st_pctl_data
*
data
,
unsigned
long
output
)
{
unsigned
int
*
delay_times
;
int
num_delay_times
;
if
(
output
)
{
delay_times
=
data
->
output_delays
;
num_delay_times
=
data
->
noutput_delays
;
}
else
{
delay_times
=
data
->
input_delays
;
num_delay_times
=
data
->
ninput_delays
;
}
if
(
index
<
num_delay_times
)
{
return
delay_times
[
index
];
}
else
{
pr_warn
(
"Delay not found in/out delay list
\n
"
);
return
0
;
}
}
static
void
st_regmap_field_bit_set_clear_pin
(
struct
regmap_field
*
field
,
int
enable
,
int
pin
)
{
unsigned
int
val
=
0
;
regmap_field_read
(
field
,
&
val
);
if
(
enable
)
val
|=
BIT
(
pin
);
else
val
&=
~
BIT
(
pin
);
regmap_field_write
(
field
,
val
);
}
static
void
st_pinconf_set_retime_packed
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
unsigned
long
config
,
int
pin
)
{
const
struct
st_pctl_data
*
data
=
info
->
data
;
struct
st_retime_packed
*
rt_p
=
&
pc
->
rt
.
rt_p
;
unsigned
int
delay
;
st_regmap_field_bit_set_clear_pin
(
rt_p
->
clk1notclk0
,
ST_PINCONF_UNPACK_RT_CLK
(
config
),
pin
);
st_regmap_field_bit_set_clear_pin
(
rt_p
->
clknotdata
,
ST_PINCONF_UNPACK_RT_CLKNOTDATA
(
config
),
pin
);
st_regmap_field_bit_set_clear_pin
(
rt_p
->
double_edge
,
ST_PINCONF_UNPACK_RT_DOUBLE_EDGE
(
config
),
pin
);
st_regmap_field_bit_set_clear_pin
(
rt_p
->
invertclk
,
ST_PINCONF_UNPACK_RT_INVERTCLK
(
config
),
pin
);
st_regmap_field_bit_set_clear_pin
(
rt_p
->
retime
,
ST_PINCONF_UNPACK_RT
(
config
),
pin
);
delay
=
st_pinconf_delay_to_bit
(
ST_PINCONF_UNPACK_RT_DELAY
(
config
),
data
,
config
);
/* 2 bit delay, lsb */
st_regmap_field_bit_set_clear_pin
(
rt_p
->
delay_0
,
delay
&
0x1
,
pin
);
/* 2 bit delay, msb */
st_regmap_field_bit_set_clear_pin
(
rt_p
->
delay_1
,
delay
&
0x2
,
pin
);
}
static
void
st_pinconf_set_retime_dedicated
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
unsigned
long
config
,
int
pin
)
{
int
input
=
ST_PINCONF_UNPACK_OE
(
config
)
?
0
:
1
;
int
clk
=
ST_PINCONF_UNPACK_RT_CLK
(
config
);
int
clknotdata
=
ST_PINCONF_UNPACK_RT_CLKNOTDATA
(
config
);
int
double_edge
=
ST_PINCONF_UNPACK_RT_DOUBLE_EDGE
(
config
);
int
invertclk
=
ST_PINCONF_UNPACK_RT_INVERTCLK
(
config
);
int
retime
=
ST_PINCONF_UNPACK_RT
(
config
);
unsigned
long
delay
=
st_pinconf_delay_to_bit
(
ST_PINCONF_UNPACK_RT_DELAY
(
config
),
info
->
data
,
config
);
struct
st_retime_dedicated
*
rt_d
=
&
pc
->
rt
.
rt_d
;
unsigned
long
retime_config
=
((
clk
)
<<
RT_D_CFG_CLK_SHIFT
)
|
((
delay
)
<<
RT_D_CFG_DELAY_SHIFT
)
|
((
input
)
<<
RT_D_CFG_DELAY_INNOTOUT_SHIFT
)
|
((
retime
)
<<
RT_D_CFG_RETIME_SHIFT
)
|
((
clknotdata
)
<<
RT_D_CFG_CLKNOTDATA_SHIFT
)
|
((
invertclk
)
<<
RT_D_CFG_INVERTCLK_SHIFT
)
|
((
double_edge
)
<<
RT_D_CFG_DOUBLE_EDGE_SHIFT
);
regmap_field_write
(
rt_d
->
rt
[
pin
],
retime_config
);
}
static
void
st_pinconf_get_direction
(
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
*
config
)
{
unsigned
int
oe_value
,
pu_value
,
od_value
;
regmap_field_read
(
pc
->
oe
,
&
oe_value
);
regmap_field_read
(
pc
->
pu
,
&
pu_value
);
regmap_field_read
(
pc
->
od
,
&
od_value
);
if
(
oe_value
&
BIT
(
pin
))
ST_PINCONF_PACK_OE
(
*
config
);
if
(
pu_value
&
BIT
(
pin
))
ST_PINCONF_PACK_PU
(
*
config
);
if
(
od_value
&
BIT
(
pin
))
ST_PINCONF_PACK_OD
(
*
config
);
}
static
int
st_pinconf_get_retime_packed
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
*
config
)
{
const
struct
st_pctl_data
*
data
=
info
->
data
;
struct
st_retime_packed
*
rt_p
=
&
pc
->
rt
.
rt_p
;
unsigned
int
delay_bits
,
delay
,
delay0
,
delay1
,
val
;
int
output
=
ST_PINCONF_UNPACK_OE
(
*
config
);
if
(
!
regmap_field_read
(
rt_p
->
retime
,
&
val
)
&&
(
val
&
BIT
(
pin
)))
ST_PINCONF_PACK_RT
(
*
config
);
if
(
!
regmap_field_read
(
rt_p
->
clk1notclk0
,
&
val
)
&&
(
val
&
BIT
(
pin
)))
ST_PINCONF_PACK_RT_CLK
(
*
config
,
1
);
if
(
!
regmap_field_read
(
rt_p
->
clknotdata
,
&
val
)
&&
(
val
&
BIT
(
pin
)))
ST_PINCONF_PACK_RT_CLKNOTDATA
(
*
config
);
if
(
!
regmap_field_read
(
rt_p
->
double_edge
,
&
val
)
&&
(
val
&
BIT
(
pin
)))
ST_PINCONF_PACK_RT_DOUBLE_EDGE
(
*
config
);
if
(
!
regmap_field_read
(
rt_p
->
invertclk
,
&
val
)
&&
(
val
&
BIT
(
pin
)))
ST_PINCONF_PACK_RT_INVERTCLK
(
*
config
);
regmap_field_read
(
rt_p
->
delay_0
,
&
delay0
);
regmap_field_read
(
rt_p
->
delay_1
,
&
delay1
);
delay_bits
=
(((
delay1
&
BIT
(
pin
))
?
1
:
0
)
<<
1
)
|
(((
delay0
&
BIT
(
pin
))
?
1
:
0
));
delay
=
st_pinconf_bit_to_delay
(
delay_bits
,
data
,
output
);
ST_PINCONF_PACK_RT_DELAY
(
*
config
,
delay
);
return
0
;
}
static
int
st_pinconf_get_retime_dedicated
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
*
config
)
{
unsigned
int
value
;
unsigned
long
delay_bits
,
delay
,
rt_clk
;
int
output
=
ST_PINCONF_UNPACK_OE
(
*
config
);
struct
st_retime_dedicated
*
rt_d
=
&
pc
->
rt
.
rt_d
;
regmap_field_read
(
rt_d
->
rt
[
pin
],
&
value
);
rt_clk
=
(
value
&
RT_D_CFG_CLK_MASK
)
>>
RT_D_CFG_CLK_SHIFT
;
ST_PINCONF_PACK_RT_CLK
(
*
config
,
rt_clk
);
delay_bits
=
(
value
&
RT_D_CFG_DELAY_MASK
)
>>
RT_D_CFG_DELAY_SHIFT
;
delay
=
st_pinconf_bit_to_delay
(
delay_bits
,
info
->
data
,
output
);
ST_PINCONF_PACK_RT_DELAY
(
*
config
,
delay
);
if
(
value
&
RT_D_CFG_CLKNOTDATA_MASK
)
ST_PINCONF_PACK_RT_CLKNOTDATA
(
*
config
);
if
(
value
&
RT_D_CFG_DOUBLE_EDGE_MASK
)
ST_PINCONF_PACK_RT_DOUBLE_EDGE
(
*
config
);
if
(
value
&
RT_D_CFG_INVERTCLK_MASK
)
ST_PINCONF_PACK_RT_INVERTCLK
(
*
config
);
if
(
value
&
RT_D_CFG_RETIME_MASK
)
ST_PINCONF_PACK_RT
(
*
config
);
return
0
;
}
/* GPIO related functions */
static
inline
void
__st_gpio_set
(
struct
st_gpio_bank
*
bank
,
unsigned
offset
,
int
value
)
{
if
(
value
)
writel
(
BIT
(
offset
),
bank
->
base
+
REG_PIO_SET_POUT
);
else
writel
(
BIT
(
offset
),
bank
->
base
+
REG_PIO_CLR_POUT
);
}
static
void
st_gpio_direction
(
struct
st_gpio_bank
*
bank
,
unsigned
int
gpio
,
unsigned
int
direction
)
{
int
offset
=
st_gpio_pin
(
gpio
);
int
i
=
0
;
/**
* There are three configuration registers (PIOn_PC0, PIOn_PC1
* and PIOn_PC2) for each port. These are used to configure the
* PIO port pins. Each pin can be configured as an input, output,
* bidirectional, or alternative function pin. Three bits, one bit
* from each of the three registers, configure the corresponding bit of
* the port. Valid bit settings is:
*
* PC2 PC1 PC0 Direction.
* 0 0 0 [Input Weak pull-up]
* 0 0 or 1 1 [Bidirection]
* 0 1 0 [Output]
* 1 0 0 [Input]
*
* PIOn_SET_PC and PIOn_CLR_PC registers are used to set and clear bits
* individually.
*/
for
(
i
=
0
;
i
<=
2
;
i
++
)
{
if
(
direction
&
BIT
(
i
))
writel
(
BIT
(
offset
),
bank
->
base
+
REG_PIO_SET_PC
(
i
));
else
writel
(
BIT
(
offset
),
bank
->
base
+
REG_PIO_CLR_PC
(
i
));
}
}
static
int
st_gpio_request
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
return
pinctrl_request_gpio
(
chip
->
base
+
offset
);
}
static
void
st_gpio_free
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
pinctrl_free_gpio
(
chip
->
base
+
offset
);
}
static
int
st_gpio_get
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
st_gpio_bank
*
bank
=
gpio_chip_to_bank
(
chip
);
return
!!
(
readl
(
bank
->
base
+
REG_PIO_PIN
)
&
BIT
(
offset
));
}
static
void
st_gpio_set
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
value
)
{
struct
st_gpio_bank
*
bank
=
gpio_chip_to_bank
(
chip
);
__st_gpio_set
(
bank
,
offset
,
value
);
}
static
int
st_gpio_direction_input
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
pinctrl_gpio_direction_input
(
chip
->
base
+
offset
);
return
0
;
}
static
int
st_gpio_direction_output
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
value
)
{
struct
st_gpio_bank
*
bank
=
gpio_chip_to_bank
(
chip
);
__st_gpio_set
(
bank
,
offset
,
value
);
pinctrl_gpio_direction_output
(
chip
->
base
+
offset
);
return
0
;
}
static
int
st_gpio_xlate
(
struct
gpio_chip
*
gc
,
const
struct
of_phandle_args
*
gpiospec
,
u32
*
flags
)
{
if
(
WARN_ON
(
gc
->
of_gpio_n_cells
<
1
))
return
-
EINVAL
;
if
(
WARN_ON
(
gpiospec
->
args_count
<
gc
->
of_gpio_n_cells
))
return
-
EINVAL
;
if
(
gpiospec
->
args
[
0
]
>
gc
->
ngpio
)
return
-
EINVAL
;
return
gpiospec
->
args
[
0
];
}
/* Pinctrl Groups */
static
int
st_pctl_get_groups_count
(
struct
pinctrl_dev
*
pctldev
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
info
->
ngroups
;
}
static
const
char
*
st_pctl_get_group_name
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
info
->
groups
[
selector
].
name
;
}
static
int
st_pctl_get_group_pins
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
,
const
unsigned
**
pins
,
unsigned
*
npins
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
if
(
selector
>=
info
->
ngroups
)
return
-
EINVAL
;
*
pins
=
info
->
groups
[
selector
].
pins
;
*
npins
=
info
->
groups
[
selector
].
npins
;
return
0
;
}
static
const
inline
struct
st_pctl_group
*
st_pctl_find_group_by_name
(
const
struct
st_pinctrl
*
info
,
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
info
->
ngroups
;
i
++
)
{
if
(
!
strcmp
(
info
->
groups
[
i
].
name
,
name
))
return
&
info
->
groups
[
i
];
}
return
NULL
;
}
static
int
st_pctl_dt_node_to_map
(
struct
pinctrl_dev
*
pctldev
,
struct
device_node
*
np
,
struct
pinctrl_map
**
map
,
unsigned
*
num_maps
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
const
struct
st_pctl_group
*
grp
;
struct
pinctrl_map
*
new_map
;
struct
device_node
*
parent
;
int
map_num
,
i
;
grp
=
st_pctl_find_group_by_name
(
info
,
np
->
name
);
if
(
!
grp
)
{
dev_err
(
info
->
dev
,
"unable to find group for node %s
\n
"
,
np
->
name
);
return
-
EINVAL
;
}
map_num
=
grp
->
npins
+
1
;
new_map
=
devm_kzalloc
(
pctldev
->
dev
,
sizeof
(
*
new_map
)
*
map_num
,
GFP_KERNEL
);
if
(
!
new_map
)
return
-
ENOMEM
;
parent
=
of_get_parent
(
np
);
if
(
!
parent
)
{
devm_kfree
(
pctldev
->
dev
,
new_map
);
return
-
EINVAL
;
}
*
map
=
new_map
;
*
num_maps
=
map_num
;
new_map
[
0
].
type
=
PIN_MAP_TYPE_MUX_GROUP
;
new_map
[
0
].
data
.
mux
.
function
=
parent
->
name
;
new_map
[
0
].
data
.
mux
.
group
=
np
->
name
;
of_node_put
(
parent
);
/* create config map per pin */
new_map
++
;
for
(
i
=
0
;
i
<
grp
->
npins
;
i
++
)
{
new_map
[
i
].
type
=
PIN_MAP_TYPE_CONFIGS_PIN
;
new_map
[
i
].
data
.
configs
.
group_or_pin
=
pin_get_name
(
pctldev
,
grp
->
pins
[
i
]);
new_map
[
i
].
data
.
configs
.
configs
=
&
grp
->
pin_conf
[
i
].
config
;
new_map
[
i
].
data
.
configs
.
num_configs
=
1
;
}
dev_info
(
pctldev
->
dev
,
"maps: function %s group %s num %d
\n
"
,
(
*
map
)
->
data
.
mux
.
function
,
grp
->
name
,
map_num
);
return
0
;
}
static
void
st_pctl_dt_free_map
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_map
*
map
,
unsigned
num_maps
)
{
}
static
struct
pinctrl_ops
st_pctlops
=
{
.
get_groups_count
=
st_pctl_get_groups_count
,
.
get_group_pins
=
st_pctl_get_group_pins
,
.
get_group_name
=
st_pctl_get_group_name
,
.
dt_node_to_map
=
st_pctl_dt_node_to_map
,
.
dt_free_map
=
st_pctl_dt_free_map
,
};
/* Pinmux */
static
int
st_pmx_get_funcs_count
(
struct
pinctrl_dev
*
pctldev
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
info
->
nfunctions
;
}
const
char
*
st_pmx_get_fname
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
info
->
functions
[
selector
].
name
;
}
static
int
st_pmx_get_groups
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
,
const
char
*
const
**
grps
,
unsigned
*
const
ngrps
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
*
grps
=
info
->
functions
[
selector
].
groups
;
*
ngrps
=
info
->
functions
[
selector
].
ngroups
;
return
0
;
}
static
struct
st_pio_control
*
st_get_pio_control
(
struct
pinctrl_dev
*
pctldev
,
int
pin
)
{
struct
pinctrl_gpio_range
*
range
=
pinctrl_find_gpio_range_from_pin
(
pctldev
,
pin
);
struct
st_gpio_bank
*
bank
=
gpio_range_to_bank
(
range
);
return
&
bank
->
pc
;
}
static
int
st_pmx_enable
(
struct
pinctrl_dev
*
pctldev
,
unsigned
fselector
,
unsigned
group
)
{
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
st_pinconf
*
conf
=
info
->
groups
[
group
].
pin_conf
;
struct
st_pio_control
*
pc
;
int
i
;
for
(
i
=
0
;
i
<
info
->
groups
[
group
].
npins
;
i
++
)
{
pc
=
st_get_pio_control
(
pctldev
,
conf
[
i
].
pin
);
st_pctl_set_function
(
pc
,
conf
[
i
].
pin
,
conf
[
i
].
altfunc
);
}
return
0
;
}
static
void
st_pmx_disable
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
,
unsigned
group
)
{
}
static
int
st_pmx_set_gpio_direction
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_gpio_range
*
range
,
unsigned
gpio
,
bool
input
)
{
struct
st_gpio_bank
*
bank
=
gpio_range_to_bank
(
range
);
/*
* When a PIO bank is used in its primary function mode (altfunc = 0)
* Output Enable (OE), Open Drain(OD), and Pull Up (PU)
* for the primary PIO functions are driven by the related PIO block
*/
st_pctl_set_function
(
&
bank
->
pc
,
gpio
,
0
);
st_gpio_direction
(
bank
,
gpio
,
input
?
ST_GPIO_DIRECTION_IN
:
ST_GPIO_DIRECTION_OUT
);
return
0
;
}
static
struct
pinmux_ops
st_pmxops
=
{
.
get_functions_count
=
st_pmx_get_funcs_count
,
.
get_function_name
=
st_pmx_get_fname
,
.
get_function_groups
=
st_pmx_get_groups
,
.
enable
=
st_pmx_enable
,
.
disable
=
st_pmx_disable
,
.
gpio_set_direction
=
st_pmx_set_gpio_direction
,
};
/* Pinconf */
static
void
st_pinconf_get_retime
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
*
config
)
{
if
(
info
->
data
->
rt_style
==
st_retime_style_packed
)
st_pinconf_get_retime_packed
(
info
,
pc
,
pin
,
config
);
else
if
(
info
->
data
->
rt_style
==
st_retime_style_dedicated
)
if
((
BIT
(
pin
)
&
pc
->
rt_pin_mask
))
st_pinconf_get_retime_dedicated
(
info
,
pc
,
pin
,
config
);
}
static
void
st_pinconf_set_retime
(
struct
st_pinctrl
*
info
,
struct
st_pio_control
*
pc
,
int
pin
,
unsigned
long
config
)
{
if
(
info
->
data
->
rt_style
==
st_retime_style_packed
)
st_pinconf_set_retime_packed
(
info
,
pc
,
config
,
pin
);
else
if
(
info
->
data
->
rt_style
==
st_retime_style_dedicated
)
if
((
BIT
(
pin
)
&
pc
->
rt_pin_mask
))
st_pinconf_set_retime_dedicated
(
info
,
pc
,
config
,
pin
);
}
static
int
st_pinconf_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
pin_id
,
unsigned
long
config
)
{
int
pin
=
st_gpio_pin
(
pin_id
);
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
st_pio_control
*
pc
=
st_get_pio_control
(
pctldev
,
pin_id
);
st_pinconf_set_config
(
pc
,
pin
,
config
);
st_pinconf_set_retime
(
info
,
pc
,
pin
,
config
);
return
0
;
}
static
int
st_pinconf_get
(
struct
pinctrl_dev
*
pctldev
,
unsigned
pin_id
,
unsigned
long
*
config
)
{
int
pin
=
st_gpio_pin
(
pin_id
);
struct
st_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
st_pio_control
*
pc
=
st_get_pio_control
(
pctldev
,
pin_id
);
*
config
=
0
;
st_pinconf_get_direction
(
pc
,
pin
,
config
);
st_pinconf_get_retime
(
info
,
pc
,
pin
,
config
);
return
0
;
}
static
void
st_pinconf_dbg_show
(
struct
pinctrl_dev
*
pctldev
,
struct
seq_file
*
s
,
unsigned
pin_id
)
{
unsigned
long
config
;
st_pinconf_get
(
pctldev
,
pin_id
,
&
config
);
seq_printf
(
s
,
"[OE:%ld,PU:%ld,OD:%ld]
\n
"
"
\t\t
[retime:%ld,invclk:%ld,clknotdat:%ld,"
"de:%ld,rt-clk:%ld,rt-delay:%ld]"
,
ST_PINCONF_UNPACK_OE
(
config
),
ST_PINCONF_UNPACK_PU
(
config
),
ST_PINCONF_UNPACK_OD
(
config
),
ST_PINCONF_UNPACK_RT
(
config
),
ST_PINCONF_UNPACK_RT_INVERTCLK
(
config
),
ST_PINCONF_UNPACK_RT_CLKNOTDATA
(
config
),
ST_PINCONF_UNPACK_RT_DOUBLE_EDGE
(
config
),
ST_PINCONF_UNPACK_RT_CLK
(
config
),
ST_PINCONF_UNPACK_RT_DELAY
(
config
));
}
static
struct
pinconf_ops
st_confops
=
{
.
pin_config_get
=
st_pinconf_get
,
.
pin_config_set
=
st_pinconf_set
,
.
pin_config_dbg_show
=
st_pinconf_dbg_show
,
};
static
void
st_pctl_dt_child_count
(
struct
st_pinctrl
*
info
,
struct
device_node
*
np
)
{
struct
device_node
*
child
;
for_each_child_of_node
(
np
,
child
)
{
if
(
of_property_read_bool
(
child
,
"gpio-controller"
))
{
info
->
nbanks
++
;
}
else
{
info
->
nfunctions
++
;
info
->
ngroups
+=
of_get_child_count
(
child
);
}
}
}
static
int
st_pctl_dt_setup_retime_packed
(
struct
st_pinctrl
*
info
,
int
bank
,
struct
st_pio_control
*
pc
)
{
struct
device
*
dev
=
info
->
dev
;
struct
regmap
*
rm
=
info
->
regmap
;
const
struct
st_pctl_data
*
data
=
info
->
data
;
/* 2 registers per bank */
int
reg
=
(
data
->
rt
+
bank
*
RT_P_CFGS_PER_BANK
)
*
4
;
struct
st_retime_packed
*
rt_p
=
&
pc
->
rt
.
rt_p
;
/* cfg0 */
struct
reg_field
clk1notclk0
=
RT_P_CFG0_CLK1NOTCLK0_FIELD
(
reg
);
struct
reg_field
delay_0
=
RT_P_CFG0_DELAY_0_FIELD
(
reg
);
struct
reg_field
delay_1
=
RT_P_CFG0_DELAY_1_FIELD
(
reg
);
/* cfg1 */
struct
reg_field
invertclk
=
RT_P_CFG1_INVERTCLK_FIELD
(
reg
+
4
);
struct
reg_field
retime
=
RT_P_CFG1_RETIME_FIELD
(
reg
+
4
);
struct
reg_field
clknotdata
=
RT_P_CFG1_CLKNOTDATA_FIELD
(
reg
+
4
);
struct
reg_field
double_edge
=
RT_P_CFG1_DOUBLE_EDGE_FIELD
(
reg
+
4
);
rt_p
->
clk1notclk0
=
devm_regmap_field_alloc
(
dev
,
rm
,
clk1notclk0
);
rt_p
->
delay_0
=
devm_regmap_field_alloc
(
dev
,
rm
,
delay_0
);
rt_p
->
delay_1
=
devm_regmap_field_alloc
(
dev
,
rm
,
delay_1
);
rt_p
->
invertclk
=
devm_regmap_field_alloc
(
dev
,
rm
,
invertclk
);
rt_p
->
retime
=
devm_regmap_field_alloc
(
dev
,
rm
,
retime
);
rt_p
->
clknotdata
=
devm_regmap_field_alloc
(
dev
,
rm
,
clknotdata
);
rt_p
->
double_edge
=
devm_regmap_field_alloc
(
dev
,
rm
,
double_edge
);
if
(
IS_ERR
(
rt_p
->
clk1notclk0
)
||
IS_ERR
(
rt_p
->
delay_0
)
||
IS_ERR
(
rt_p
->
delay_1
)
||
IS_ERR
(
rt_p
->
invertclk
)
||
IS_ERR
(
rt_p
->
retime
)
||
IS_ERR
(
rt_p
->
clknotdata
)
||
IS_ERR
(
rt_p
->
double_edge
))
return
-
EINVAL
;
return
0
;
}
static
int
st_pctl_dt_setup_retime_dedicated
(
struct
st_pinctrl
*
info
,
int
bank
,
struct
st_pio_control
*
pc
)
{
struct
device
*
dev
=
info
->
dev
;
struct
regmap
*
rm
=
info
->
regmap
;
const
struct
st_pctl_data
*
data
=
info
->
data
;
/* 8 registers per bank */
int
reg_offset
=
(
data
->
rt
+
bank
*
RT_D_CFGS_PER_BANK
)
*
4
;
struct
st_retime_dedicated
*
rt_d
=
&
pc
->
rt
.
rt_d
;
unsigned
int
j
;
u32
pin_mask
=
pc
->
rt_pin_mask
;
for
(
j
=
0
;
j
<
RT_D_CFGS_PER_BANK
;
j
++
)
{
if
(
BIT
(
j
)
&
pin_mask
)
{
struct
reg_field
reg
=
REG_FIELD
(
reg_offset
,
0
,
31
);
rt_d
->
rt
[
j
]
=
devm_regmap_field_alloc
(
dev
,
rm
,
reg
);
if
(
IS_ERR
(
rt_d
->
rt
[
j
]))
return
-
EINVAL
;
reg_offset
+=
4
;
}
}
return
0
;
}
static
int
st_pctl_dt_setup_retime
(
struct
st_pinctrl
*
info
,
int
bank
,
struct
st_pio_control
*
pc
)
{
const
struct
st_pctl_data
*
data
=
info
->
data
;
if
(
data
->
rt_style
==
st_retime_style_packed
)
return
st_pctl_dt_setup_retime_packed
(
info
,
bank
,
pc
);
else
if
(
data
->
rt_style
==
st_retime_style_dedicated
)
return
st_pctl_dt_setup_retime_dedicated
(
info
,
bank
,
pc
);
return
-
EINVAL
;
}
static
int
st_parse_syscfgs
(
struct
st_pinctrl
*
info
,
int
bank
,
struct
device_node
*
np
)
{
const
struct
st_pctl_data
*
data
=
info
->
data
;
/**
* For a given shared register like OE/PU/OD, there are 8 bits per bank
* 0:7 belongs to bank0, 8:15 belongs to bank1 ...
* So each register is shared across 4 banks.
*/
int
lsb
=
(
bank
%
4
)
*
ST_GPIO_PINS_PER_BANK
;
int
msb
=
lsb
+
ST_GPIO_PINS_PER_BANK
-
1
;
struct
reg_field
alt_reg
=
REG_FIELD
((
data
->
alt
+
bank
)
*
4
,
0
,
31
);
struct
reg_field
oe_reg
=
REG_FIELD
((
data
->
oe
+
bank
/
4
)
*
4
,
lsb
,
msb
);
struct
reg_field
pu_reg
=
REG_FIELD
((
data
->
pu
+
bank
/
4
)
*
4
,
lsb
,
msb
);
struct
reg_field
od_reg
=
REG_FIELD
((
data
->
od
+
bank
/
4
)
*
4
,
lsb
,
msb
);
struct
st_pio_control
*
pc
=
&
info
->
banks
[
bank
].
pc
;
struct
device
*
dev
=
info
->
dev
;
struct
regmap
*
regmap
=
info
->
regmap
;
pc
->
alt
=
devm_regmap_field_alloc
(
dev
,
regmap
,
alt_reg
);
pc
->
oe
=
devm_regmap_field_alloc
(
dev
,
regmap
,
oe_reg
);
pc
->
pu
=
devm_regmap_field_alloc
(
dev
,
regmap
,
pu_reg
);
pc
->
od
=
devm_regmap_field_alloc
(
dev
,
regmap
,
od_reg
);
if
(
IS_ERR
(
pc
->
alt
)
||
IS_ERR
(
pc
->
oe
)
||
IS_ERR
(
pc
->
pu
)
||
IS_ERR
(
pc
->
od
))
return
-
EINVAL
;
/* retime avaiable for all pins by default */
pc
->
rt_pin_mask
=
0xff
;
of_property_read_u32
(
np
,
"st,retime-pin-mask"
,
&
pc
->
rt_pin_mask
);
st_pctl_dt_setup_retime
(
info
,
bank
,
pc
);
return
0
;
}
/*
* Each pin is represented in of the below forms.
* <bank offset mux direction rt_type rt_delay rt_clk>
*/
static
int
st_pctl_dt_parse_groups
(
struct
device_node
*
np
,
struct
st_pctl_group
*
grp
,
struct
st_pinctrl
*
info
,
int
idx
)
{
/* bank pad direction val altfunction */
const
__be32
*
list
;
struct
property
*
pp
;
struct
st_pinconf
*
conf
;
phandle
phandle
;
struct
device_node
*
pins
;
u32
pin
;
int
i
=
0
,
npins
=
0
,
nr_props
;
pins
=
of_get_child_by_name
(
np
,
"st,pins"
);
if
(
!
pins
)
return
-
ENODATA
;
for_each_property_of_node
(
pins
,
pp
)
{
/* Skip those we do not want to proceed */
if
(
!
strcmp
(
pp
->
name
,
"name"
))
continue
;
if
(
pp
&&
(
pp
->
length
/
sizeof
(
__be32
))
>=
OF_GPIO_ARGS_MIN
)
{
npins
++
;
}
else
{
pr_warn
(
"Invalid st,pins in %s node
\n
"
,
np
->
name
);
return
-
EINVAL
;
}
}
grp
->
npins
=
npins
;
grp
->
name
=
np
->
name
;
grp
->
pins
=
devm_kzalloc
(
info
->
dev
,
npins
*
sizeof
(
u32
),
GFP_KERNEL
);
grp
->
pin_conf
=
devm_kzalloc
(
info
->
dev
,
npins
*
sizeof
(
*
conf
),
GFP_KERNEL
);
if
(
!
grp
->
pins
||
!
grp
->
pin_conf
)
return
-
ENOMEM
;
/* <bank offset mux direction rt_type rt_delay rt_clk> */
for_each_property_of_node
(
pins
,
pp
)
{
if
(
!
strcmp
(
pp
->
name
,
"name"
))
continue
;
nr_props
=
pp
->
length
/
sizeof
(
u32
);
list
=
pp
->
value
;
conf
=
&
grp
->
pin_conf
[
i
];
/* bank & offset */
phandle
=
be32_to_cpup
(
list
++
);
pin
=
be32_to_cpup
(
list
++
);
conf
->
pin
=
of_get_named_gpio
(
pins
,
pp
->
name
,
0
);
conf
->
name
=
pp
->
name
;
grp
->
pins
[
i
]
=
conf
->
pin
;
/* mux */
conf
->
altfunc
=
be32_to_cpup
(
list
++
);
conf
->
config
=
0
;
/* direction */
conf
->
config
|=
be32_to_cpup
(
list
++
);
/* rt_type rt_delay rt_clk */
if
(
nr_props
>=
OF_GPIO_ARGS_MIN
+
OF_RT_ARGS_MIN
)
{
/* rt_type */
conf
->
config
|=
be32_to_cpup
(
list
++
);
/* rt_delay */
conf
->
config
|=
be32_to_cpup
(
list
++
);
/* rt_clk */
if
(
nr_props
>
OF_GPIO_ARGS_MIN
+
OF_RT_ARGS_MIN
)
conf
->
config
|=
be32_to_cpup
(
list
++
);
}
i
++
;
}
of_node_put
(
pins
);
return
0
;
}
static
int
st_pctl_parse_functions
(
struct
device_node
*
np
,
struct
st_pinctrl
*
info
,
u32
index
,
int
*
grp_index
)
{
struct
device_node
*
child
;
struct
st_pmx_func
*
func
;
struct
st_pctl_group
*
grp
;
int
ret
,
i
;
func
=
&
info
->
functions
[
index
];
func
->
name
=
np
->
name
;
func
->
ngroups
=
of_get_child_count
(
np
);
if
(
func
->
ngroups
<=
0
)
{
dev_err
(
info
->
dev
,
"No groups defined
\n
"
);
return
-
EINVAL
;
}
func
->
groups
=
devm_kzalloc
(
info
->
dev
,
func
->
ngroups
*
sizeof
(
char
*
),
GFP_KERNEL
);
if
(
!
func
->
groups
)
return
-
ENOMEM
;
i
=
0
;
for_each_child_of_node
(
np
,
child
)
{
func
->
groups
[
i
]
=
child
->
name
;
grp
=
&
info
->
groups
[
*
grp_index
];
*
grp_index
+=
1
;
ret
=
st_pctl_dt_parse_groups
(
child
,
grp
,
info
,
i
++
);
if
(
ret
)
return
ret
;
}
dev_info
(
info
->
dev
,
"Function[%d
\t
name:%s,
\t
groups:%d]
\n
"
,
index
,
func
->
name
,
func
->
ngroups
);
return
0
;
}
static
struct
gpio_chip
st_gpio_template
=
{
.
request
=
st_gpio_request
,
.
free
=
st_gpio_free
,
.
get
=
st_gpio_get
,
.
set
=
st_gpio_set
,
.
direction_input
=
st_gpio_direction_input
,
.
direction_output
=
st_gpio_direction_output
,
.
ngpio
=
ST_GPIO_PINS_PER_BANK
,
.
of_gpio_n_cells
=
1
,
.
of_xlate
=
st_gpio_xlate
,
};
static
int
st_gpiolib_register_bank
(
struct
st_pinctrl
*
info
,
int
bank_nr
,
struct
device_node
*
np
)
{
struct
st_gpio_bank
*
bank
=
&
info
->
banks
[
bank_nr
];
struct
pinctrl_gpio_range
*
range
=
&
bank
->
range
;
struct
device
*
dev
=
info
->
dev
;
int
bank_num
=
of_alias_get_id
(
np
,
"gpio"
);
struct
resource
res
;
int
err
;
if
(
of_address_to_resource
(
np
,
0
,
&
res
))
return
-
ENODEV
;
bank
->
base
=
devm_request_and_ioremap
(
dev
,
&
res
);
if
(
!
bank
->
base
)
{
dev_err
(
dev
,
"Can't get IO memory mapping!
\n
"
);
return
-
ENODEV
;
}
bank
->
gpio_chip
=
st_gpio_template
;
bank
->
gpio_chip
.
base
=
bank_num
*
ST_GPIO_PINS_PER_BANK
;
bank
->
gpio_chip
.
ngpio
=
ST_GPIO_PINS_PER_BANK
;
bank
->
gpio_chip
.
of_node
=
np
;
of_property_read_string
(
np
,
"st,bank-name"
,
&
range
->
name
);
bank
->
gpio_chip
.
label
=
range
->
name
;
range
->
id
=
bank_num
;
range
->
pin_base
=
range
->
base
=
range
->
id
*
ST_GPIO_PINS_PER_BANK
;
range
->
npins
=
bank
->
gpio_chip
.
ngpio
;
range
->
gc
=
&
bank
->
gpio_chip
;
err
=
gpiochip_add
(
&
bank
->
gpio_chip
);
if
(
err
)
{
dev_err
(
dev
,
"Failed to add gpiochip(%d)!
\n
"
,
bank_num
);
return
err
;
}
dev_info
(
dev
,
"%s bank added.
\n
"
,
range
->
name
);
return
0
;
}
static
struct
of_device_id
st_pctl_of_match
[]
=
{
{
.
compatible
=
"st,stih415-sbc-pinctrl"
,
.
data
=
&
stih415_sbc_data
},
{
.
compatible
=
"st,stih415-rear-pinctrl"
,
.
data
=
&
stih415_rear_data
},
{
.
compatible
=
"st,stih415-left-pinctrl"
,
.
data
=
&
stih415_left_data
},
{
.
compatible
=
"st,stih415-right-pinctrl"
,
.
data
=
&
stih415_right_data
},
{
.
compatible
=
"st,stih415-front-pinctrl"
,
.
data
=
&
stih415_front_data
},
{
.
compatible
=
"st,stih416-sbc-pinctrl"
,
.
data
=
&
stih416_data
},
{
.
compatible
=
"st,stih416-front-pinctrl"
,
.
data
=
&
stih416_data
},
{
.
compatible
=
"st,stih416-rear-pinctrl"
,
.
data
=
&
stih416_data
},
{
.
compatible
=
"st,stih416-fvdp-fe-pinctrl"
,
.
data
=
&
stih416_data
},
{
.
compatible
=
"st,stih416-fvdp-lite-pinctrl"
,
.
data
=
&
stih416_data
},
{
/* sentinel */
}
};
static
int
st_pctl_probe_dt
(
struct
platform_device
*
pdev
,
struct
pinctrl_desc
*
pctl_desc
,
struct
st_pinctrl
*
info
)
{
int
ret
=
0
;
int
i
=
0
,
j
=
0
,
k
=
0
,
bank
;
struct
pinctrl_pin_desc
*
pdesc
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
child
;
int
grp_index
=
0
;
st_pctl_dt_child_count
(
info
,
np
);
if
(
!
info
->
nbanks
)
{
dev_err
(
&
pdev
->
dev
,
"you need atleast one gpio bank
\n
"
);
return
-
EINVAL
;
}
dev_info
(
&
pdev
->
dev
,
"nbanks = %d
\n
"
,
info
->
nbanks
);
dev_info
(
&
pdev
->
dev
,
"nfunctions = %d
\n
"
,
info
->
nfunctions
);
dev_info
(
&
pdev
->
dev
,
"ngroups = %d
\n
"
,
info
->
ngroups
);
info
->
functions
=
devm_kzalloc
(
&
pdev
->
dev
,
info
->
nfunctions
*
sizeof
(
*
info
->
functions
),
GFP_KERNEL
);
info
->
groups
=
devm_kzalloc
(
&
pdev
->
dev
,
info
->
ngroups
*
sizeof
(
*
info
->
groups
)
,
GFP_KERNEL
);
info
->
banks
=
devm_kzalloc
(
&
pdev
->
dev
,
info
->
nbanks
*
sizeof
(
*
info
->
banks
),
GFP_KERNEL
);
if
(
!
info
->
functions
||
!
info
->
groups
||
!
info
->
banks
)
return
-
ENOMEM
;
info
->
regmap
=
syscon_regmap_lookup_by_phandle
(
np
,
"st,syscfg"
);
if
(
IS_ERR
(
info
->
regmap
))
{
dev_err
(
info
->
dev
,
"No syscfg phandle specified
\n
"
);
return
PTR_ERR
(
info
->
regmap
);
}
info
->
data
=
of_match_node
(
st_pctl_of_match
,
np
)
->
data
;
pctl_desc
->
npins
=
info
->
nbanks
*
ST_GPIO_PINS_PER_BANK
;
pdesc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pdesc
)
*
pctl_desc
->
npins
,
GFP_KERNEL
);
if
(
!
pdesc
)
return
-
ENOMEM
;
pctl_desc
->
pins
=
pdesc
;
bank
=
0
;
for_each_child_of_node
(
np
,
child
)
{
if
(
of_property_read_bool
(
child
,
"gpio-controller"
))
{
const
char
*
bank_name
=
NULL
;
ret
=
st_gpiolib_register_bank
(
info
,
bank
,
child
);
if
(
ret
)
return
ret
;
k
=
info
->
banks
[
bank
].
range
.
pin_base
;
bank_name
=
info
->
banks
[
bank
].
range
.
name
;
for
(
j
=
0
;
j
<
ST_GPIO_PINS_PER_BANK
;
j
++
,
k
++
)
{
pdesc
->
number
=
k
;
pdesc
->
name
=
kasprintf
(
GFP_KERNEL
,
"%s[%d]"
,
bank_name
,
j
);
pdesc
++
;
}
st_parse_syscfgs
(
info
,
bank
,
child
);
bank
++
;
}
else
{
ret
=
st_pctl_parse_functions
(
child
,
info
,
i
++
,
&
grp_index
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"No functions found.
\n
"
);
return
ret
;
}
}
}
return
0
;
}
static
int
st_pctl_probe
(
struct
platform_device
*
pdev
)
{
struct
st_pinctrl
*
info
;
struct
pinctrl_desc
*
pctl_desc
;
int
ret
,
i
;
if
(
!
pdev
->
dev
.
of_node
)
{
dev_err
(
&
pdev
->
dev
,
"device node not found.
\n
"
);
return
-
EINVAL
;
}
pctl_desc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pctl_desc
),
GFP_KERNEL
);
if
(
!
pctl_desc
)
return
-
ENOMEM
;
info
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
info
),
GFP_KERNEL
);
if
(
!
info
)
return
-
ENOMEM
;
info
->
dev
=
&
pdev
->
dev
;
platform_set_drvdata
(
pdev
,
info
);
ret
=
st_pctl_probe_dt
(
pdev
,
pctl_desc
,
info
);
if
(
ret
)
return
ret
;
pctl_desc
->
owner
=
THIS_MODULE
,
pctl_desc
->
pctlops
=
&
st_pctlops
,
pctl_desc
->
pmxops
=
&
st_pmxops
,
pctl_desc
->
confops
=
&
st_confops
,
pctl_desc
->
name
=
dev_name
(
&
pdev
->
dev
);
info
->
pctl
=
pinctrl_register
(
pctl_desc
,
&
pdev
->
dev
,
info
);
if
(
!
info
->
pctl
)
{
dev_err
(
&
pdev
->
dev
,
"Failed pinctrl registration
\n
"
);
return
-
EINVAL
;
}
for
(
i
=
0
;
i
<
info
->
nbanks
;
i
++
)
pinctrl_add_gpio_range
(
info
->
pctl
,
&
info
->
banks
[
i
].
range
);
return
0
;
}
static
struct
platform_driver
st_pctl_driver
=
{
.
driver
=
{
.
name
=
"st-pinctrl"
,
.
owner
=
THIS_MODULE
,
.
of_match_table
=
st_pctl_of_match
,
},
.
probe
=
st_pctl_probe
,
};
static
int
__init
st_pctl_init
(
void
)
{
return
platform_driver_register
(
&
st_pctl_driver
);
}
arch_initcall
(
st_pctl_init
);
include/linux/regmap.h
View file @
7bc8c4c3
...
...
@@ -23,6 +23,7 @@ struct irq_domain;
struct
spi_device
;
struct
regmap
;
struct
regmap_range_cfg
;
struct
regmap_field
;
/* An enum of all the supported cache types */
enum
regcache_type
{
...
...
@@ -416,6 +417,36 @@ bool regmap_reg_in_ranges(unsigned int reg,
const
struct
regmap_range
*
ranges
,
unsigned
int
nranges
);
/**
* Description of an register field
*
* @reg: Offset of the register within the regmap bank
* @lsb: lsb of the register field.
* @reg: msb of the register field.
*/
struct
reg_field
{
unsigned
int
reg
;
unsigned
int
lsb
;
unsigned
int
msb
;
};
#define REG_FIELD(_reg, _lsb, _msb) { \
.reg = _reg, \
.lsb = _lsb, \
.msb = _msb, \
}
struct
regmap_field
*
regmap_field_alloc
(
struct
regmap
*
regmap
,
struct
reg_field
reg_field
);
void
regmap_field_free
(
struct
regmap_field
*
field
);
struct
regmap_field
*
devm_regmap_field_alloc
(
struct
device
*
dev
,
struct
regmap
*
regmap
,
struct
reg_field
reg_field
);
void
devm_regmap_field_free
(
struct
device
*
dev
,
struct
regmap_field
*
field
);
int
regmap_field_read
(
struct
regmap_field
*
field
,
unsigned
int
*
val
);
int
regmap_field_write
(
struct
regmap_field
*
field
,
unsigned
int
val
);
/**
* Description of an IRQ for the generic regmap irq_chip.
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment