Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
88826394
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
88826394
编写于
8月 29, 2018
作者:
L
Linus Walleij
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'ib-ingenic' of ../linux-pinctrl into devel
上级
62cdcb6c
28d6eeb4
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
487 addition
and
470 deletion
+487
-470
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
+0
-46
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
...mentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
+35
-4
drivers/gpio/Kconfig
drivers/gpio/Kconfig
+0
-11
drivers/gpio/Makefile
drivers/gpio/Makefile
+0
-1
drivers/gpio/gpio-ingenic.c
drivers/gpio/gpio-ingenic.c
+0
-392
drivers/pinctrl/Kconfig
drivers/pinctrl/Kconfig
+4
-2
drivers/pinctrl/pinctrl-ingenic.c
drivers/pinctrl/pinctrl-ingenic.c
+448
-14
未找到文件。
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
已删除
100644 → 0
浏览文件 @
62cdcb6c
Ingenic jz47xx GPIO controller
That the Ingenic GPIO driver node must be a sub-node of the Ingenic pinctrl
driver node.
Required properties:
--------------------
- compatible: Must contain one of:
- "ingenic,jz4740-gpio"
- "ingenic,jz4770-gpio"
- "ingenic,jz4780-gpio"
- reg: The GPIO bank number.
- interrupt-controller: Marks the device node as an interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
- #interrupt-cells: Should be 2. Refer to
../interrupt-controller/interrupts.txt for more details.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
- gpio-ranges: Range of pins managed by the GPIO controller. Refer to
'gpio.txt' in this directory for more details.
Example:
--------
&pinctrl {
#address-cells = <1>;
#size-cells = <0>;
gpa: gpio@0 {
compatible = "ingenic,jz4740-gpio";
reg = <0>;
gpio-controller;
gpio-ranges = <&pinctrl 0 0 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <28>;
};
};
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
浏览文件 @
88826394
...
...
@@ -20,16 +20,30 @@ Required properties:
- compatible: One of:
- "ingenic,jz4740-pinctrl"
- "ingenic,jz4725b-pinctrl"
- "ingenic,jz4770-pinctrl"
- "ingenic,jz4780-pinctrl"
- reg: Address range of the pinctrl registers.
GPIO sub-nodes
--------------
Required properties for sub-nodes (GPIO chips):
--------------
---------------------------------
The pinctrl node can have optional sub-nodes for the Ingenic GPIO driver;
please refer to ../gpio/ingenic,gpio.txt.
- compatible: Must contain one of:
- "ingenic,jz4740-gpio"
- "ingenic,jz4770-gpio"
- "ingenic,jz4780-gpio"
- reg: The GPIO bank number.
- interrupt-controller: Marks the device node as an interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
- #interrupt-cells: Should be 2. Refer to
../interrupt-controller/interrupts.txt for more details.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
- gpio-ranges: Range of pins managed by the GPIO controller. Refer to
../gpio/gpio.txt for more details.
Example:
...
...
@@ -38,4 +52,21 @@ Example:
pinctrl: pin-controller@10010000 {
compatible = "ingenic,jz4740-pinctrl";
reg = <0x10010000 0x400>;
#address-cells = <1>;
#size-cells = <0>;
gpa: gpio@0 {
compatible = "ingenic,jz4740-gpio";
reg = <0>;
gpio-controller;
gpio-ranges = <&pinctrl 0 0 32>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <28>;
};
};
drivers/gpio/Kconfig
浏览文件 @
88826394
...
...
@@ -268,17 +268,6 @@ config GPIO_ICH
If unsure, say N.
config GPIO_INGENIC
tristate "Ingenic JZ47xx SoCs GPIO support"
depends on OF
depends on MACH_INGENIC || COMPILE_TEST
select GPIOLIB_IRQCHIP
help
Say yes here to support the GPIO functionality present on the
JZ4740 and JZ4780 SoCs from Ingenic.
If unsure, say N.
config GPIO_IOP
tristate "Intel IOP GPIO"
depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
...
...
drivers/gpio/Makefile
浏览文件 @
88826394
...
...
@@ -57,7 +57,6 @@ obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_HLWD)
+=
gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO)
+=
gpio-htc-egpio.o
obj-$(CONFIG_GPIO_ICH)
+=
gpio-ich.o
obj-$(CONFIG_GPIO_INGENIC)
+=
gpio-ingenic.o
obj-$(CONFIG_GPIO_IOP)
+=
gpio-iop.o
obj-$(CONFIG_GPIO_IT87)
+=
gpio-it87.o
obj-$(CONFIG_GPIO_JANZ_TTL)
+=
gpio-janz-ttl.o
...
...
drivers/gpio/gpio-ingenic.c
已删除
100644 → 0
浏览文件 @
62cdcb6c
/*
* Ingenic JZ47xx GPIO driver
*
* Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
*
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#define GPIO_PIN 0x00
#define GPIO_MSK 0x20
#define JZ4740_GPIO_DATA 0x10
#define JZ4740_GPIO_SELECT 0x50
#define JZ4740_GPIO_DIR 0x60
#define JZ4740_GPIO_TRIG 0x70
#define JZ4740_GPIO_FLAG 0x80
#define JZ4770_GPIO_INT 0x10
#define JZ4770_GPIO_PAT1 0x30
#define JZ4770_GPIO_PAT0 0x40
#define JZ4770_GPIO_FLAG 0x50
#define REG_SET(x) ((x) + 0x4)
#define REG_CLEAR(x) ((x) + 0x8)
enum
jz_version
{
ID_JZ4740
,
ID_JZ4770
,
ID_JZ4780
,
};
struct
ingenic_gpio_chip
{
struct
regmap
*
map
;
struct
gpio_chip
gc
;
struct
irq_chip
irq_chip
;
unsigned
int
irq
,
reg_base
;
enum
jz_version
version
;
};
static
u32
gpio_ingenic_read_reg
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
reg
)
{
unsigned
int
val
;
regmap_read
(
jzgc
->
map
,
jzgc
->
reg_base
+
reg
,
&
val
);
return
(
u32
)
val
;
}
static
void
gpio_ingenic_set_bit
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
reg
,
u8
offset
,
bool
set
)
{
if
(
set
)
reg
=
REG_SET
(
reg
);
else
reg
=
REG_CLEAR
(
reg
);
regmap_write
(
jzgc
->
map
,
jzgc
->
reg_base
+
reg
,
BIT
(
offset
));
}
static
inline
bool
gpio_get_value
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
)
{
unsigned
int
val
=
gpio_ingenic_read_reg
(
jzgc
,
GPIO_PIN
);
return
!!
(
val
&
BIT
(
offset
));
}
static
void
gpio_set_value
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
,
int
value
)
{
if
(
jzgc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_PAT0
,
offset
,
!!
value
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_DATA
,
offset
,
!!
value
);
}
static
void
irq_set_type
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
,
unsigned
int
type
)
{
u8
reg1
,
reg2
;
if
(
jzgc
->
version
>=
ID_JZ4770
)
{
reg1
=
JZ4770_GPIO_PAT1
;
reg2
=
JZ4770_GPIO_PAT0
;
}
else
{
reg1
=
JZ4740_GPIO_TRIG
;
reg2
=
JZ4740_GPIO_DIR
;
}
switch
(
type
)
{
case
IRQ_TYPE_EDGE_RISING
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
true
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
true
);
break
;
case
IRQ_TYPE_EDGE_FALLING
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
false
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
true
);
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
true
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
false
);
break
;
case
IRQ_TYPE_LEVEL_LOW
:
default:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
false
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
false
);
break
;
}
}
static
void
ingenic_gpio_irq_mask
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
gpio_ingenic_set_bit
(
jzgc
,
GPIO_MSK
,
irqd
->
hwirq
,
true
);
}
static
void
ingenic_gpio_irq_unmask
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
gpio_ingenic_set_bit
(
jzgc
,
GPIO_MSK
,
irqd
->
hwirq
,
false
);
}
static
void
ingenic_gpio_irq_enable
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
if
(
jzgc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_INT
,
irq
,
true
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_SELECT
,
irq
,
true
);
ingenic_gpio_irq_unmask
(
irqd
);
}
static
void
ingenic_gpio_irq_disable
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
ingenic_gpio_irq_mask
(
irqd
);
if
(
jzgc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_INT
,
irq
,
false
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_SELECT
,
irq
,
false
);
}
static
void
ingenic_gpio_irq_ack
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
bool
high
;
if
(
irqd_get_trigger_type
(
irqd
)
==
IRQ_TYPE_EDGE_BOTH
)
{
/*
* Switch to an interrupt for the opposite edge to the one that
* triggered the interrupt being ACKed.
*/
high
=
gpio_get_value
(
jzgc
,
irq
);
if
(
high
)
irq_set_type
(
jzgc
,
irq
,
IRQ_TYPE_EDGE_FALLING
);
else
irq_set_type
(
jzgc
,
irq
,
IRQ_TYPE_EDGE_RISING
);
}
if
(
jzgc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_FLAG
,
irq
,
false
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_DATA
,
irq
,
true
);
}
static
int
ingenic_gpio_irq_set_type
(
struct
irq_data
*
irqd
,
unsigned
int
type
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
switch
(
type
)
{
case
IRQ_TYPE_EDGE_BOTH
:
case
IRQ_TYPE_EDGE_RISING
:
case
IRQ_TYPE_EDGE_FALLING
:
irq_set_handler_locked
(
irqd
,
handle_edge_irq
);
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
case
IRQ_TYPE_LEVEL_LOW
:
irq_set_handler_locked
(
irqd
,
handle_level_irq
);
break
;
default:
irq_set_handler_locked
(
irqd
,
handle_bad_irq
);
}
if
(
type
==
IRQ_TYPE_EDGE_BOTH
)
{
/*
* The hardware does not support interrupts on both edges. The
* best we can do is to set up a single-edge interrupt and then
* switch to the opposing edge when ACKing the interrupt.
*/
bool
high
=
gpio_get_value
(
jzgc
,
irqd
->
hwirq
);
type
=
high
?
IRQ_TYPE_EDGE_FALLING
:
IRQ_TYPE_EDGE_RISING
;
}
irq_set_type
(
jzgc
,
irqd
->
hwirq
,
type
);
return
0
;
}
static
int
ingenic_gpio_irq_set_wake
(
struct
irq_data
*
irqd
,
unsigned
int
on
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
return
irq_set_irq_wake
(
jzgc
->
irq
,
on
);
}
static
void
ingenic_gpio_irq_handler
(
struct
irq_desc
*
desc
)
{
struct
gpio_chip
*
gc
=
irq_desc_get_handler_data
(
desc
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
struct
irq_chip
*
irq_chip
=
irq_data_get_irq_chip
(
&
desc
->
irq_data
);
unsigned
long
flag
,
i
;
chained_irq_enter
(
irq_chip
,
desc
);
if
(
jzgc
->
version
>=
ID_JZ4770
)
flag
=
gpio_ingenic_read_reg
(
jzgc
,
JZ4770_GPIO_FLAG
);
else
flag
=
gpio_ingenic_read_reg
(
jzgc
,
JZ4740_GPIO_FLAG
);
for_each_set_bit
(
i
,
&
flag
,
32
)
generic_handle_irq
(
irq_linear_revmap
(
gc
->
irq
.
domain
,
i
));
chained_irq_exit
(
irq_chip
,
desc
);
}
static
void
ingenic_gpio_set
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
gpio_set_value
(
jzgc
,
offset
,
value
);
}
static
int
ingenic_gpio_get
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
return
(
int
)
gpio_get_value
(
jzgc
,
offset
);
}
static
int
ingenic_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
return
pinctrl_gpio_direction_input
(
gc
->
base
+
offset
);
}
static
int
ingenic_gpio_direction_output
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
ingenic_gpio_set
(
gc
,
offset
,
value
);
return
pinctrl_gpio_direction_output
(
gc
->
base
+
offset
);
}
static
const
struct
of_device_id
ingenic_gpio_of_match
[]
=
{
{
.
compatible
=
"ingenic,jz4740-gpio"
,
.
data
=
(
void
*
)
ID_JZ4740
},
{
.
compatible
=
"ingenic,jz4770-gpio"
,
.
data
=
(
void
*
)
ID_JZ4770
},
{
.
compatible
=
"ingenic,jz4780-gpio"
,
.
data
=
(
void
*
)
ID_JZ4780
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
ingenic_gpio_of_match
);
static
int
ingenic_gpio_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
ingenic_gpio_chip
*
jzgc
;
u32
bank
;
int
err
;
jzgc
=
devm_kzalloc
(
dev
,
sizeof
(
*
jzgc
),
GFP_KERNEL
);
if
(
!
jzgc
)
return
-
ENOMEM
;
jzgc
->
map
=
dev_get_drvdata
(
dev
->
parent
);
if
(
!
jzgc
->
map
)
{
dev_err
(
dev
,
"Cannot get parent regmap
\n
"
);
return
-
ENXIO
;
}
err
=
of_property_read_u32
(
dev
->
of_node
,
"reg"
,
&
bank
);
if
(
err
)
{
dev_err
(
dev
,
"Cannot read
\"
reg
\"
property: %i
\n
"
,
err
);
return
err
;
}
jzgc
->
reg_base
=
bank
*
0x100
;
jzgc
->
gc
.
label
=
devm_kasprintf
(
dev
,
GFP_KERNEL
,
"GPIO%c"
,
'A'
+
bank
);
if
(
!
jzgc
->
gc
.
label
)
return
-
ENOMEM
;
/* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
* ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
* <linux/gpio/consumer.h> INSTEAD.
*/
jzgc
->
gc
.
base
=
bank
*
32
;
jzgc
->
gc
.
ngpio
=
32
;
jzgc
->
gc
.
parent
=
dev
;
jzgc
->
gc
.
of_node
=
dev
->
of_node
;
jzgc
->
gc
.
owner
=
THIS_MODULE
;
jzgc
->
version
=
(
enum
jz_version
)
of_device_get_match_data
(
dev
);
jzgc
->
gc
.
set
=
ingenic_gpio_set
;
jzgc
->
gc
.
get
=
ingenic_gpio_get
;
jzgc
->
gc
.
direction_input
=
ingenic_gpio_direction_input
;
jzgc
->
gc
.
direction_output
=
ingenic_gpio_direction_output
;
if
(
of_property_read_bool
(
dev
->
of_node
,
"gpio-ranges"
))
{
jzgc
->
gc
.
request
=
gpiochip_generic_request
;
jzgc
->
gc
.
free
=
gpiochip_generic_free
;
}
err
=
devm_gpiochip_add_data
(
dev
,
&
jzgc
->
gc
,
jzgc
);
if
(
err
)
return
err
;
jzgc
->
irq
=
irq_of_parse_and_map
(
dev
->
of_node
,
0
);
if
(
!
jzgc
->
irq
)
return
-
EINVAL
;
jzgc
->
irq_chip
.
name
=
jzgc
->
gc
.
label
;
jzgc
->
irq_chip
.
irq_enable
=
ingenic_gpio_irq_enable
;
jzgc
->
irq_chip
.
irq_disable
=
ingenic_gpio_irq_disable
;
jzgc
->
irq_chip
.
irq_unmask
=
ingenic_gpio_irq_unmask
;
jzgc
->
irq_chip
.
irq_mask
=
ingenic_gpio_irq_mask
;
jzgc
->
irq_chip
.
irq_ack
=
ingenic_gpio_irq_ack
;
jzgc
->
irq_chip
.
irq_set_type
=
ingenic_gpio_irq_set_type
;
jzgc
->
irq_chip
.
irq_set_wake
=
ingenic_gpio_irq_set_wake
;
jzgc
->
irq_chip
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
;
err
=
gpiochip_irqchip_add
(
&
jzgc
->
gc
,
&
jzgc
->
irq_chip
,
0
,
handle_level_irq
,
IRQ_TYPE_NONE
);
if
(
err
)
return
err
;
gpiochip_set_chained_irqchip
(
&
jzgc
->
gc
,
&
jzgc
->
irq_chip
,
jzgc
->
irq
,
ingenic_gpio_irq_handler
);
return
0
;
}
static
int
ingenic_gpio_remove
(
struct
platform_device
*
pdev
)
{
return
0
;
}
static
struct
platform_driver
ingenic_gpio_driver
=
{
.
driver
=
{
.
name
=
"gpio-ingenic"
,
.
of_match_table
=
of_match_ptr
(
ingenic_gpio_of_match
),
},
.
probe
=
ingenic_gpio_probe
,
.
remove
=
ingenic_gpio_remove
,
};
static
int
__init
ingenic_gpio_drv_register
(
void
)
{
return
platform_driver_register
(
&
ingenic_gpio_driver
);
}
subsys_initcall
(
ingenic_gpio_drv_register
);
static
void
__exit
ingenic_gpio_drv_unregister
(
void
)
{
platform_driver_unregister
(
&
ingenic_gpio_driver
);
}
module_exit
(
ingenic_gpio_drv_unregister
);
MODULE_AUTHOR
(
"Paul Cercueil <paul@crapouillou.net>"
);
MODULE_DESCRIPTION
(
"Ingenic JZ47xx GPIO driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/pinctrl/Kconfig
浏览文件 @
88826394
...
...
@@ -309,12 +309,14 @@ config PINCTRL_ZYNQ
config PINCTRL_INGENIC
bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
default
y
default
MACH_INGENIC
depends on OF
depends on M
ACH_INGENIC
|| COMPILE_TEST
depends on M
IPS
|| COMPILE_TEST
select GENERIC_PINCONF
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
select GPIOLIB
select GPIOLIB_IRQCHIP
select REGMAP_MMIO
config PINCTRL_RK805
...
...
drivers/pinctrl/pinctrl-ingenic.c
浏览文件 @
88826394
...
...
@@ -7,10 +7,11 @@
*/
#include <linux/compiler.h>
#include <linux/gpio.h>
#include <linux/gpio
/driver
.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
...
...
@@ -24,6 +25,9 @@
#include "pinconf.h"
#include "pinmux.h"
#define GPIO_PIN 0x00
#define GPIO_MSK 0x20
#define JZ4740_GPIO_DATA 0x10
#define JZ4740_GPIO_PULL_DIS 0x30
#define JZ4740_GPIO_FUNC 0x40
...
...
@@ -33,7 +37,6 @@
#define JZ4740_GPIO_FLAG 0x80
#define JZ4770_GPIO_INT 0x10
#define JZ4770_GPIO_MSK 0x20
#define JZ4770_GPIO_PAT1 0x30
#define JZ4770_GPIO_PAT0 0x40
#define JZ4770_GPIO_FLAG 0x50
...
...
@@ -46,6 +49,7 @@
enum
jz_version
{
ID_JZ4740
,
ID_JZ4725B
,
ID_JZ4770
,
ID_JZ4780
,
};
...
...
@@ -72,6 +76,13 @@ struct ingenic_pinctrl {
const
struct
ingenic_chip_info
*
info
;
};
struct
ingenic_gpio_chip
{
struct
ingenic_pinctrl
*
jzpc
;
struct
gpio_chip
gc
;
struct
irq_chip
irq_chip
;
unsigned
int
irq
,
reg_base
;
};
static
const
u32
jz4740_pull_ups
[
4
]
=
{
0xffffffff
,
0xffffffff
,
0xffffffff
,
0xffffffff
,
};
...
...
@@ -205,6 +216,99 @@ static const struct ingenic_chip_info jz4740_chip_info = {
.
pull_downs
=
jz4740_pull_downs
,
};
static
int
jz4725b_mmc0_1bit_pins
[]
=
{
0x48
,
0x49
,
0x5c
,
};
static
int
jz4725b_mmc0_4bit_pins
[]
=
{
0x5d
,
0x5b
,
0x56
,
};
static
int
jz4725b_mmc1_1bit_pins
[]
=
{
0x7a
,
0x7b
,
0x7c
,
};
static
int
jz4725b_mmc1_4bit_pins
[]
=
{
0x7d
,
0x7e
,
0x7f
,
};
static
int
jz4725b_uart_data_pins
[]
=
{
0x4c
,
0x4d
,
};
static
int
jz4725b_nand_cs1_pins
[]
=
{
0x55
,
};
static
int
jz4725b_nand_cs2_pins
[]
=
{
0x56
,
};
static
int
jz4725b_nand_cs3_pins
[]
=
{
0x57
,
};
static
int
jz4725b_nand_cs4_pins
[]
=
{
0x58
,
};
static
int
jz4725b_nand_cle_ale_pins
[]
=
{
0x48
,
0x49
};
static
int
jz4725b_nand_fre_fwe_pins
[]
=
{
0x5c
,
0x5d
};
static
int
jz4725b_pwm_pwm0_pins
[]
=
{
0x4a
,
};
static
int
jz4725b_pwm_pwm1_pins
[]
=
{
0x4b
,
};
static
int
jz4725b_pwm_pwm2_pins
[]
=
{
0x4c
,
};
static
int
jz4725b_pwm_pwm3_pins
[]
=
{
0x4d
,
};
static
int
jz4725b_pwm_pwm4_pins
[]
=
{
0x4e
,
};
static
int
jz4725b_pwm_pwm5_pins
[]
=
{
0x4f
,
};
static
int
jz4725b_mmc0_1bit_funcs
[]
=
{
1
,
1
,
1
,
};
static
int
jz4725b_mmc0_4bit_funcs
[]
=
{
1
,
0
,
1
,
};
static
int
jz4725b_mmc1_1bit_funcs
[]
=
{
0
,
0
,
0
,
};
static
int
jz4725b_mmc1_4bit_funcs
[]
=
{
0
,
0
,
0
,
};
static
int
jz4725b_uart_data_funcs
[]
=
{
1
,
1
,
};
static
int
jz4725b_nand_cs1_funcs
[]
=
{
0
,
};
static
int
jz4725b_nand_cs2_funcs
[]
=
{
0
,
};
static
int
jz4725b_nand_cs3_funcs
[]
=
{
0
,
};
static
int
jz4725b_nand_cs4_funcs
[]
=
{
0
,
};
static
int
jz4725b_nand_cle_ale_funcs
[]
=
{
0
,
0
,
};
static
int
jz4725b_nand_fre_fwe_funcs
[]
=
{
0
,
0
,
};
static
int
jz4725b_pwm_pwm0_funcs
[]
=
{
0
,
};
static
int
jz4725b_pwm_pwm1_funcs
[]
=
{
0
,
};
static
int
jz4725b_pwm_pwm2_funcs
[]
=
{
0
,
};
static
int
jz4725b_pwm_pwm3_funcs
[]
=
{
0
,
};
static
int
jz4725b_pwm_pwm4_funcs
[]
=
{
0
,
};
static
int
jz4725b_pwm_pwm5_funcs
[]
=
{
0
,
};
static
const
struct
group_desc
jz4725b_groups
[]
=
{
INGENIC_PIN_GROUP
(
"mmc0-1bit"
,
jz4725b_mmc0_1bit
),
INGENIC_PIN_GROUP
(
"mmc0-4bit"
,
jz4725b_mmc0_4bit
),
INGENIC_PIN_GROUP
(
"mmc1-1bit"
,
jz4725b_mmc1_1bit
),
INGENIC_PIN_GROUP
(
"mmc1-4bit"
,
jz4725b_mmc1_4bit
),
INGENIC_PIN_GROUP
(
"uart-data"
,
jz4725b_uart_data
),
INGENIC_PIN_GROUP
(
"nand-cs1"
,
jz4725b_nand_cs1
),
INGENIC_PIN_GROUP
(
"nand-cs2"
,
jz4725b_nand_cs2
),
INGENIC_PIN_GROUP
(
"nand-cs3"
,
jz4725b_nand_cs3
),
INGENIC_PIN_GROUP
(
"nand-cs4"
,
jz4725b_nand_cs4
),
INGENIC_PIN_GROUP
(
"nand-cle-ale"
,
jz4725b_nand_cle_ale
),
INGENIC_PIN_GROUP
(
"nand-fre-fwe"
,
jz4725b_nand_fre_fwe
),
INGENIC_PIN_GROUP
(
"pwm0"
,
jz4725b_pwm_pwm0
),
INGENIC_PIN_GROUP
(
"pwm1"
,
jz4725b_pwm_pwm1
),
INGENIC_PIN_GROUP
(
"pwm2"
,
jz4725b_pwm_pwm2
),
INGENIC_PIN_GROUP
(
"pwm3"
,
jz4725b_pwm_pwm3
),
INGENIC_PIN_GROUP
(
"pwm4"
,
jz4725b_pwm_pwm4
),
INGENIC_PIN_GROUP
(
"pwm5"
,
jz4725b_pwm_pwm5
),
};
static
const
char
*
jz4725b_mmc0_groups
[]
=
{
"mmc0-1bit"
,
"mmc0-4bit"
,
};
static
const
char
*
jz4725b_mmc1_groups
[]
=
{
"mmc1-1bit"
,
"mmc1-4bit"
,
};
static
const
char
*
jz4725b_uart_groups
[]
=
{
"uart-data"
,
};
static
const
char
*
jz4725b_nand_groups
[]
=
{
"nand-cs1"
,
"nand-cs2"
,
"nand-cs3"
,
"nand-cs4"
,
"nand-cle-ale"
,
"nand-fre-fwe"
,
};
static
const
char
*
jz4725b_pwm0_groups
[]
=
{
"pwm0"
,
};
static
const
char
*
jz4725b_pwm1_groups
[]
=
{
"pwm1"
,
};
static
const
char
*
jz4725b_pwm2_groups
[]
=
{
"pwm2"
,
};
static
const
char
*
jz4725b_pwm3_groups
[]
=
{
"pwm3"
,
};
static
const
char
*
jz4725b_pwm4_groups
[]
=
{
"pwm4"
,
};
static
const
char
*
jz4725b_pwm5_groups
[]
=
{
"pwm5"
,
};
static
const
struct
function_desc
jz4725b_functions
[]
=
{
{
"mmc0"
,
jz4725b_mmc0_groups
,
ARRAY_SIZE
(
jz4725b_mmc0_groups
),
},
{
"mmc1"
,
jz4725b_mmc1_groups
,
ARRAY_SIZE
(
jz4725b_mmc1_groups
),
},
{
"uart"
,
jz4725b_uart_groups
,
ARRAY_SIZE
(
jz4725b_uart_groups
),
},
{
"nand"
,
jz4725b_nand_groups
,
ARRAY_SIZE
(
jz4725b_nand_groups
),
},
{
"pwm0"
,
jz4725b_pwm0_groups
,
ARRAY_SIZE
(
jz4725b_pwm0_groups
),
},
{
"pwm1"
,
jz4725b_pwm1_groups
,
ARRAY_SIZE
(
jz4725b_pwm1_groups
),
},
{
"pwm2"
,
jz4725b_pwm2_groups
,
ARRAY_SIZE
(
jz4725b_pwm2_groups
),
},
{
"pwm3"
,
jz4725b_pwm3_groups
,
ARRAY_SIZE
(
jz4725b_pwm3_groups
),
},
{
"pwm4"
,
jz4725b_pwm4_groups
,
ARRAY_SIZE
(
jz4725b_pwm4_groups
),
},
{
"pwm5"
,
jz4725b_pwm5_groups
,
ARRAY_SIZE
(
jz4725b_pwm5_groups
),
},
};
static
const
struct
ingenic_chip_info
jz4725b_chip_info
=
{
.
num_chips
=
4
,
.
groups
=
jz4725b_groups
,
.
num_groups
=
ARRAY_SIZE
(
jz4725b_groups
),
.
functions
=
jz4725b_functions
,
.
num_functions
=
ARRAY_SIZE
(
jz4725b_functions
),
.
pull_ups
=
jz4740_pull_ups
,
.
pull_downs
=
jz4740_pull_downs
,
};
static
const
u32
jz4770_pull_ups
[
6
]
=
{
0x3fffffff
,
0xfff0030c
,
0xffffffff
,
0xffff4fff
,
0xfffffb7c
,
0xffa7f00f
,
};
...
...
@@ -438,6 +542,235 @@ static const struct ingenic_chip_info jz4770_chip_info = {
.
pull_downs
=
jz4770_pull_downs
,
};
static
u32
gpio_ingenic_read_reg
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
reg
)
{
unsigned
int
val
;
regmap_read
(
jzgc
->
jzpc
->
map
,
jzgc
->
reg_base
+
reg
,
&
val
);
return
(
u32
)
val
;
}
static
void
gpio_ingenic_set_bit
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
reg
,
u8
offset
,
bool
set
)
{
if
(
set
)
reg
=
REG_SET
(
reg
);
else
reg
=
REG_CLEAR
(
reg
);
regmap_write
(
jzgc
->
jzpc
->
map
,
jzgc
->
reg_base
+
reg
,
BIT
(
offset
));
}
static
inline
bool
ingenic_gpio_get_value
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
)
{
unsigned
int
val
=
gpio_ingenic_read_reg
(
jzgc
,
GPIO_PIN
);
return
!!
(
val
&
BIT
(
offset
));
}
static
void
ingenic_gpio_set_value
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
,
int
value
)
{
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_PAT0
,
offset
,
!!
value
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_DATA
,
offset
,
!!
value
);
}
static
void
irq_set_type
(
struct
ingenic_gpio_chip
*
jzgc
,
u8
offset
,
unsigned
int
type
)
{
u8
reg1
,
reg2
;
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
{
reg1
=
JZ4770_GPIO_PAT1
;
reg2
=
JZ4770_GPIO_PAT0
;
}
else
{
reg1
=
JZ4740_GPIO_TRIG
;
reg2
=
JZ4740_GPIO_DIR
;
}
switch
(
type
)
{
case
IRQ_TYPE_EDGE_RISING
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
true
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
true
);
break
;
case
IRQ_TYPE_EDGE_FALLING
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
false
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
true
);
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
true
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
false
);
break
;
case
IRQ_TYPE_LEVEL_LOW
:
default:
gpio_ingenic_set_bit
(
jzgc
,
reg2
,
offset
,
false
);
gpio_ingenic_set_bit
(
jzgc
,
reg1
,
offset
,
false
);
break
;
}
}
static
void
ingenic_gpio_irq_mask
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
gpio_ingenic_set_bit
(
jzgc
,
GPIO_MSK
,
irqd
->
hwirq
,
true
);
}
static
void
ingenic_gpio_irq_unmask
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
gpio_ingenic_set_bit
(
jzgc
,
GPIO_MSK
,
irqd
->
hwirq
,
false
);
}
static
void
ingenic_gpio_irq_enable
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_INT
,
irq
,
true
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_SELECT
,
irq
,
true
);
ingenic_gpio_irq_unmask
(
irqd
);
}
static
void
ingenic_gpio_irq_disable
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
ingenic_gpio_irq_mask
(
irqd
);
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_INT
,
irq
,
false
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_SELECT
,
irq
,
false
);
}
static
void
ingenic_gpio_irq_ack
(
struct
irq_data
*
irqd
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
int
irq
=
irqd
->
hwirq
;
bool
high
;
if
(
irqd_get_trigger_type
(
irqd
)
==
IRQ_TYPE_EDGE_BOTH
)
{
/*
* Switch to an interrupt for the opposite edge to the one that
* triggered the interrupt being ACKed.
*/
high
=
ingenic_gpio_get_value
(
jzgc
,
irq
);
if
(
high
)
irq_set_type
(
jzgc
,
irq
,
IRQ_TYPE_EDGE_FALLING
);
else
irq_set_type
(
jzgc
,
irq
,
IRQ_TYPE_EDGE_RISING
);
}
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
gpio_ingenic_set_bit
(
jzgc
,
JZ4770_GPIO_FLAG
,
irq
,
false
);
else
gpio_ingenic_set_bit
(
jzgc
,
JZ4740_GPIO_DATA
,
irq
,
true
);
}
static
int
ingenic_gpio_irq_set_type
(
struct
irq_data
*
irqd
,
unsigned
int
type
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
switch
(
type
)
{
case
IRQ_TYPE_EDGE_BOTH
:
case
IRQ_TYPE_EDGE_RISING
:
case
IRQ_TYPE_EDGE_FALLING
:
irq_set_handler_locked
(
irqd
,
handle_edge_irq
);
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
case
IRQ_TYPE_LEVEL_LOW
:
irq_set_handler_locked
(
irqd
,
handle_level_irq
);
break
;
default:
irq_set_handler_locked
(
irqd
,
handle_bad_irq
);
}
if
(
type
==
IRQ_TYPE_EDGE_BOTH
)
{
/*
* The hardware does not support interrupts on both edges. The
* best we can do is to set up a single-edge interrupt and then
* switch to the opposing edge when ACKing the interrupt.
*/
bool
high
=
ingenic_gpio_get_value
(
jzgc
,
irqd
->
hwirq
);
type
=
high
?
IRQ_TYPE_EDGE_FALLING
:
IRQ_TYPE_EDGE_RISING
;
}
irq_set_type
(
jzgc
,
irqd
->
hwirq
,
type
);
return
0
;
}
static
int
ingenic_gpio_irq_set_wake
(
struct
irq_data
*
irqd
,
unsigned
int
on
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
irqd
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
return
irq_set_irq_wake
(
jzgc
->
irq
,
on
);
}
static
void
ingenic_gpio_irq_handler
(
struct
irq_desc
*
desc
)
{
struct
gpio_chip
*
gc
=
irq_desc_get_handler_data
(
desc
);
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
struct
irq_chip
*
irq_chip
=
irq_data_get_irq_chip
(
&
desc
->
irq_data
);
unsigned
long
flag
,
i
;
chained_irq_enter
(
irq_chip
,
desc
);
if
(
jzgc
->
jzpc
->
version
>=
ID_JZ4770
)
flag
=
gpio_ingenic_read_reg
(
jzgc
,
JZ4770_GPIO_FLAG
);
else
flag
=
gpio_ingenic_read_reg
(
jzgc
,
JZ4740_GPIO_FLAG
);
for_each_set_bit
(
i
,
&
flag
,
32
)
generic_handle_irq
(
irq_linear_revmap
(
gc
->
irq
.
domain
,
i
));
chained_irq_exit
(
irq_chip
,
desc
);
}
static
void
ingenic_gpio_set
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
ingenic_gpio_set_value
(
jzgc
,
offset
,
value
);
}
static
int
ingenic_gpio_get
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
return
(
int
)
ingenic_gpio_get_value
(
jzgc
,
offset
);
}
static
int
ingenic_gpio_direction_input
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
return
pinctrl_gpio_direction_input
(
gc
->
base
+
offset
);
}
static
int
ingenic_gpio_direction_output
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
int
value
)
{
ingenic_gpio_set
(
gc
,
offset
,
value
);
return
pinctrl_gpio_direction_output
(
gc
->
base
+
offset
);
}
static
inline
void
ingenic_config_pin
(
struct
ingenic_pinctrl
*
jzpc
,
unsigned
int
pin
,
u8
reg
,
bool
set
)
{
...
...
@@ -460,6 +793,21 @@ static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
return
val
&
BIT
(
idx
);
}
static
int
ingenic_gpio_get_direction
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
)
{
struct
ingenic_gpio_chip
*
jzgc
=
gpiochip_get_data
(
gc
);
struct
ingenic_pinctrl
*
jzpc
=
jzgc
->
jzpc
;
unsigned
int
pin
=
gc
->
base
+
offset
;
if
(
jzpc
->
version
>=
ID_JZ4770
)
return
ingenic_get_pin_config
(
jzpc
,
pin
,
JZ4770_GPIO_PAT1
);
if
(
ingenic_get_pin_config
(
jzpc
,
pin
,
JZ4740_GPIO_SELECT
))
return
true
;
return
!
ingenic_get_pin_config
(
jzpc
,
pin
,
JZ4740_GPIO_DIR
);
}
static
const
struct
pinctrl_ops
ingenic_pctlops
=
{
.
get_groups_count
=
pinctrl_generic_get_group_count
,
.
get_group_name
=
pinctrl_generic_get_group_name
,
...
...
@@ -479,7 +827,7 @@ static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
if
(
jzpc
->
version
>=
ID_JZ4770
)
{
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_GPIO_INT
,
false
);
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_
GPIO_MSK
,
false
);
ingenic_config_pin
(
jzpc
,
pin
,
GPIO_MSK
,
false
);
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_GPIO_PAT1
,
func
&
0x2
);
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_GPIO_PAT0
,
func
&
0x1
);
}
else
{
...
...
@@ -532,7 +880,7 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
if
(
jzpc
->
version
>=
ID_JZ4770
)
{
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_GPIO_INT
,
false
);
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_
GPIO_MSK
,
true
);
ingenic_config_pin
(
jzpc
,
pin
,
GPIO_MSK
,
true
);
ingenic_config_pin
(
jzpc
,
pin
,
JZ4770_GPIO_PAT1
,
input
);
}
else
{
ingenic_config_pin
(
jzpc
,
pin
,
JZ4740_GPIO_SELECT
,
false
);
...
...
@@ -712,12 +1060,95 @@ static const struct regmap_config ingenic_pinctrl_regmap_config = {
static
const
struct
of_device_id
ingenic_pinctrl_of_match
[]
=
{
{
.
compatible
=
"ingenic,jz4740-pinctrl"
,
.
data
=
(
void
*
)
ID_JZ4740
},
{
.
compatible
=
"ingenic,jz4725b-pinctrl"
,
.
data
=
(
void
*
)
ID_JZ4725B
},
{
.
compatible
=
"ingenic,jz4770-pinctrl"
,
.
data
=
(
void
*
)
ID_JZ4770
},
{
.
compatible
=
"ingenic,jz4780-pinctrl"
,
.
data
=
(
void
*
)
ID_JZ4780
},
{},
};
static
int
ingenic_pinctrl_probe
(
struct
platform_device
*
pdev
)
static
const
struct
of_device_id
ingenic_gpio_of_match
[]
__initconst
=
{
{
.
compatible
=
"ingenic,jz4740-gpio"
,
},
{
.
compatible
=
"ingenic,jz4770-gpio"
,
},
{
.
compatible
=
"ingenic,jz4780-gpio"
,
},
{},
};
static
int
__init
ingenic_gpio_probe
(
struct
ingenic_pinctrl
*
jzpc
,
struct
device_node
*
node
)
{
struct
ingenic_gpio_chip
*
jzgc
;
struct
device
*
dev
=
jzpc
->
dev
;
unsigned
int
bank
;
int
err
;
err
=
of_property_read_u32
(
node
,
"reg"
,
&
bank
);
if
(
err
)
{
dev_err
(
dev
,
"Cannot read
\"
reg
\"
property: %i
\n
"
,
err
);
return
err
;
}
jzgc
=
devm_kzalloc
(
dev
,
sizeof
(
*
jzgc
),
GFP_KERNEL
);
if
(
!
jzgc
)
return
-
ENOMEM
;
jzgc
->
jzpc
=
jzpc
;
jzgc
->
reg_base
=
bank
*
0x100
;
jzgc
->
gc
.
label
=
devm_kasprintf
(
dev
,
GFP_KERNEL
,
"GPIO%c"
,
'A'
+
bank
);
if
(
!
jzgc
->
gc
.
label
)
return
-
ENOMEM
;
/* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
* ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
* <linux/gpio/consumer.h> INSTEAD.
*/
jzgc
->
gc
.
base
=
bank
*
32
;
jzgc
->
gc
.
ngpio
=
32
;
jzgc
->
gc
.
parent
=
dev
;
jzgc
->
gc
.
of_node
=
node
;
jzgc
->
gc
.
owner
=
THIS_MODULE
;
jzgc
->
gc
.
set
=
ingenic_gpio_set
;
jzgc
->
gc
.
get
=
ingenic_gpio_get
;
jzgc
->
gc
.
direction_input
=
ingenic_gpio_direction_input
;
jzgc
->
gc
.
direction_output
=
ingenic_gpio_direction_output
;
jzgc
->
gc
.
get_direction
=
ingenic_gpio_get_direction
;
if
(
of_property_read_bool
(
node
,
"gpio-ranges"
))
{
jzgc
->
gc
.
request
=
gpiochip_generic_request
;
jzgc
->
gc
.
free
=
gpiochip_generic_free
;
}
err
=
devm_gpiochip_add_data
(
dev
,
&
jzgc
->
gc
,
jzgc
);
if
(
err
)
return
err
;
jzgc
->
irq
=
irq_of_parse_and_map
(
node
,
0
);
if
(
!
jzgc
->
irq
)
return
-
EINVAL
;
jzgc
->
irq_chip
.
name
=
jzgc
->
gc
.
label
;
jzgc
->
irq_chip
.
irq_enable
=
ingenic_gpio_irq_enable
;
jzgc
->
irq_chip
.
irq_disable
=
ingenic_gpio_irq_disable
;
jzgc
->
irq_chip
.
irq_unmask
=
ingenic_gpio_irq_unmask
;
jzgc
->
irq_chip
.
irq_mask
=
ingenic_gpio_irq_mask
;
jzgc
->
irq_chip
.
irq_ack
=
ingenic_gpio_irq_ack
;
jzgc
->
irq_chip
.
irq_set_type
=
ingenic_gpio_irq_set_type
;
jzgc
->
irq_chip
.
irq_set_wake
=
ingenic_gpio_irq_set_wake
;
jzgc
->
irq_chip
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
;
err
=
gpiochip_irqchip_add
(
&
jzgc
->
gc
,
&
jzgc
->
irq_chip
,
0
,
handle_level_irq
,
IRQ_TYPE_NONE
);
if
(
err
)
return
err
;
gpiochip_set_chained_irqchip
(
&
jzgc
->
gc
,
&
jzgc
->
irq_chip
,
jzgc
->
irq
,
ingenic_gpio_irq_handler
);
return
0
;
}
static
int
__init
ingenic_pinctrl_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
ingenic_pinctrl
*
jzpc
;
...
...
@@ -727,6 +1158,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
const
struct
of_device_id
*
of_id
=
of_match_device
(
ingenic_pinctrl_of_match
,
dev
);
const
struct
ingenic_chip_info
*
chip_info
;
struct
device_node
*
node
;
unsigned
int
i
;
int
err
;
...
...
@@ -755,6 +1187,8 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
if
(
jzpc
->
version
>=
ID_JZ4770
)
chip_info
=
&
jz4770_chip_info
;
else
if
(
jzpc
->
version
>=
ID_JZ4725B
)
chip_info
=
&
jz4725b_chip_info
;
else
chip_info
=
&
jz4740_chip_info
;
jzpc
->
info
=
chip_info
;
...
...
@@ -815,11 +1249,11 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
dev_set_drvdata
(
dev
,
jzpc
->
map
);
if
(
dev
->
of_
node
)
{
err
=
of_platform_populate
(
dev
->
of_node
,
NULL
,
NULL
,
dev
);
if
(
err
)
{
dev_err
(
dev
,
"Failed to probe GPIO devices
\n
"
);
return
err
;
for_each_child_of_node
(
dev
->
of_node
,
node
)
{
if
(
of_match_node
(
ingenic_gpio_of_match
,
node
))
{
err
=
ingenic_gpio_probe
(
jzpc
,
node
);
if
(
err
)
return
err
;
}
}
...
...
@@ -828,6 +1262,7 @@ static int ingenic_pinctrl_probe(struct platform_device *pdev)
static
const
struct
platform_device_id
ingenic_pinctrl_ids
[]
=
{
{
"jz4740-pinctrl"
,
ID_JZ4740
},
{
"jz4725b-pinctrl"
,
ID_JZ4725B
},
{
"jz4770-pinctrl"
,
ID_JZ4770
},
{
"jz4780-pinctrl"
,
ID_JZ4780
},
{},
...
...
@@ -837,14 +1272,13 @@ static struct platform_driver ingenic_pinctrl_driver = {
.
driver
=
{
.
name
=
"pinctrl-ingenic"
,
.
of_match_table
=
of_match_ptr
(
ingenic_pinctrl_of_match
),
.
suppress_bind_attrs
=
true
,
},
.
probe
=
ingenic_pinctrl_probe
,
.
id_table
=
ingenic_pinctrl_ids
,
};
static
int
__init
ingenic_pinctrl_drv_register
(
void
)
{
return
platform_driver_register
(
&
ingenic_pinctrl_driver
);
return
platform_driver_probe
(
&
ingenic_pinctrl_driver
,
ingenic_pinctrl_probe
);
}
postcore
_initcall
(
ingenic_pinctrl_drv_register
);
subsys
_initcall
(
ingenic_pinctrl_drv_register
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录