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
0dda8b01
Commit
0dda8b01
authored
Aug 17, 2021
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-rockchip' into devel
parents
8cd99e3e
9ce9a020
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1089 additions
and
892 deletions
+1089
-892
Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml
...entation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml
+4
-1
drivers/gpio/Kconfig
drivers/gpio/Kconfig
+8
-0
drivers/gpio/Makefile
drivers/gpio/Makefile
+1
-0
drivers/gpio/gpio-rockchip.c
drivers/gpio/gpio-rockchip.c
+771
-0
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-rockchip.c
+18
-891
drivers/pinctrl/pinctrl-rockchip.h
drivers/pinctrl/pinctrl-rockchip.h
+287
-0
No files found.
Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml
View file @
0dda8b01
...
@@ -22,7 +22,10 @@ properties:
...
@@ -22,7 +22,10 @@ properties:
maxItems
:
1
maxItems
:
1
clocks
:
clocks
:
maxItems
:
1
minItems
:
1
items
:
-
description
:
APB interface clock source
-
description
:
GPIO debounce reference clock source
gpio-controller
:
true
gpio-controller
:
true
...
...
drivers/gpio/Kconfig
View file @
0dda8b01
...
@@ -520,6 +520,14 @@ config GPIO_REG
...
@@ -520,6 +520,14 @@ config GPIO_REG
A 32-bit single register GPIO fixed in/out implementation. This
A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals.
can be used to represent any register as a set of GPIO signals.
config GPIO_ROCKCHIP
tristate "Rockchip GPIO support"
depends on ARCH_ROCKCHIP || COMPILE_TEST
select GPIOLIB_IRQCHIP
default ARCH_ROCKCHIP
help
Say yes here to support GPIO on Rockchip SoCs.
config GPIO_SAMA5D2_PIOBU
config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
depends on MFD_SYSCON
...
...
drivers/gpio/Makefile
View file @
0dda8b01
...
@@ -128,6 +128,7 @@ obj-$(CONFIG_GPIO_RDA) += gpio-rda.o
...
@@ -128,6 +128,7 @@ obj-$(CONFIG_GPIO_RDA) += gpio-rda.o
obj-$(CONFIG_GPIO_RDC321X)
+=
gpio-rdc321x.o
obj-$(CONFIG_GPIO_RDC321X)
+=
gpio-rdc321x.o
obj-$(CONFIG_GPIO_REALTEK_OTTO)
+=
gpio-realtek-otto.o
obj-$(CONFIG_GPIO_REALTEK_OTTO)
+=
gpio-realtek-otto.o
obj-$(CONFIG_GPIO_REG)
+=
gpio-reg.o
obj-$(CONFIG_GPIO_REG)
+=
gpio-reg.o
obj-$(CONFIG_GPIO_ROCKCHIP)
+=
gpio-rockchip.o
obj-$(CONFIG_ARCH_SA1100)
+=
gpio-sa1100.o
obj-$(CONFIG_ARCH_SA1100)
+=
gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)
+=
gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)
+=
gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SCH311X)
+=
gpio-sch311x.o
obj-$(CONFIG_GPIO_SCH311X)
+=
gpio-sch311x.o
...
...
drivers/gpio/gpio-rockchip.c
0 → 100644
View file @
0dda8b01
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
*/
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include "../pinctrl/core.h"
#include "../pinctrl/pinctrl-rockchip.h"
#define GPIO_TYPE_V1 (0)
/* GPIO Version ID reserved */
#define GPIO_TYPE_V2 (0x01000C2B)
/* GPIO Version ID 0x01000C2B */
static
const
struct
rockchip_gpio_regs
gpio_regs_v1
=
{
.
port_dr
=
0x00
,
.
port_ddr
=
0x04
,
.
int_en
=
0x30
,
.
int_mask
=
0x34
,
.
int_type
=
0x38
,
.
int_polarity
=
0x3c
,
.
int_status
=
0x40
,
.
int_rawstatus
=
0x44
,
.
debounce
=
0x48
,
.
port_eoi
=
0x4c
,
.
ext_port
=
0x50
,
};
static
const
struct
rockchip_gpio_regs
gpio_regs_v2
=
{
.
port_dr
=
0x00
,
.
port_ddr
=
0x08
,
.
int_en
=
0x10
,
.
int_mask
=
0x18
,
.
int_type
=
0x20
,
.
int_polarity
=
0x28
,
.
int_bothedge
=
0x30
,
.
int_status
=
0x50
,
.
int_rawstatus
=
0x58
,
.
debounce
=
0x38
,
.
dbclk_div_en
=
0x40
,
.
dbclk_div_con
=
0x48
,
.
port_eoi
=
0x60
,
.
ext_port
=
0x70
,
.
version_id
=
0x78
,
};
static
inline
void
gpio_writel_v2
(
u32
val
,
void
__iomem
*
reg
)
{
writel
((
val
&
0xffff
)
|
0xffff0000
,
reg
);
writel
((
val
>>
16
)
|
0xffff0000
,
reg
+
0x4
);
}
static
inline
u32
gpio_readl_v2
(
void
__iomem
*
reg
)
{
return
readl
(
reg
+
0x4
)
<<
16
|
readl
(
reg
);
}
static
inline
void
rockchip_gpio_writel
(
struct
rockchip_pin_bank
*
bank
,
u32
value
,
unsigned
int
offset
)
{
void
__iomem
*
reg
=
bank
->
reg_base
+
offset
;
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
gpio_writel_v2
(
value
,
reg
);
else
writel
(
value
,
reg
);
}
static
inline
u32
rockchip_gpio_readl
(
struct
rockchip_pin_bank
*
bank
,
unsigned
int
offset
)
{
void
__iomem
*
reg
=
bank
->
reg_base
+
offset
;
u32
value
;
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
value
=
gpio_readl_v2
(
reg
);
else
value
=
readl
(
reg
);
return
value
;
}
static
inline
void
rockchip_gpio_writel_bit
(
struct
rockchip_pin_bank
*
bank
,
u32
bit
,
u32
value
,
unsigned
int
offset
)
{
void
__iomem
*
reg
=
bank
->
reg_base
+
offset
;
u32
data
;
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
{
if
(
value
)
data
=
BIT
(
bit
%
16
)
|
BIT
(
bit
%
16
+
16
);
else
data
=
BIT
(
bit
%
16
+
16
);
writel
(
data
,
bit
>=
16
?
reg
+
0x4
:
reg
);
}
else
{
data
=
readl
(
reg
);
data
&=
~
BIT
(
bit
);
if
(
value
)
data
|=
BIT
(
bit
);
writel
(
data
,
reg
);
}
}
static
inline
u32
rockchip_gpio_readl_bit
(
struct
rockchip_pin_bank
*
bank
,
u32
bit
,
unsigned
int
offset
)
{
void
__iomem
*
reg
=
bank
->
reg_base
+
offset
;
u32
data
;
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
{
data
=
readl
(
bit
>=
16
?
reg
+
0x4
:
reg
);
data
>>=
bit
%
16
;
}
else
{
data
=
readl
(
reg
);
data
>>=
bit
;
}
return
data
&
(
0x1
);
}
static
int
rockchip_gpio_get_direction
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
chip
);
u32
data
;
data
=
rockchip_gpio_readl_bit
(
bank
,
offset
,
bank
->
gpio_regs
->
port_ddr
);
if
(
data
&
BIT
(
offset
))
return
GPIO_LINE_DIRECTION_OUT
;
return
GPIO_LINE_DIRECTION_IN
;
}
static
int
rockchip_gpio_set_direction
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
bool
input
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
chip
);
unsigned
long
flags
;
u32
data
=
input
?
0
:
1
;
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
rockchip_gpio_writel_bit
(
bank
,
offset
,
data
,
bank
->
gpio_regs
->
port_ddr
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
return
0
;
}
static
void
rockchip_gpio_set
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
unsigned
long
flags
;
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
rockchip_gpio_writel_bit
(
bank
,
offset
,
value
,
bank
->
gpio_regs
->
port_dr
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
}
static
int
rockchip_gpio_get
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
u32
data
;
data
=
readl
(
bank
->
reg_base
+
bank
->
gpio_regs
->
ext_port
);
data
>>=
offset
;
data
&=
1
;
return
data
;
}
static
int
rockchip_gpio_set_debounce
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
unsigned
int
debounce
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
const
struct
rockchip_gpio_regs
*
reg
=
bank
->
gpio_regs
;
unsigned
long
flags
,
div_reg
,
freq
,
max_debounce
;
bool
div_debounce_support
;
unsigned
int
cur_div_reg
;
u64
div
;
if
(
!
IS_ERR
(
bank
->
db_clk
))
{
div_debounce_support
=
true
;
freq
=
clk_get_rate
(
bank
->
db_clk
);
max_debounce
=
(
GENMASK
(
23
,
0
)
+
1
)
*
2
*
1000000
/
freq
;
if
(
debounce
>
max_debounce
)
return
-
EINVAL
;
div
=
debounce
*
freq
;
div_reg
=
DIV_ROUND_CLOSEST_ULL
(
div
,
2
*
USEC_PER_SEC
)
-
1
;
}
else
{
div_debounce_support
=
false
;
}
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
/* Only the v1 needs to configure div_en and div_con for dbclk */
if
(
debounce
)
{
if
(
div_debounce_support
)
{
/* Configure the max debounce from consumers */
cur_div_reg
=
readl
(
bank
->
reg_base
+
reg
->
dbclk_div_con
);
if
(
cur_div_reg
<
div_reg
)
writel
(
div_reg
,
bank
->
reg_base
+
reg
->
dbclk_div_con
);
rockchip_gpio_writel_bit
(
bank
,
offset
,
1
,
reg
->
dbclk_div_en
);
}
rockchip_gpio_writel_bit
(
bank
,
offset
,
1
,
reg
->
debounce
);
}
else
{
if
(
div_debounce_support
)
rockchip_gpio_writel_bit
(
bank
,
offset
,
0
,
reg
->
dbclk_div_en
);
rockchip_gpio_writel_bit
(
bank
,
offset
,
0
,
reg
->
debounce
);
}
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
/* Enable or disable dbclk at last */
if
(
div_debounce_support
)
{
if
(
debounce
)
clk_prepare_enable
(
bank
->
db_clk
);
else
clk_disable_unprepare
(
bank
->
db_clk
);
}
return
0
;
}
static
int
rockchip_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
return
rockchip_gpio_set_direction
(
gc
,
offset
,
true
);
}
static
int
rockchip_gpio_direction_output
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
rockchip_gpio_set
(
gc
,
offset
,
value
);
return
rockchip_gpio_set_direction
(
gc
,
offset
,
false
);
}
/*
* gpiolib set_config callback function. The setting of the pin
* mux function as 'gpio output' will be handled by the pinctrl subsystem
* interface.
*/
static
int
rockchip_gpio_set_config
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
unsigned
long
config
)
{
enum
pin_config_param
param
=
pinconf_to_config_param
(
config
);
switch
(
param
)
{
case
PIN_CONFIG_INPUT_DEBOUNCE
:
rockchip_gpio_set_debounce
(
gc
,
offset
,
true
);
/*
* Rockchip's gpio could only support up to one period
* of the debounce clock(pclk), which is far away from
* satisftying the requirement, as pclk is usually near
* 100MHz shared by all peripherals. So the fact is it
* has crippled debounce capability could only be useful
* to prevent any spurious glitches from waking up the system
* if the gpio is conguired as wakeup interrupt source. Let's
* still return -ENOTSUPP as before, to make sure the caller
* of gpiod_set_debounce won't change its behaviour.
*/
return
-
ENOTSUPP
;
default:
return
-
ENOTSUPP
;
}
}
/*
* gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
* and a virtual IRQ, if not already present.
*/
static
int
rockchip_gpio_to_irq
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
unsigned
int
virq
;
if
(
!
bank
->
domain
)
return
-
ENXIO
;
virq
=
irq_create_mapping
(
bank
->
domain
,
offset
);
return
(
virq
)
?
:
-
ENXIO
;
}
static
const
struct
gpio_chip
rockchip_gpiolib_chip
=
{
.
request
=
gpiochip_generic_request
,
.
free
=
gpiochip_generic_free
,
.
set
=
rockchip_gpio_set
,
.
get
=
rockchip_gpio_get
,
.
get_direction
=
rockchip_gpio_get_direction
,
.
direction_input
=
rockchip_gpio_direction_input
,
.
direction_output
=
rockchip_gpio_direction_output
,
.
set_config
=
rockchip_gpio_set_config
,
.
to_irq
=
rockchip_gpio_to_irq
,
.
owner
=
THIS_MODULE
,
};
static
void
rockchip_irq_demux
(
struct
irq_desc
*
desc
)
{
struct
irq_chip
*
chip
=
irq_desc_get_chip
(
desc
);
struct
rockchip_pin_bank
*
bank
=
irq_desc_get_handler_data
(
desc
);
u32
pend
;
dev_dbg
(
bank
->
dev
,
"got irq for bank %s
\n
"
,
bank
->
name
);
chained_irq_enter
(
chip
,
desc
);
pend
=
readl_relaxed
(
bank
->
reg_base
+
bank
->
gpio_regs
->
int_status
);
while
(
pend
)
{
unsigned
int
irq
,
virq
;
irq
=
__ffs
(
pend
);
pend
&=
~
BIT
(
irq
);
virq
=
irq_find_mapping
(
bank
->
domain
,
irq
);
if
(
!
virq
)
{
dev_err
(
bank
->
dev
,
"unmapped irq %d
\n
"
,
irq
);
continue
;
}
dev_dbg
(
bank
->
dev
,
"handling irq %d
\n
"
,
irq
);
/*
* Triggering IRQ on both rising and falling edge
* needs manual intervention.
*/
if
(
bank
->
toggle_edge_mode
&
BIT
(
irq
))
{
u32
data
,
data_old
,
polarity
;
unsigned
long
flags
;
data
=
readl_relaxed
(
bank
->
reg_base
+
bank
->
gpio_regs
->
ext_port
);
do
{
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
polarity
=
readl_relaxed
(
bank
->
reg_base
+
bank
->
gpio_regs
->
int_polarity
);
if
(
data
&
BIT
(
irq
))
polarity
&=
~
BIT
(
irq
);
else
polarity
|=
BIT
(
irq
);
writel
(
polarity
,
bank
->
reg_base
+
bank
->
gpio_regs
->
int_polarity
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
data_old
=
data
;
data
=
readl_relaxed
(
bank
->
reg_base
+
bank
->
gpio_regs
->
ext_port
);
}
while
((
data
&
BIT
(
irq
))
!=
(
data_old
&
BIT
(
irq
)));
}
generic_handle_irq
(
virq
);
}
chained_irq_exit
(
chip
,
desc
);
}
static
int
rockchip_irq_set_type
(
struct
irq_data
*
d
,
unsigned
int
type
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
u32
mask
=
BIT
(
d
->
hwirq
);
u32
polarity
;
u32
level
;
u32
data
;
unsigned
long
flags
;
int
ret
=
0
;
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
rockchip_gpio_writel_bit
(
bank
,
d
->
hwirq
,
0
,
bank
->
gpio_regs
->
port_ddr
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
if
(
type
&
IRQ_TYPE_EDGE_BOTH
)
irq_set_handler_locked
(
d
,
handle_edge_irq
);
else
irq_set_handler_locked
(
d
,
handle_level_irq
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
level
=
rockchip_gpio_readl
(
bank
,
bank
->
gpio_regs
->
int_type
);
polarity
=
rockchip_gpio_readl
(
bank
,
bank
->
gpio_regs
->
int_polarity
);
switch
(
type
)
{
case
IRQ_TYPE_EDGE_BOTH
:
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
{
bank
->
toggle_edge_mode
&=
~
mask
;
rockchip_gpio_writel_bit
(
bank
,
d
->
hwirq
,
1
,
bank
->
gpio_regs
->
int_bothedge
);
goto
out
;
}
else
{
bank
->
toggle_edge_mode
|=
mask
;
level
|=
mask
;
/*
* Determine gpio state. If 1 next interrupt should be
* falling otherwise rising.
*/
data
=
readl
(
bank
->
reg_base
+
bank
->
gpio_regs
->
ext_port
);
if
(
data
&
mask
)
polarity
&=
~
mask
;
else
polarity
|=
mask
;
}
break
;
case
IRQ_TYPE_EDGE_RISING
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
|=
mask
;
polarity
|=
mask
;
break
;
case
IRQ_TYPE_EDGE_FALLING
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
|=
mask
;
polarity
&=
~
mask
;
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
&=
~
mask
;
polarity
|=
mask
;
break
;
case
IRQ_TYPE_LEVEL_LOW
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
&=
~
mask
;
polarity
&=
~
mask
;
break
;
default:
ret
=
-
EINVAL
;
goto
out
;
}
rockchip_gpio_writel
(
bank
,
level
,
bank
->
gpio_regs
->
int_type
);
rockchip_gpio_writel
(
bank
,
polarity
,
bank
->
gpio_regs
->
int_polarity
);
out:
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
return
ret
;
}
static
void
rockchip_irq_suspend
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
bank
->
saved_masks
=
irq_reg_readl
(
gc
,
bank
->
gpio_regs
->
int_mask
);
irq_reg_writel
(
gc
,
~
gc
->
wake_active
,
bank
->
gpio_regs
->
int_mask
);
}
static
void
rockchip_irq_resume
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
irq_reg_writel
(
gc
,
bank
->
saved_masks
,
bank
->
gpio_regs
->
int_mask
);
}
static
void
rockchip_irq_enable
(
struct
irq_data
*
d
)
{
irq_gc_mask_clr_bit
(
d
);
}
static
void
rockchip_irq_disable
(
struct
irq_data
*
d
)
{
irq_gc_mask_set_bit
(
d
);
}
static
int
rockchip_interrupts_register
(
struct
rockchip_pin_bank
*
bank
)
{
unsigned
int
clr
=
IRQ_NOREQUEST
|
IRQ_NOPROBE
|
IRQ_NOAUTOEN
;
struct
irq_chip_generic
*
gc
;
int
ret
;
bank
->
domain
=
irq_domain_add_linear
(
bank
->
of_node
,
32
,
&
irq_generic_chip_ops
,
NULL
);
if
(
!
bank
->
domain
)
{
dev_warn
(
bank
->
dev
,
"could not init irq domain for bank %s
\n
"
,
bank
->
name
);
return
-
EINVAL
;
}
ret
=
irq_alloc_domain_generic_chips
(
bank
->
domain
,
32
,
1
,
"rockchip_gpio_irq"
,
handle_level_irq
,
clr
,
0
,
0
);
if
(
ret
)
{
dev_err
(
bank
->
dev
,
"could not alloc generic chips for bank %s
\n
"
,
bank
->
name
);
irq_domain_remove
(
bank
->
domain
);
return
-
EINVAL
;
}
gc
=
irq_get_domain_generic_chip
(
bank
->
domain
,
0
);
if
(
bank
->
gpio_type
==
GPIO_TYPE_V2
)
{
gc
->
reg_writel
=
gpio_writel_v2
;
gc
->
reg_readl
=
gpio_readl_v2
;
}
gc
->
reg_base
=
bank
->
reg_base
;
gc
->
private
=
bank
;
gc
->
chip_types
[
0
].
regs
.
mask
=
bank
->
gpio_regs
->
int_mask
;
gc
->
chip_types
[
0
].
regs
.
ack
=
bank
->
gpio_regs
->
port_eoi
;
gc
->
chip_types
[
0
].
chip
.
irq_ack
=
irq_gc_ack_set_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_mask
=
irq_gc_mask_set_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_unmask
=
irq_gc_mask_clr_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_enable
=
rockchip_irq_enable
;
gc
->
chip_types
[
0
].
chip
.
irq_disable
=
rockchip_irq_disable
;
gc
->
chip_types
[
0
].
chip
.
irq_set_wake
=
irq_gc_set_wake
;
gc
->
chip_types
[
0
].
chip
.
irq_suspend
=
rockchip_irq_suspend
;
gc
->
chip_types
[
0
].
chip
.
irq_resume
=
rockchip_irq_resume
;
gc
->
chip_types
[
0
].
chip
.
irq_set_type
=
rockchip_irq_set_type
;
gc
->
wake_enabled
=
IRQ_MSK
(
bank
->
nr_pins
);
/*
* Linux assumes that all interrupts start out disabled/masked.
* Our driver only uses the concept of masked and always keeps
* things enabled, so for us that's all masked and all enabled.
*/
rockchip_gpio_writel
(
bank
,
0xffffffff
,
bank
->
gpio_regs
->
int_mask
);
rockchip_gpio_writel
(
bank
,
0xffffffff
,
bank
->
gpio_regs
->
port_eoi
);
rockchip_gpio_writel
(
bank
,
0xffffffff
,
bank
->
gpio_regs
->
int_en
);
gc
->
mask_cache
=
0xffffffff
;
irq_set_chained_handler_and_data
(
bank
->
irq
,
rockchip_irq_demux
,
bank
);
return
0
;
}
static
int
rockchip_gpiolib_register
(
struct
rockchip_pin_bank
*
bank
)
{
struct
gpio_chip
*
gc
;
int
ret
;
bank
->
gpio_chip
=
rockchip_gpiolib_chip
;
gc
=
&
bank
->
gpio_chip
;
gc
->
base
=
bank
->
pin_base
;
gc
->
ngpio
=
bank
->
nr_pins
;
gc
->
label
=
bank
->
name
;
gc
->
parent
=
bank
->
dev
;
#ifdef CONFIG_OF_GPIO
gc
->
of_node
=
of_node_get
(
bank
->
of_node
);
#endif
ret
=
gpiochip_add_data
(
gc
,
bank
);
if
(
ret
)
{
dev_err
(
bank
->
dev
,
"failed to add gpiochip %s, %d
\n
"
,
gc
->
label
,
ret
);
return
ret
;
}
/*
* For DeviceTree-supported systems, the gpio core checks the
* pinctrl's device node for the "gpio-ranges" property.
* If it is present, it takes care of adding the pin ranges
* for the driver. In this case the driver can skip ahead.
*
* In order to remain compatible with older, existing DeviceTree
* files which don't set the "gpio-ranges" property or systems that
* utilize ACPI the driver has to call gpiochip_add_pin_range().
*/
if
(
!
of_property_read_bool
(
bank
->
of_node
,
"gpio-ranges"
))
{
struct
device_node
*
pctlnp
=
of_get_parent
(
bank
->
of_node
);
struct
pinctrl_dev
*
pctldev
=
NULL
;
if
(
!
pctlnp
)
return
-
ENODATA
;
pctldev
=
of_pinctrl_get
(
pctlnp
);
if
(
!
pctldev
)
return
-
ENODEV
;
ret
=
gpiochip_add_pin_range
(
gc
,
dev_name
(
pctldev
->
dev
),
0
,
gc
->
base
,
gc
->
ngpio
);
if
(
ret
)
{
dev_err
(
bank
->
dev
,
"Failed to add pin range
\n
"
);
goto
fail
;
}
}
ret
=
rockchip_interrupts_register
(
bank
);
if
(
ret
)
{
dev_err
(
bank
->
dev
,
"failed to register interrupt, %d
\n
"
,
ret
);
goto
fail
;
}
return
0
;
fail:
gpiochip_remove
(
&
bank
->
gpio_chip
);
return
ret
;
}
static
int
rockchip_get_bank_data
(
struct
rockchip_pin_bank
*
bank
)
{
struct
resource
res
;
int
id
=
0
;
if
(
of_address_to_resource
(
bank
->
of_node
,
0
,
&
res
))
{
dev_err
(
bank
->
dev
,
"cannot find IO resource for bank
\n
"
);
return
-
ENOENT
;
}
bank
->
reg_base
=
devm_ioremap_resource
(
bank
->
dev
,
&
res
);
if
(
IS_ERR
(
bank
->
reg_base
))
return
PTR_ERR
(
bank
->
reg_base
);
bank
->
irq
=
irq_of_parse_and_map
(
bank
->
of_node
,
0
);
if
(
!
bank
->
irq
)
return
-
EINVAL
;
bank
->
clk
=
of_clk_get
(
bank
->
of_node
,
0
);
if
(
IS_ERR
(
bank
->
clk
))
return
PTR_ERR
(
bank
->
clk
);
clk_prepare_enable
(
bank
->
clk
);
id
=
readl
(
bank
->
reg_base
+
gpio_regs_v2
.
version_id
);
/* If not gpio v2, that is default to v1. */
if
(
id
==
GPIO_TYPE_V2
)
{
bank
->
gpio_regs
=
&
gpio_regs_v2
;
bank
->
gpio_type
=
GPIO_TYPE_V2
;
bank
->
db_clk
=
of_clk_get
(
bank
->
of_node
,
1
);
if
(
IS_ERR
(
bank
->
db_clk
))
{
dev_err
(
bank
->
dev
,
"cannot find debounce clk
\n
"
);
clk_disable_unprepare
(
bank
->
clk
);
return
-
EINVAL
;
}
}
else
{
bank
->
gpio_regs
=
&
gpio_regs_v1
;
bank
->
gpio_type
=
GPIO_TYPE_V1
;
}
return
0
;
}
static
struct
rockchip_pin_bank
*
rockchip_gpio_find_bank
(
struct
pinctrl_dev
*
pctldev
,
int
id
)
{
struct
rockchip_pinctrl
*
info
;
struct
rockchip_pin_bank
*
bank
;
int
i
,
found
=
0
;
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
bank
=
info
->
ctrl
->
pin_banks
;
for
(
i
=
0
;
i
<
info
->
ctrl
->
nr_banks
;
i
++
,
bank
++
)
{
if
(
bank
->
bank_num
==
id
)
{
found
=
1
;
break
;
}
}
return
found
?
bank
:
NULL
;
}
static
int
rockchip_gpio_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
device_node
*
np
=
dev
->
of_node
;
struct
device_node
*
pctlnp
=
of_get_parent
(
np
);
struct
pinctrl_dev
*
pctldev
=
NULL
;
struct
rockchip_pin_bank
*
bank
=
NULL
;
static
int
gpio
;
int
id
,
ret
;
if
(
!
np
||
!
pctlnp
)
return
-
ENODEV
;
pctldev
=
of_pinctrl_get
(
pctlnp
);
if
(
!
pctldev
)
return
-
EPROBE_DEFER
;
id
=
of_alias_get_id
(
np
,
"gpio"
);
if
(
id
<
0
)
id
=
gpio
++
;
bank
=
rockchip_gpio_find_bank
(
pctldev
,
id
);
if
(
!
bank
)
return
-
EINVAL
;
bank
->
dev
=
dev
;
bank
->
of_node
=
np
;
raw_spin_lock_init
(
&
bank
->
slock
);
ret
=
rockchip_get_bank_data
(
bank
);
if
(
ret
)
return
ret
;
ret
=
rockchip_gpiolib_register
(
bank
);
if
(
ret
)
{
clk_disable_unprepare
(
bank
->
clk
);
return
ret
;
}
platform_set_drvdata
(
pdev
,
bank
);
dev_info
(
dev
,
"probed %pOF
\n
"
,
np
);
return
0
;
}
static
int
rockchip_gpio_remove
(
struct
platform_device
*
pdev
)
{
struct
rockchip_pin_bank
*
bank
=
platform_get_drvdata
(
pdev
);
clk_disable_unprepare
(
bank
->
clk
);
gpiochip_remove
(
&
bank
->
gpio_chip
);
return
0
;
}
static
const
struct
of_device_id
rockchip_gpio_match
[]
=
{
{
.
compatible
=
"rockchip,gpio-bank"
,
},
{
.
compatible
=
"rockchip,rk3188-gpio-bank0"
},
{
},
};
static
struct
platform_driver
rockchip_gpio_driver
=
{
.
probe
=
rockchip_gpio_probe
,
.
remove
=
rockchip_gpio_remove
,
.
driver
=
{
.
name
=
"rockchip-gpio"
,
.
of_match_table
=
rockchip_gpio_match
,
},
};
static
int
__init
rockchip_gpio_init
(
void
)
{
return
platform_driver_register
(
&
rockchip_gpio_driver
);
}
postcore_initcall
(
rockchip_gpio_init
);
static
void
__exit
rockchip_gpio_exit
(
void
)
{
platform_driver_unregister
(
&
rockchip_gpio_driver
);
}
module_exit
(
rockchip_gpio_exit
);
MODULE_DESCRIPTION
(
"Rockchip gpio driver"
);
MODULE_ALIAS
(
"platform:rockchip-gpio"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_DEVICE_TABLE
(
of
,
rockchip_gpio_match
);
drivers/pinctrl/pinctrl-rockchip.c
View file @
0dda8b01
...
@@ -21,8 +21,8 @@
...
@@ -21,8 +21,8 @@
#include <linux/io.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/driver.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf.h>
...
@@ -37,35 +37,7 @@
...
@@ -37,35 +37,7 @@
#include "core.h"
#include "core.h"
#include "pinconf.h"
#include "pinconf.h"
#include "pinctrl-rockchip.h"
/* GPIO control registers */
#define GPIO_SWPORT_DR 0x00
#define GPIO_SWPORT_DDR 0x04
#define GPIO_INTEN 0x30
#define GPIO_INTMASK 0x34
#define GPIO_INTTYPE_LEVEL 0x38
#define GPIO_INT_POLARITY 0x3c
#define GPIO_INT_STATUS 0x40
#define GPIO_INT_RAWSTATUS 0x44
#define GPIO_DEBOUNCE 0x48
#define GPIO_PORTS_EOI 0x4c
#define GPIO_EXT_PORT 0x50
#define GPIO_LS_SYNC 0x60
enum
rockchip_pinctrl_type
{
PX30
,
RV1108
,
RK2928
,
RK3066B
,
RK3128
,
RK3188
,
RK3288
,
RK3308
,
RK3368
,
RK3399
,
RK3568
,
};
/**
/**
* Generate a bitmask for setting a value (v) with a write mask bit in hiword
* Generate a bitmask for setting a value (v) with a write mask bit in hiword
...
@@ -84,103 +56,6 @@ enum rockchip_pinctrl_type {
...
@@ -84,103 +56,6 @@ enum rockchip_pinctrl_type {
#define IOMUX_WIDTH_3BIT BIT(4)
#define IOMUX_WIDTH_3BIT BIT(4)
#define IOMUX_WIDTH_2BIT BIT(5)
#define IOMUX_WIDTH_2BIT BIT(5)
/**
* struct rockchip_iomux
* @type: iomux variant using IOMUX_* constants
* @offset: if initialized to -1 it will be autocalculated, by specifying
* an initial offset value the relevant source offset can be reset
* to a new value for autocalculating the following iomux registers.
*/
struct
rockchip_iomux
{
int
type
;
int
offset
;
};
/*
* enum type index corresponding to rockchip_perpin_drv_list arrays index.
*/
enum
rockchip_pin_drv_type
{
DRV_TYPE_IO_DEFAULT
=
0
,
DRV_TYPE_IO_1V8_OR_3V0
,
DRV_TYPE_IO_1V8_ONLY
,
DRV_TYPE_IO_1V8_3V0_AUTO
,
DRV_TYPE_IO_3V3_ONLY
,
DRV_TYPE_MAX
};
/*
* enum type index corresponding to rockchip_pull_list arrays index.
*/
enum
rockchip_pin_pull_type
{
PULL_TYPE_IO_DEFAULT
=
0
,
PULL_TYPE_IO_1V8_ONLY
,
PULL_TYPE_MAX
};
/**
* struct rockchip_drv
* @drv_type: drive strength variant using rockchip_perpin_drv_type
* @offset: if initialized to -1 it will be autocalculated, by specifying
* an initial offset value the relevant source offset can be reset
* to a new value for autocalculating the following drive strength
* registers. if used chips own cal_drv func instead to calculate
* registers offset, the variant could be ignored.
*/
struct
rockchip_drv
{
enum
rockchip_pin_drv_type
drv_type
;
int
offset
;
};
/**
* struct rockchip_pin_bank
* @reg_base: register base of the gpio bank
* @regmap_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
* @irq: interrupt of the gpio bank
* @saved_masks: Saved content of GPIO_INTEN at suspend time.
* @pin_base: first pin number
* @nr_pins: number of pins in this bank
* @name: name of the bank
* @bank_num: number of the bank, to account for holes
* @iomux: array describing the 4 iomux sources of the bank
* @drv: array describing the 4 drive strength sources of the bank
* @pull_type: array describing the 4 pull type sources of the bank
* @valid: is all necessary information present
* @of_node: dt node of this bank
* @drvdata: common pinctrl basedata
* @domain: irqdomain of the gpio bank
* @gpio_chip: gpiolib chip
* @grange: gpio range
* @slock: spinlock for the gpio bank
* @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode
* @recalced_mask: bit mask to indicate a need to recalulate the mask
* @route_mask: bits describing the routing pins of per bank
*/
struct
rockchip_pin_bank
{
void
__iomem
*
reg_base
;
struct
regmap
*
regmap_pull
;
struct
clk
*
clk
;
int
irq
;
u32
saved_masks
;
u32
pin_base
;
u8
nr_pins
;
char
*
name
;
u8
bank_num
;
struct
rockchip_iomux
iomux
[
4
];
struct
rockchip_drv
drv
[
4
];
enum
rockchip_pin_pull_type
pull_type
[
4
];
bool
valid
;
struct
device_node
*
of_node
;
struct
rockchip_pinctrl
*
drvdata
;
struct
irq_domain
*
domain
;
struct
gpio_chip
gpio_chip
;
struct
pinctrl_gpio_range
grange
;
raw_spinlock_t
slock
;
u32
toggle_edge_mode
;
u32
recalced_mask
;
u32
route_mask
;
};
#define PIN_BANK(id, pins, label) \
#define PIN_BANK(id, pins, label) \
{ \
{ \
.bank_num = id, \
.bank_num = id, \
...
@@ -320,119 +195,6 @@ struct rockchip_pin_bank {
...
@@ -320,119 +195,6 @@ struct rockchip_pin_bank {
#define RK_MUXROUTE_PMU(ID, PIN, FUNC, REG, VAL) \
#define RK_MUXROUTE_PMU(ID, PIN, FUNC, REG, VAL) \
PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_PMU)
PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_PMU)
/**
* struct rockchip_mux_recalced_data: represent a pin iomux data.
* @num: bank number.
* @pin: pin number.
* @bit: index at register.
* @reg: register offset.
* @mask: mask bit
*/
struct
rockchip_mux_recalced_data
{
u8
num
;
u8
pin
;
u32
reg
;
u8
bit
;
u8
mask
;
};
enum
rockchip_mux_route_location
{
ROCKCHIP_ROUTE_SAME
=
0
,
ROCKCHIP_ROUTE_PMU
,
ROCKCHIP_ROUTE_GRF
,
};
/**
* struct rockchip_mux_recalced_data: represent a pin iomux data.
* @bank_num: bank number.
* @pin: index at register or used to calc index.
* @func: the min pin.
* @route_location: the mux route location (same, pmu, grf).
* @route_offset: the max pin.
* @route_val: the register offset.
*/
struct
rockchip_mux_route_data
{
u8
bank_num
;
u8
pin
;
u8
func
;
enum
rockchip_mux_route_location
route_location
;
u32
route_offset
;
u32
route_val
;
};
struct
rockchip_pin_ctrl
{
struct
rockchip_pin_bank
*
pin_banks
;
u32
nr_banks
;
u32
nr_pins
;
char
*
label
;
enum
rockchip_pinctrl_type
type
;
int
grf_mux_offset
;
int
pmu_mux_offset
;
int
grf_drv_offset
;
int
pmu_drv_offset
;
struct
rockchip_mux_recalced_data
*
iomux_recalced
;
u32
niomux_recalced
;
struct
rockchip_mux_route_data
*
iomux_routes
;
u32
niomux_routes
;
void
(
*
pull_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
void
(
*
drv_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
int
(
*
schmitt_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
};
struct
rockchip_pin_config
{
unsigned
int
func
;
unsigned
long
*
configs
;
unsigned
int
nconfigs
;
};
/**
* struct rockchip_pin_group: represent group of pins of a pinmux function.
* @name: name of the pin group, used to lookup the group.
* @pins: the pins included in this group.
* @npins: number of pins included in this group.
* @data: local pin configuration
*/
struct
rockchip_pin_group
{
const
char
*
name
;
unsigned
int
npins
;
unsigned
int
*
pins
;
struct
rockchip_pin_config
*
data
;
};
/**
* struct rockchip_pmx_func: represent a pin function.
* @name: name of the pin function, used to lookup the function.
* @groups: one or more names of pin groups that provide this function.
* @ngroups: number of groups included in @groups.
*/
struct
rockchip_pmx_func
{
const
char
*
name
;
const
char
**
groups
;
u8
ngroups
;
};
struct
rockchip_pinctrl
{
struct
regmap
*
regmap_base
;
int
reg_size
;
struct
regmap
*
regmap_pull
;
struct
regmap
*
regmap_pmu
;
struct
device
*
dev
;
struct
rockchip_pin_ctrl
*
ctrl
;
struct
pinctrl_desc
pctl
;
struct
pinctrl_dev
*
pctl_dev
;
struct
rockchip_pin_group
*
groups
;
unsigned
int
ngroups
;
struct
rockchip_pmx_func
*
functions
;
unsigned
int
nfunctions
;
};
static
struct
regmap_config
rockchip_regmap_config
=
{
static
struct
regmap_config
rockchip_regmap_config
=
{
.
reg_bits
=
32
,
.
reg_bits
=
32
,
.
val_bits
=
32
,
.
val_bits
=
32
,
...
@@ -2295,86 +2057,11 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
...
@@ -2295,86 +2057,11 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
return
0
;
return
0
;
}
}
static
int
rockchip_gpio_get_direction
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
chip
);
u32
data
;
int
ret
;
ret
=
clk_enable
(
bank
->
clk
);
if
(
ret
<
0
)
{
dev_err
(
bank
->
drvdata
->
dev
,
"failed to enable clock for bank %s
\n
"
,
bank
->
name
);
return
ret
;
}
data
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_SWPORT_DDR
);
clk_disable
(
bank
->
clk
);
if
(
data
&
BIT
(
offset
))
return
GPIO_LINE_DIRECTION_OUT
;
return
GPIO_LINE_DIRECTION_IN
;
}
/*
* The calls to gpio_direction_output() and gpio_direction_input()
* leads to this function call (via the pinctrl_gpio_direction_{input|output}()
* function called from the gpiolib interface).
*/
static
int
_rockchip_pmx_gpio_set_direction
(
struct
gpio_chip
*
chip
,
int
pin
,
bool
input
)
{
struct
rockchip_pin_bank
*
bank
;
int
ret
;
unsigned
long
flags
;
u32
data
;
bank
=
gpiochip_get_data
(
chip
);
ret
=
rockchip_set_mux
(
bank
,
pin
,
RK_FUNC_GPIO
);
if
(
ret
<
0
)
return
ret
;
clk_enable
(
bank
->
clk
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
data
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_SWPORT_DDR
);
/* set bit to 1 for output, 0 for input */
if
(
!
input
)
data
|=
BIT
(
pin
);
else
data
&=
~
BIT
(
pin
);
writel_relaxed
(
data
,
bank
->
reg_base
+
GPIO_SWPORT_DDR
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
clk_disable
(
bank
->
clk
);
return
0
;
}
static
int
rockchip_pmx_gpio_set_direction
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_gpio_range
*
range
,
unsigned
offset
,
bool
input
)
{
struct
rockchip_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
gpio_chip
*
chip
;
int
pin
;
chip
=
range
->
gc
;
pin
=
offset
-
chip
->
base
;
dev_dbg
(
info
->
dev
,
"gpio_direction for pin %u as %s-%d to %s
\n
"
,
offset
,
range
->
name
,
pin
,
input
?
"input"
:
"output"
);
return
_rockchip_pmx_gpio_set_direction
(
chip
,
offset
-
chip
->
base
,
input
);
}
static
const
struct
pinmux_ops
rockchip_pmx_ops
=
{
static
const
struct
pinmux_ops
rockchip_pmx_ops
=
{
.
get_functions_count
=
rockchip_pmx_get_funcs_count
,
.
get_functions_count
=
rockchip_pmx_get_funcs_count
,
.
get_function_name
=
rockchip_pmx_get_func_name
,
.
get_function_name
=
rockchip_pmx_get_func_name
,
.
get_function_groups
=
rockchip_pmx_get_groups
,
.
get_function_groups
=
rockchip_pmx_get_groups
,
.
set_mux
=
rockchip_pmx_set
,
.
set_mux
=
rockchip_pmx_set
,
.
gpio_set_direction
=
rockchip_pmx_gpio_set_direction
,
};
};
/*
/*
...
@@ -2405,15 +2092,13 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
...
@@ -2405,15 +2092,13 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
return
false
;
return
false
;
}
}
static
void
rockchip_gpio_set
(
struct
gpio_chip
*
gc
,
unsigned
offset
,
int
value
);
static
int
rockchip_gpio_get
(
struct
gpio_chip
*
gc
,
unsigned
offset
);
/* set the pin config settings for a specified pin */
/* set the pin config settings for a specified pin */
static
int
rockchip_pinconf_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
pin
,
static
int
rockchip_pinconf_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
pin
,
unsigned
long
*
configs
,
unsigned
num_configs
)
unsigned
long
*
configs
,
unsigned
num_configs
)
{
{
struct
rockchip_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
rockchip_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
rockchip_pin_bank
*
bank
=
pin_to_bank
(
info
,
pin
);
struct
rockchip_pin_bank
*
bank
=
pin_to_bank
(
info
,
pin
);
struct
gpio_chip
*
gpio
=
&
bank
->
gpio_chip
;
enum
pin_config_param
param
;
enum
pin_config_param
param
;
u32
arg
;
u32
arg
;
int
i
;
int
i
;
...
@@ -2446,10 +2131,13 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
...
@@ -2446,10 +2131,13 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
return
rc
;
return
rc
;
break
;
break
;
case
PIN_CONFIG_OUTPUT
:
case
PIN_CONFIG_OUTPUT
:
rockchip_gpio_set
(
&
bank
->
gpio_chip
,
rc
=
rockchip_set_mux
(
bank
,
pin
-
bank
->
pin_base
,
pin
-
bank
->
pin_base
,
arg
);
RK_FUNC_GPIO
);
rc
=
_rockchip_pmx_gpio_set_direction
(
&
bank
->
gpio_chip
,
if
(
rc
!=
RK_FUNC_GPIO
)
pin
-
bank
->
pin_base
,
false
);
return
-
EINVAL
;
rc
=
gpio
->
direction_output
(
gpio
,
pin
-
bank
->
pin_base
,
arg
);
if
(
rc
)
if
(
rc
)
return
rc
;
return
rc
;
break
;
break
;
...
@@ -2487,6 +2175,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
...
@@ -2487,6 +2175,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
{
{
struct
rockchip_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
rockchip_pinctrl
*
info
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
rockchip_pin_bank
*
bank
=
pin_to_bank
(
info
,
pin
);
struct
rockchip_pin_bank
*
bank
=
pin_to_bank
(
info
,
pin
);
struct
gpio_chip
*
gpio
=
&
bank
->
gpio_chip
;
enum
pin_config_param
param
=
pinconf_to_config_param
(
*
config
);
enum
pin_config_param
param
=
pinconf_to_config_param
(
*
config
);
u16
arg
;
u16
arg
;
int
rc
;
int
rc
;
...
@@ -2515,7 +2204,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
...
@@ -2515,7 +2204,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
if
(
rc
!=
RK_FUNC_GPIO
)
if
(
rc
!=
RK_FUNC_GPIO
)
return
-
EINVAL
;
return
-
EINVAL
;
rc
=
rockchip_gpio_get
(
&
bank
->
gpio_chip
,
pin
-
bank
->
pin_base
);
rc
=
gpio
->
get
(
gpio
,
pin
-
bank
->
pin_base
);
if
(
rc
<
0
)
if
(
rc
<
0
)
return
rc
;
return
rc
;
...
@@ -2753,7 +2442,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
...
@@ -2753,7 +2442,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
ctrldesc
->
npins
=
info
->
ctrl
->
nr_pins
;
ctrldesc
->
npins
=
info
->
ctrl
->
nr_pins
;
pdesc
=
pindesc
;
pdesc
=
pindesc
;
for
(
bank
=
0
,
k
=
0
;
bank
<
info
->
ctrl
->
nr_banks
;
bank
++
)
{
for
(
bank
=
0
,
k
=
0
;
bank
<
info
->
ctrl
->
nr_banks
;
bank
++
)
{
pin_bank
=
&
info
->
ctrl
->
pin_banks
[
bank
];
pin_bank
=
&
info
->
ctrl
->
pin_banks
[
bank
];
for
(
pin
=
0
;
pin
<
pin_bank
->
nr_pins
;
pin
++
,
k
++
)
{
for
(
pin
=
0
;
pin
<
pin_bank
->
nr_pins
;
pin
++
,
k
++
)
{
pdesc
->
number
=
k
;
pdesc
->
number
=
k
;
...
@@ -2773,553 +2462,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
...
@@ -2773,553 +2462,9 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
return
PTR_ERR
(
info
->
pctl_dev
);
return
PTR_ERR
(
info
->
pctl_dev
);
}
}
for
(
bank
=
0
;
bank
<
info
->
ctrl
->
nr_banks
;
++
bank
)
{
pin_bank
=
&
info
->
ctrl
->
pin_banks
[
bank
];
pin_bank
->
grange
.
name
=
pin_bank
->
name
;
pin_bank
->
grange
.
id
=
bank
;
pin_bank
->
grange
.
pin_base
=
pin_bank
->
pin_base
;
pin_bank
->
grange
.
base
=
pin_bank
->
gpio_chip
.
base
;
pin_bank
->
grange
.
npins
=
pin_bank
->
gpio_chip
.
ngpio
;
pin_bank
->
grange
.
gc
=
&
pin_bank
->
gpio_chip
;
pinctrl_add_gpio_range
(
info
->
pctl_dev
,
&
pin_bank
->
grange
);
}
return
0
;
}
/*
* GPIO handling
*/
static
void
rockchip_gpio_set
(
struct
gpio_chip
*
gc
,
unsigned
offset
,
int
value
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
void
__iomem
*
reg
=
bank
->
reg_base
+
GPIO_SWPORT_DR
;
unsigned
long
flags
;
u32
data
;
clk_enable
(
bank
->
clk
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
data
=
readl
(
reg
);
data
&=
~
BIT
(
offset
);
if
(
value
)
data
|=
BIT
(
offset
);
writel
(
data
,
reg
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
clk_disable
(
bank
->
clk
);
}
/*
* Returns the level of the pin for input direction and setting of the DR
* register for output gpios.
*/
static
int
rockchip_gpio_get
(
struct
gpio_chip
*
gc
,
unsigned
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
u32
data
;
clk_enable
(
bank
->
clk
);
data
=
readl
(
bank
->
reg_base
+
GPIO_EXT_PORT
);
clk_disable
(
bank
->
clk
);
data
>>=
offset
;
data
&=
1
;
return
data
;
}
/*
* gpiolib gpio_direction_input callback function. The setting of the pin
* mux function as 'gpio input' will be handled by the pinctrl subsystem
* interface.
*/
static
int
rockchip_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
offset
)
{
return
pinctrl_gpio_direction_input
(
gc
->
base
+
offset
);
}
/*
* gpiolib gpio_direction_output callback function. The setting of the pin
* mux function as 'gpio output' will be handled by the pinctrl subsystem
* interface.
*/
static
int
rockchip_gpio_direction_output
(
struct
gpio_chip
*
gc
,
unsigned
offset
,
int
value
)
{
rockchip_gpio_set
(
gc
,
offset
,
value
);
return
pinctrl_gpio_direction_output
(
gc
->
base
+
offset
);
}
static
void
rockchip_gpio_set_debounce
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
bool
enable
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
void
__iomem
*
reg
=
bank
->
reg_base
+
GPIO_DEBOUNCE
;
unsigned
long
flags
;
u32
data
;
clk_enable
(
bank
->
clk
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
data
=
readl
(
reg
);
if
(
enable
)
data
|=
BIT
(
offset
);
else
data
&=
~
BIT
(
offset
);
writel
(
data
,
reg
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
clk_disable
(
bank
->
clk
);
}
/*
* gpiolib set_config callback function. The setting of the pin
* mux function as 'gpio output' will be handled by the pinctrl subsystem
* interface.
*/
static
int
rockchip_gpio_set_config
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
unsigned
long
config
)
{
enum
pin_config_param
param
=
pinconf_to_config_param
(
config
);
switch
(
param
)
{
case
PIN_CONFIG_INPUT_DEBOUNCE
:
rockchip_gpio_set_debounce
(
gc
,
offset
,
true
);
/*
* Rockchip's gpio could only support up to one period
* of the debounce clock(pclk), which is far away from
* satisftying the requirement, as pclk is usually near
* 100MHz shared by all peripherals. So the fact is it
* has crippled debounce capability could only be useful
* to prevent any spurious glitches from waking up the system
* if the gpio is conguired as wakeup interrupt source. Let's
* still return -ENOTSUPP as before, to make sure the caller
* of gpiod_set_debounce won't change its behaviour.
*/
return
-
ENOTSUPP
;
default:
return
-
ENOTSUPP
;
}
}
/*
* gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
* and a virtual IRQ, if not already present.
*/
static
int
rockchip_gpio_to_irq
(
struct
gpio_chip
*
gc
,
unsigned
offset
)
{
struct
rockchip_pin_bank
*
bank
=
gpiochip_get_data
(
gc
);
unsigned
int
virq
;
if
(
!
bank
->
domain
)
return
-
ENXIO
;
clk_enable
(
bank
->
clk
);
virq
=
irq_create_mapping
(
bank
->
domain
,
offset
);
clk_disable
(
bank
->
clk
);
return
(
virq
)
?
:
-
ENXIO
;
}
static
const
struct
gpio_chip
rockchip_gpiolib_chip
=
{
.
request
=
gpiochip_generic_request
,
.
free
=
gpiochip_generic_free
,
.
set
=
rockchip_gpio_set
,
.
get
=
rockchip_gpio_get
,
.
get_direction
=
rockchip_gpio_get_direction
,
.
direction_input
=
rockchip_gpio_direction_input
,
.
direction_output
=
rockchip_gpio_direction_output
,
.
set_config
=
rockchip_gpio_set_config
,
.
to_irq
=
rockchip_gpio_to_irq
,
.
owner
=
THIS_MODULE
,
};
/*
* Interrupt handling
*/
static
void
rockchip_irq_demux
(
struct
irq_desc
*
desc
)
{
struct
irq_chip
*
chip
=
irq_desc_get_chip
(
desc
);
struct
rockchip_pin_bank
*
bank
=
irq_desc_get_handler_data
(
desc
);
u32
pend
;
dev_dbg
(
bank
->
drvdata
->
dev
,
"got irq for bank %s
\n
"
,
bank
->
name
);
chained_irq_enter
(
chip
,
desc
);
pend
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_INT_STATUS
);
while
(
pend
)
{
unsigned
int
irq
,
virq
;
irq
=
__ffs
(
pend
);
pend
&=
~
BIT
(
irq
);
virq
=
irq_find_mapping
(
bank
->
domain
,
irq
);
if
(
!
virq
)
{
dev_err
(
bank
->
drvdata
->
dev
,
"unmapped irq %d
\n
"
,
irq
);
continue
;
}
dev_dbg
(
bank
->
drvdata
->
dev
,
"handling irq %d
\n
"
,
irq
);
/*
* Triggering IRQ on both rising and falling edge
* needs manual intervention.
*/
if
(
bank
->
toggle_edge_mode
&
BIT
(
irq
))
{
u32
data
,
data_old
,
polarity
;
unsigned
long
flags
;
data
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_EXT_PORT
);
do
{
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
polarity
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_INT_POLARITY
);
if
(
data
&
BIT
(
irq
))
polarity
&=
~
BIT
(
irq
);
else
polarity
|=
BIT
(
irq
);
writel
(
polarity
,
bank
->
reg_base
+
GPIO_INT_POLARITY
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
data_old
=
data
;
data
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_EXT_PORT
);
}
while
((
data
&
BIT
(
irq
))
!=
(
data_old
&
BIT
(
irq
)));
}
generic_handle_irq
(
virq
);
}
chained_irq_exit
(
chip
,
desc
);
}
static
int
rockchip_irq_set_type
(
struct
irq_data
*
d
,
unsigned
int
type
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
u32
mask
=
BIT
(
d
->
hwirq
);
u32
polarity
;
u32
level
;
u32
data
;
unsigned
long
flags
;
int
ret
;
/* make sure the pin is configured as gpio input */
ret
=
rockchip_set_mux
(
bank
,
d
->
hwirq
,
RK_FUNC_GPIO
);
if
(
ret
<
0
)
return
ret
;
clk_enable
(
bank
->
clk
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
data
=
readl_relaxed
(
bank
->
reg_base
+
GPIO_SWPORT_DDR
);
data
&=
~
mask
;
writel_relaxed
(
data
,
bank
->
reg_base
+
GPIO_SWPORT_DDR
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
if
(
type
&
IRQ_TYPE_EDGE_BOTH
)
irq_set_handler_locked
(
d
,
handle_edge_irq
);
else
irq_set_handler_locked
(
d
,
handle_level_irq
);
raw_spin_lock_irqsave
(
&
bank
->
slock
,
flags
);
irq_gc_lock
(
gc
);
level
=
readl_relaxed
(
gc
->
reg_base
+
GPIO_INTTYPE_LEVEL
);
polarity
=
readl_relaxed
(
gc
->
reg_base
+
GPIO_INT_POLARITY
);
switch
(
type
)
{
case
IRQ_TYPE_EDGE_BOTH
:
bank
->
toggle_edge_mode
|=
mask
;
level
|=
mask
;
/*
* Determine gpio state. If 1 next interrupt should be falling
* otherwise rising.
*/
data
=
readl
(
bank
->
reg_base
+
GPIO_EXT_PORT
);
if
(
data
&
mask
)
polarity
&=
~
mask
;
else
polarity
|=
mask
;
break
;
case
IRQ_TYPE_EDGE_RISING
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
|=
mask
;
polarity
|=
mask
;
break
;
case
IRQ_TYPE_EDGE_FALLING
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
|=
mask
;
polarity
&=
~
mask
;
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
&=
~
mask
;
polarity
|=
mask
;
break
;
case
IRQ_TYPE_LEVEL_LOW
:
bank
->
toggle_edge_mode
&=
~
mask
;
level
&=
~
mask
;
polarity
&=
~
mask
;
break
;
default:
irq_gc_unlock
(
gc
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
clk_disable
(
bank
->
clk
);
return
-
EINVAL
;
}
writel_relaxed
(
level
,
gc
->
reg_base
+
GPIO_INTTYPE_LEVEL
);
writel_relaxed
(
polarity
,
gc
->
reg_base
+
GPIO_INT_POLARITY
);
irq_gc_unlock
(
gc
);
raw_spin_unlock_irqrestore
(
&
bank
->
slock
,
flags
);
clk_disable
(
bank
->
clk
);
return
0
;
}
static
void
rockchip_irq_suspend
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
clk_enable
(
bank
->
clk
);
bank
->
saved_masks
=
irq_reg_readl
(
gc
,
GPIO_INTMASK
);
irq_reg_writel
(
gc
,
~
gc
->
wake_active
,
GPIO_INTMASK
);
clk_disable
(
bank
->
clk
);
}
static
void
rockchip_irq_resume
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
clk_enable
(
bank
->
clk
);
irq_reg_writel
(
gc
,
bank
->
saved_masks
,
GPIO_INTMASK
);
clk_disable
(
bank
->
clk
);
}
static
void
rockchip_irq_enable
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
clk_enable
(
bank
->
clk
);
irq_gc_mask_clr_bit
(
d
);
}
static
void
rockchip_irq_disable
(
struct
irq_data
*
d
)
{
struct
irq_chip_generic
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
rockchip_pin_bank
*
bank
=
gc
->
private
;
irq_gc_mask_set_bit
(
d
);
clk_disable
(
bank
->
clk
);
}
static
int
rockchip_interrupts_register
(
struct
platform_device
*
pdev
,
struct
rockchip_pinctrl
*
info
)
{
struct
rockchip_pin_ctrl
*
ctrl
=
info
->
ctrl
;
struct
rockchip_pin_bank
*
bank
=
ctrl
->
pin_banks
;
unsigned
int
clr
=
IRQ_NOREQUEST
|
IRQ_NOPROBE
|
IRQ_NOAUTOEN
;
struct
irq_chip_generic
*
gc
;
int
ret
;
int
i
;
for
(
i
=
0
;
i
<
ctrl
->
nr_banks
;
++
i
,
++
bank
)
{
if
(
!
bank
->
valid
)
{
dev_warn
(
&
pdev
->
dev
,
"bank %s is not valid
\n
"
,
bank
->
name
);
continue
;
}
ret
=
clk_enable
(
bank
->
clk
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to enable clock for bank %s
\n
"
,
bank
->
name
);
continue
;
}
bank
->
domain
=
irq_domain_add_linear
(
bank
->
of_node
,
32
,
&
irq_generic_chip_ops
,
NULL
);
if
(
!
bank
->
domain
)
{
dev_warn
(
&
pdev
->
dev
,
"could not initialize irq domain for bank %s
\n
"
,
bank
->
name
);
clk_disable
(
bank
->
clk
);
continue
;
}
ret
=
irq_alloc_domain_generic_chips
(
bank
->
domain
,
32
,
1
,
"rockchip_gpio_irq"
,
handle_level_irq
,
clr
,
0
,
0
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"could not alloc generic chips for bank %s
\n
"
,
bank
->
name
);
irq_domain_remove
(
bank
->
domain
);
clk_disable
(
bank
->
clk
);
continue
;
}
gc
=
irq_get_domain_generic_chip
(
bank
->
domain
,
0
);
gc
->
reg_base
=
bank
->
reg_base
;
gc
->
private
=
bank
;
gc
->
chip_types
[
0
].
regs
.
mask
=
GPIO_INTMASK
;
gc
->
chip_types
[
0
].
regs
.
ack
=
GPIO_PORTS_EOI
;
gc
->
chip_types
[
0
].
chip
.
irq_ack
=
irq_gc_ack_set_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_mask
=
irq_gc_mask_set_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_unmask
=
irq_gc_mask_clr_bit
;
gc
->
chip_types
[
0
].
chip
.
irq_enable
=
rockchip_irq_enable
;
gc
->
chip_types
[
0
].
chip
.
irq_disable
=
rockchip_irq_disable
;
gc
->
chip_types
[
0
].
chip
.
irq_set_wake
=
irq_gc_set_wake
;
gc
->
chip_types
[
0
].
chip
.
irq_suspend
=
rockchip_irq_suspend
;
gc
->
chip_types
[
0
].
chip
.
irq_resume
=
rockchip_irq_resume
;
gc
->
chip_types
[
0
].
chip
.
irq_set_type
=
rockchip_irq_set_type
;
gc
->
wake_enabled
=
IRQ_MSK
(
bank
->
nr_pins
);
/*
* Linux assumes that all interrupts start out disabled/masked.
* Our driver only uses the concept of masked and always keeps
* things enabled, so for us that's all masked and all enabled.
*/
writel_relaxed
(
0xffffffff
,
bank
->
reg_base
+
GPIO_INTMASK
);
writel_relaxed
(
0xffffffff
,
bank
->
reg_base
+
GPIO_PORTS_EOI
);
writel_relaxed
(
0xffffffff
,
bank
->
reg_base
+
GPIO_INTEN
);
gc
->
mask_cache
=
0xffffffff
;
irq_set_chained_handler_and_data
(
bank
->
irq
,
rockchip_irq_demux
,
bank
);
clk_disable
(
bank
->
clk
);
}
return
0
;
return
0
;
}
}
static
int
rockchip_gpiolib_register
(
struct
platform_device
*
pdev
,
struct
rockchip_pinctrl
*
info
)
{
struct
rockchip_pin_ctrl
*
ctrl
=
info
->
ctrl
;
struct
rockchip_pin_bank
*
bank
=
ctrl
->
pin_banks
;
struct
gpio_chip
*
gc
;
int
ret
;
int
i
;
for
(
i
=
0
;
i
<
ctrl
->
nr_banks
;
++
i
,
++
bank
)
{
if
(
!
bank
->
valid
)
{
dev_warn
(
&
pdev
->
dev
,
"bank %s is not valid
\n
"
,
bank
->
name
);
continue
;
}
bank
->
gpio_chip
=
rockchip_gpiolib_chip
;
gc
=
&
bank
->
gpio_chip
;
gc
->
base
=
bank
->
pin_base
;
gc
->
ngpio
=
bank
->
nr_pins
;
gc
->
parent
=
&
pdev
->
dev
;
gc
->
of_node
=
bank
->
of_node
;
gc
->
label
=
bank
->
name
;
ret
=
gpiochip_add_data
(
gc
,
bank
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register gpio_chip %s, error code: %d
\n
"
,
gc
->
label
,
ret
);
goto
fail
;
}
}
rockchip_interrupts_register
(
pdev
,
info
);
return
0
;
fail:
for
(
--
i
,
--
bank
;
i
>=
0
;
--
i
,
--
bank
)
{
if
(
!
bank
->
valid
)
continue
;
gpiochip_remove
(
&
bank
->
gpio_chip
);
}
return
ret
;
}
static
int
rockchip_gpiolib_unregister
(
struct
platform_device
*
pdev
,
struct
rockchip_pinctrl
*
info
)
{
struct
rockchip_pin_ctrl
*
ctrl
=
info
->
ctrl
;
struct
rockchip_pin_bank
*
bank
=
ctrl
->
pin_banks
;
int
i
;
for
(
i
=
0
;
i
<
ctrl
->
nr_banks
;
++
i
,
++
bank
)
{
if
(
!
bank
->
valid
)
continue
;
gpiochip_remove
(
&
bank
->
gpio_chip
);
}
return
0
;
}
static
int
rockchip_get_bank_data
(
struct
rockchip_pin_bank
*
bank
,
struct
rockchip_pinctrl
*
info
)
{
struct
resource
res
;
void
__iomem
*
base
;
if
(
of_address_to_resource
(
bank
->
of_node
,
0
,
&
res
))
{
dev_err
(
info
->
dev
,
"cannot find IO resource for bank
\n
"
);
return
-
ENOENT
;
}
bank
->
reg_base
=
devm_ioremap_resource
(
info
->
dev
,
&
res
);
if
(
IS_ERR
(
bank
->
reg_base
))
return
PTR_ERR
(
bank
->
reg_base
);
/*
* special case, where parts of the pull setting-registers are
* part of the PMU register space
*/
if
(
of_device_is_compatible
(
bank
->
of_node
,
"rockchip,rk3188-gpio-bank0"
))
{
struct
device_node
*
node
;
node
=
of_parse_phandle
(
bank
->
of_node
->
parent
,
"rockchip,pmu"
,
0
);
if
(
!
node
)
{
if
(
of_address_to_resource
(
bank
->
of_node
,
1
,
&
res
))
{
dev_err
(
info
->
dev
,
"cannot find IO resource for bank
\n
"
);
return
-
ENOENT
;
}
base
=
devm_ioremap_resource
(
info
->
dev
,
&
res
);
if
(
IS_ERR
(
base
))
return
PTR_ERR
(
base
);
rockchip_regmap_config
.
max_register
=
resource_size
(
&
res
)
-
4
;
rockchip_regmap_config
.
name
=
"rockchip,rk3188-gpio-bank0-pull"
;
bank
->
regmap_pull
=
devm_regmap_init_mmio
(
info
->
dev
,
base
,
&
rockchip_regmap_config
);
}
of_node_put
(
node
);
}
bank
->
irq
=
irq_of_parse_and_map
(
bank
->
of_node
,
0
);
bank
->
clk
=
of_clk_get
(
bank
->
of_node
,
0
);
if
(
IS_ERR
(
bank
->
clk
))
return
PTR_ERR
(
bank
->
clk
);
return
clk_prepare
(
bank
->
clk
);
}
static
const
struct
of_device_id
rockchip_pinctrl_dt_match
[];
static
const
struct
of_device_id
rockchip_pinctrl_dt_match
[];
/* retrieve the soc specific data */
/* retrieve the soc specific data */
...
@@ -3329,7 +2474,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
...
@@ -3329,7 +2474,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
{
{
const
struct
of_device_id
*
match
;
const
struct
of_device_id
*
match
;
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
struct
device_node
*
np
;
struct
rockchip_pin_ctrl
*
ctrl
;
struct
rockchip_pin_ctrl
*
ctrl
;
struct
rockchip_pin_bank
*
bank
;
struct
rockchip_pin_bank
*
bank
;
int
grf_offs
,
pmu_offs
,
drv_grf_offs
,
drv_pmu_offs
,
i
,
j
;
int
grf_offs
,
pmu_offs
,
drv_grf_offs
,
drv_pmu_offs
,
i
,
j
;
...
@@ -3337,23 +2481,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
...
@@ -3337,23 +2481,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
match
=
of_match_node
(
rockchip_pinctrl_dt_match
,
node
);
match
=
of_match_node
(
rockchip_pinctrl_dt_match
,
node
);
ctrl
=
(
struct
rockchip_pin_ctrl
*
)
match
->
data
;
ctrl
=
(
struct
rockchip_pin_ctrl
*
)
match
->
data
;
for_each_child_of_node
(
node
,
np
)
{
if
(
!
of_find_property
(
np
,
"gpio-controller"
,
NULL
))
continue
;
bank
=
ctrl
->
pin_banks
;
for
(
i
=
0
;
i
<
ctrl
->
nr_banks
;
++
i
,
++
bank
)
{
if
(
!
strcmp
(
bank
->
name
,
np
->
name
))
{
bank
->
of_node
=
np
;
if
(
!
rockchip_get_bank_data
(
bank
,
d
))
bank
->
valid
=
true
;
break
;
}
}
}
grf_offs
=
ctrl
->
grf_mux_offset
;
grf_offs
=
ctrl
->
grf_mux_offset
;
pmu_offs
=
ctrl
->
pmu_mux_offset
;
pmu_offs
=
ctrl
->
pmu_mux_offset
;
drv_pmu_offs
=
ctrl
->
pmu_drv_offset
;
drv_pmu_offs
=
ctrl
->
pmu_drv_offset
;
...
@@ -3574,18 +2701,18 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
...
@@ -3574,18 +2701,18 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
return
PTR_ERR
(
info
->
regmap_pmu
);
return
PTR_ERR
(
info
->
regmap_pmu
);
}
}
ret
=
rockchip_
gpiolib
_register
(
pdev
,
info
);
ret
=
rockchip_
pinctrl
_register
(
pdev
,
info
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
ret
=
rockchip_pinctrl_register
(
pdev
,
info
);
platform_set_drvdata
(
pdev
,
info
);
ret
=
of_platform_populate
(
np
,
rockchip_bank_match
,
NULL
,
NULL
);
if
(
ret
)
{
if
(
ret
)
{
rockchip_gpiolib_unregister
(
pdev
,
info
);
dev_err
(
&
pdev
->
dev
,
"failed to register gpio device
\n
"
);
return
ret
;
return
ret
;
}
}
platform_set_drvdata
(
pdev
,
info
);
return
0
;
return
0
;
}
}
...
...
drivers/pinctrl/pinctrl-rockchip.h
0 → 100644
View file @
0dda8b01
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020-2021 Rockchip Electronics Co. Ltd.
*
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* With some ideas taken from pinctrl-samsung:
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
* Copyright (c) 2012 Linaro Ltd
* https://www.linaro.org
*
* and pinctrl-at91:
* Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*/
#ifndef _PINCTRL_ROCKCHIP_H
#define _PINCTRL_ROCKCHIP_H
enum
rockchip_pinctrl_type
{
PX30
,
RV1108
,
RK2928
,
RK3066B
,
RK3128
,
RK3188
,
RK3288
,
RK3308
,
RK3368
,
RK3399
,
RK3568
,
};
/**
* struct rockchip_gpio_regs
* @port_dr: data register
* @port_ddr: data direction register
* @int_en: interrupt enable
* @int_mask: interrupt mask
* @int_type: interrupt trigger type, such as high, low, edge trriger type.
* @int_polarity: interrupt polarity enable register
* @int_bothedge: interrupt bothedge enable register
* @int_status: interrupt status register
* @int_rawstatus: int_status = int_rawstatus & int_mask
* @debounce: enable debounce for interrupt signal
* @dbclk_div_en: enable divider for debounce clock
* @dbclk_div_con: setting for divider of debounce clock
* @port_eoi: end of interrupt of the port
* @ext_port: port data from external
* @version_id: controller version register
*/
struct
rockchip_gpio_regs
{
u32
port_dr
;
u32
port_ddr
;
u32
int_en
;
u32
int_mask
;
u32
int_type
;
u32
int_polarity
;
u32
int_bothedge
;
u32
int_status
;
u32
int_rawstatus
;
u32
debounce
;
u32
dbclk_div_en
;
u32
dbclk_div_con
;
u32
port_eoi
;
u32
ext_port
;
u32
version_id
;
};
/**
* struct rockchip_iomux
* @type: iomux variant using IOMUX_* constants
* @offset: if initialized to -1 it will be autocalculated, by specifying
* an initial offset value the relevant source offset can be reset
* to a new value for autocalculating the following iomux registers.
*/
struct
rockchip_iomux
{
int
type
;
int
offset
;
};
/*
* enum type index corresponding to rockchip_perpin_drv_list arrays index.
*/
enum
rockchip_pin_drv_type
{
DRV_TYPE_IO_DEFAULT
=
0
,
DRV_TYPE_IO_1V8_OR_3V0
,
DRV_TYPE_IO_1V8_ONLY
,
DRV_TYPE_IO_1V8_3V0_AUTO
,
DRV_TYPE_IO_3V3_ONLY
,
DRV_TYPE_MAX
};
/*
* enum type index corresponding to rockchip_pull_list arrays index.
*/
enum
rockchip_pin_pull_type
{
PULL_TYPE_IO_DEFAULT
=
0
,
PULL_TYPE_IO_1V8_ONLY
,
PULL_TYPE_MAX
};
/**
* struct rockchip_drv
* @drv_type: drive strength variant using rockchip_perpin_drv_type
* @offset: if initialized to -1 it will be autocalculated, by specifying
* an initial offset value the relevant source offset can be reset
* to a new value for autocalculating the following drive strength
* registers. if used chips own cal_drv func instead to calculate
* registers offset, the variant could be ignored.
*/
struct
rockchip_drv
{
enum
rockchip_pin_drv_type
drv_type
;
int
offset
;
};
/**
* struct rockchip_pin_bank
* @dev: the pinctrl device bind to the bank
* @reg_base: register base of the gpio bank
* @regmap_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
* @db_clk: clock of the gpio debounce
* @irq: interrupt of the gpio bank
* @saved_masks: Saved content of GPIO_INTEN at suspend time.
* @pin_base: first pin number
* @nr_pins: number of pins in this bank
* @name: name of the bank
* @bank_num: number of the bank, to account for holes
* @iomux: array describing the 4 iomux sources of the bank
* @drv: array describing the 4 drive strength sources of the bank
* @pull_type: array describing the 4 pull type sources of the bank
* @valid: is all necessary information present
* @of_node: dt node of this bank
* @drvdata: common pinctrl basedata
* @domain: irqdomain of the gpio bank
* @gpio_chip: gpiolib chip
* @grange: gpio range
* @slock: spinlock for the gpio bank
* @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode
* @recalced_mask: bit mask to indicate a need to recalulate the mask
* @route_mask: bits describing the routing pins of per bank
*/
struct
rockchip_pin_bank
{
struct
device
*
dev
;
void
__iomem
*
reg_base
;
struct
regmap
*
regmap_pull
;
struct
clk
*
clk
;
struct
clk
*
db_clk
;
int
irq
;
u32
saved_masks
;
u32
pin_base
;
u8
nr_pins
;
char
*
name
;
u8
bank_num
;
struct
rockchip_iomux
iomux
[
4
];
struct
rockchip_drv
drv
[
4
];
enum
rockchip_pin_pull_type
pull_type
[
4
];
bool
valid
;
struct
device_node
*
of_node
;
struct
rockchip_pinctrl
*
drvdata
;
struct
irq_domain
*
domain
;
struct
gpio_chip
gpio_chip
;
struct
pinctrl_gpio_range
grange
;
raw_spinlock_t
slock
;
const
struct
rockchip_gpio_regs
*
gpio_regs
;
u32
gpio_type
;
u32
toggle_edge_mode
;
u32
recalced_mask
;
u32
route_mask
;
};
/**
* struct rockchip_mux_recalced_data: represent a pin iomux data.
* @num: bank number.
* @pin: pin number.
* @bit: index at register.
* @reg: register offset.
* @mask: mask bit
*/
struct
rockchip_mux_recalced_data
{
u8
num
;
u8
pin
;
u32
reg
;
u8
bit
;
u8
mask
;
};
enum
rockchip_mux_route_location
{
ROCKCHIP_ROUTE_SAME
=
0
,
ROCKCHIP_ROUTE_PMU
,
ROCKCHIP_ROUTE_GRF
,
};
/**
* struct rockchip_mux_recalced_data: represent a pin iomux data.
* @bank_num: bank number.
* @pin: index at register or used to calc index.
* @func: the min pin.
* @route_location: the mux route location (same, pmu, grf).
* @route_offset: the max pin.
* @route_val: the register offset.
*/
struct
rockchip_mux_route_data
{
u8
bank_num
;
u8
pin
;
u8
func
;
enum
rockchip_mux_route_location
route_location
;
u32
route_offset
;
u32
route_val
;
};
struct
rockchip_pin_ctrl
{
struct
rockchip_pin_bank
*
pin_banks
;
u32
nr_banks
;
u32
nr_pins
;
char
*
label
;
enum
rockchip_pinctrl_type
type
;
int
grf_mux_offset
;
int
pmu_mux_offset
;
int
grf_drv_offset
;
int
pmu_drv_offset
;
struct
rockchip_mux_recalced_data
*
iomux_recalced
;
u32
niomux_recalced
;
struct
rockchip_mux_route_data
*
iomux_routes
;
u32
niomux_routes
;
void
(
*
pull_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
void
(
*
drv_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
int
(
*
schmitt_calc_reg
)(
struct
rockchip_pin_bank
*
bank
,
int
pin_num
,
struct
regmap
**
regmap
,
int
*
reg
,
u8
*
bit
);
};
struct
rockchip_pin_config
{
unsigned
int
func
;
unsigned
long
*
configs
;
unsigned
int
nconfigs
;
};
/**
* struct rockchip_pin_group: represent group of pins of a pinmux function.
* @name: name of the pin group, used to lookup the group.
* @pins: the pins included in this group.
* @npins: number of pins included in this group.
* @data: local pin configuration
*/
struct
rockchip_pin_group
{
const
char
*
name
;
unsigned
int
npins
;
unsigned
int
*
pins
;
struct
rockchip_pin_config
*
data
;
};
/**
* struct rockchip_pmx_func: represent a pin function.
* @name: name of the pin function, used to lookup the function.
* @groups: one or more names of pin groups that provide this function.
* @ngroups: number of groups included in @groups.
*/
struct
rockchip_pmx_func
{
const
char
*
name
;
const
char
**
groups
;
u8
ngroups
;
};
struct
rockchip_pinctrl
{
struct
regmap
*
regmap_base
;
int
reg_size
;
struct
regmap
*
regmap_pull
;
struct
regmap
*
regmap_pmu
;
struct
device
*
dev
;
struct
rockchip_pin_ctrl
*
ctrl
;
struct
pinctrl_desc
pctl
;
struct
pinctrl_dev
*
pctl_dev
;
struct
rockchip_pin_group
*
groups
;
unsigned
int
ngroups
;
struct
rockchip_pmx_func
*
functions
;
unsigned
int
nfunctions
;
};
#endif
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