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
nexedi
linux
Commits
5624bf96
Commit
5624bf96
authored
Aug 29, 2018
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-ingenic' into devel
parents
94f4e54c
28d6eeb4
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
487 additions
and
470 deletions
+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
No files found.
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
deleted
100644 → 0
View file @
94f4e54c
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
View file @
5624bf96
...
...
@@ -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
View file @
5624bf96
...
...
@@ -267,17 +267,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
View file @
5624bf96
...
...
@@ -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
deleted
100644 → 0
View file @
94f4e54c
/*
* 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
View file @
5624bf96
...
...
@@ -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
View file @
5624bf96
...
...
@@ -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
);
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