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
64df5ea9
Commit
64df5ea9
authored
Mar 07, 2024
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'ib-nomadik-gpio' into devel
parents
52279c3d
a0c807b5
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1104 additions
and
863 deletions
+1104
-863
Documentation/devicetree/bindings/gpio/gpio-nmk.txt
Documentation/devicetree/bindings/gpio/gpio-nmk.txt
+0
-31
Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml
Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml
+95
-0
MAINTAINERS
MAINTAINERS
+2
-0
drivers/gpio/Kconfig
drivers/gpio/Kconfig
+12
-0
drivers/gpio/Makefile
drivers/gpio/Makefile
+1
-0
drivers/gpio/gpio-nomadik.c
drivers/gpio/gpio-nomadik.c
+734
-0
drivers/pinctrl/nomadik/Kconfig
drivers/pinctrl/nomadik/Kconfig
+4
-4
drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c
drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c
+2
-1
drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
+2
-1
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
+141
-814
include/linux/gpio/gpio-nomadik.h
include/linux/gpio/gpio-nomadik.h
+111
-12
No files found.
Documentation/devicetree/bindings/gpio/gpio-nmk.txt
deleted
100644 → 0
View file @
52279c3d
Nomadik GPIO controller
Required properties:
- compatible : Should be "st,nomadik-gpio".
- reg : Physical base address and length of the controller's registers.
- interrupts : The interrupt outputs from the controller.
- #gpio-cells : Should be two:
The first cell is the pin number.
The second cell is used to specify optional parameters:
- bits[3:0] trigger type and level flags:
1 = low-to-high edge triggered.
2 = high-to-low edge triggered.
4 = active high level-sensitive.
8 = active low level-sensitive.
- gpio-controller : Marks the device node as a GPIO controller.
- interrupt-controller : Marks the device node as an interrupt controller.
- gpio-bank : Specifies which bank a controller owns.
- st,supports-sleepmode : Specifies whether controller can sleep or not
Example:
gpio1: gpio@8012e080 {
compatible = "st,nomadik-gpio";
reg = <0x8012e080 0x80>;
interrupts = <0 120 0x4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
st,supports-sleepmode;
gpio-bank = <1>;
};
Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml
0 → 100644
View file @
64df5ea9
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/gpio/st,nomadik-gpio.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Nomadik GPIO controller
description
:
The Nomadik GPIO driver handles Nomadik SoC GPIO blocks. This block has also
been called ST STA2X11. On the Nomadik platform, this driver is intertwined
with pinctrl-nomadik.
maintainers
:
-
Linus Walleij <linus.walleij@linaro.org>
properties
:
$nodename
:
pattern
:
"
^gpio@[0-9a-f]+$"
compatible
:
enum
:
-
st,nomadik-gpio
-
mobileye,eyeq5-gpio
reg
:
maxItems
:
1
interrupts
:
maxItems
:
1
"
#gpio-cells"
:
const
:
2
gpio-controller
:
true
interrupt-controller
:
true
"
#interrupt-cells"
:
const
:
2
gpio-bank
:
description
:
System-wide GPIO bank index.
$ref
:
/schemas/types.yaml#/definitions/uint32
st,supports-sleepmode
:
description
:
Whether the controller can sleep or not.
$ref
:
/schemas/types.yaml#/definitions/flag
clocks
:
maxItems
:
1
gpio-ranges
:
maxItems
:
1
ngpios
:
minimum
:
0
maximum
:
32
resets
:
maxItems
:
1
required
:
-
compatible
-
reg
-
interrupts
-
"
#gpio-cells"
-
gpio-controller
-
interrupt-controller
-
gpio-bank
unevaluatedProperties
:
false
allOf
:
-
if
:
properties
:
compatible
:
contains
:
const
:
mobileye,eyeq5-gpio
then
:
properties
:
st,supports-sleepmode
:
false
examples
:
-
|
gpio@8012e080 {
compatible = "st,nomadik-gpio";
reg = <0x8012e080 0x80>;
interrupts = <0 120 0x4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
st,supports-sleepmode;
gpio-bank = <1>;
};
MAINTAINERS
View file @
64df5ea9
...
...
@@ -2465,6 +2465,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
F: Documentation/devicetree/bindings/arm/ste-*
F: Documentation/devicetree/bindings/arm/ux500.yaml
F: Documentation/devicetree/bindings/arm/ux500/
F: Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml
F: Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
F: arch/arm/boot/dts/st/ste-*
F: arch/arm/mach-nomadik/
...
...
@@ -2473,6 +2474,7 @@ F: drivers/clk/clk-nomadik.c
F: drivers/clocksource/clksrc-dbx500-prcmu.c
F: drivers/dma/ste_dma40*
F: drivers/pmdomain/st/ste-ux500-pm-domain.c
F: drivers/gpio/gpio-nomadik.c
F: drivers/hwspinlock/u8500_hsem.c
F: drivers/i2c/busses/i2c-nomadik.c
F: drivers/iio/adc/ab8500-gpadc.c
...
...
drivers/gpio/Kconfig
View file @
64df5ea9
...
...
@@ -478,6 +478,18 @@ config GPIO_MXS
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
config GPIO_NOMADIK
bool "Nomadik GPIO driver"
depends on ARCH_U8500 || ARCH_NOMADIK || MACH_EYEQ5 || COMPILE_TEST
select GPIOLIB_IRQCHIP
help
Say yes here to support the Nomadik SoC GPIO block. This block is also
used by the Mobileye EyeQ5 SoC.
It handles up to 32 GPIOs per bank, that can all be interrupt sources.
It is deeply interconnected with the associated pinctrl driver as GPIO
registers handle muxing ("alternate functions") as well.
config GPIO_NPCM_SGPIO
bool "Nuvoton SGPIO support"
depends on ARCH_NPCM || COMPILE_TEST
...
...
drivers/gpio/Makefile
View file @
64df5ea9
...
...
@@ -116,6 +116,7 @@ obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o
obj-$(CONFIG_GPIO_MVEBU)
+=
gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC)
+=
gpio-mxc.o
obj-$(CONFIG_GPIO_MXS)
+=
gpio-mxs.o
obj-$(CONFIG_GPIO_NOMADIK)
+=
gpio-nomadik.o
obj-$(CONFIG_GPIO_NPCM_SGPIO)
+=
gpio-npcm-sgpio.o
obj-$(CONFIG_GPIO_OCTEON)
+=
gpio-octeon.o
obj-$(CONFIG_GPIO_OMAP)
+=
gpio-omap.o
...
...
drivers/gpio/gpio-nomadik.c
0 → 100644
View file @
64df5ea9
// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driver for the IP block found in the Nomadik SoC; it is an AMBA device,
* managing 32 pins with alternate functions. It can also handle the STA2X11
* block from ST.
*
* The GPIO chips are shared with pinctrl-nomadik if used; it needs access for
* pinmuxing functionality and others.
*
* This driver also handles the mobileye,eyeq5-gpio compatible. It is an STA2X11
* but with only data, direction and interrupts register active. We want to
* avoid touching SLPM, RWIMSC, FWIMSC, AFSLA and AFSLB registers; that is,
* wake and alternate function registers. It is NOT compatible with
* pinctrl-nomadik.
*
* Copyright (C) 2008,2009 STMicroelectronics
* Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
* Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
* Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/reset.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/gpio/gpio-nomadik.h>
#ifndef CONFIG_PINCTRL_NOMADIK
static
DEFINE_SPINLOCK
(
nmk_gpio_slpm_lock
);
#endif
void
__nmk_gpio_set_slpm
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
,
enum
nmk_gpio_slpm
mode
)
{
u32
slpm
;
/* We should NOT have been called. */
if
(
WARN_ON
(
nmk_chip
->
is_mobileye_soc
))
return
;
slpm
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_SLPC
);
if
(
mode
==
NMK_GPIO_SLPM_NOCHANGE
)
slpm
|=
BIT
(
offset
);
else
slpm
&=
~
BIT
(
offset
);
writel
(
slpm
,
nmk_chip
->
addr
+
NMK_GPIO_SLPC
);
}
static
void
__nmk_gpio_set_output
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
,
int
val
)
{
if
(
val
)
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DATS
);
else
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DATC
);
}
void
__nmk_gpio_make_output
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
,
int
val
)
{
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DIRS
);
__nmk_gpio_set_output
(
nmk_chip
,
offset
,
val
);
}
/* IRQ functions */
static
void
nmk_gpio_irq_ack
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
clk_enable
(
nmk_chip
->
clk
);
writel
(
BIT
(
d
->
hwirq
),
nmk_chip
->
addr
+
NMK_GPIO_IC
);
clk_disable
(
nmk_chip
->
clk
);
}
enum
nmk_gpio_irq_type
{
NORMAL
,
WAKE
,
};
static
void
__nmk_gpio_irq_modify
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
,
enum
nmk_gpio_irq_type
which
,
bool
enable
)
{
u32
*
rimscval
;
u32
*
fimscval
;
u32
rimscreg
;
u32
fimscreg
;
if
(
which
==
NORMAL
)
{
rimscreg
=
NMK_GPIO_RIMSC
;
fimscreg
=
NMK_GPIO_FIMSC
;
rimscval
=
&
nmk_chip
->
rimsc
;
fimscval
=
&
nmk_chip
->
fimsc
;
}
else
{
/* We should NOT have been called. */
if
(
WARN_ON
(
nmk_chip
->
is_mobileye_soc
))
return
;
rimscreg
=
NMK_GPIO_RWIMSC
;
fimscreg
=
NMK_GPIO_FWIMSC
;
rimscval
=
&
nmk_chip
->
rwimsc
;
fimscval
=
&
nmk_chip
->
fwimsc
;
}
/* we must individually set/clear the two edges */
if
(
nmk_chip
->
edge_rising
&
BIT
(
offset
))
{
if
(
enable
)
*
rimscval
|=
BIT
(
offset
);
else
*
rimscval
&=
~
BIT
(
offset
);
writel
(
*
rimscval
,
nmk_chip
->
addr
+
rimscreg
);
}
if
(
nmk_chip
->
edge_falling
&
BIT
(
offset
))
{
if
(
enable
)
*
fimscval
|=
BIT
(
offset
);
else
*
fimscval
&=
~
BIT
(
offset
);
writel
(
*
fimscval
,
nmk_chip
->
addr
+
fimscreg
);
}
}
static
void
__nmk_gpio_set_wake
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
,
bool
on
)
{
/* We should NOT have been called. */
if
(
WARN_ON
(
nmk_chip
->
is_mobileye_soc
))
return
;
/*
* Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is
* disabled, since setting SLPM to 1 increases power consumption, and
* wakeup is anyhow controlled by the RIMSC and FIMSC registers.
*/
if
(
nmk_chip
->
sleepmode
&&
on
)
{
__nmk_gpio_set_slpm
(
nmk_chip
,
offset
,
NMK_GPIO_SLPM_WAKEUP_ENABLE
);
}
__nmk_gpio_irq_modify
(
nmk_chip
,
offset
,
WAKE
,
on
);
}
static
void
nmk_gpio_irq_maskunmask
(
struct
nmk_gpio_chip
*
nmk_chip
,
struct
irq_data
*
d
,
bool
enable
)
{
unsigned
long
flags
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_gpio_slpm_lock
,
flags
);
spin_lock
(
&
nmk_chip
->
lock
);
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
enable
);
if
(
!
nmk_chip
->
is_mobileye_soc
&&
!
(
nmk_chip
->
real_wake
&
BIT
(
d
->
hwirq
)))
__nmk_gpio_set_wake
(
nmk_chip
,
d
->
hwirq
,
enable
);
spin_unlock
(
&
nmk_chip
->
lock
);
spin_unlock_irqrestore
(
&
nmk_gpio_slpm_lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
}
static
void
nmk_gpio_irq_mask
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
nmk_gpio_irq_maskunmask
(
nmk_chip
,
d
,
false
);
gpiochip_disable_irq
(
gc
,
irqd_to_hwirq
(
d
));
}
static
void
nmk_gpio_irq_unmask
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
gpiochip_enable_irq
(
gc
,
irqd_to_hwirq
(
d
));
nmk_gpio_irq_maskunmask
(
nmk_chip
,
d
,
true
);
}
static
int
nmk_gpio_irq_set_wake
(
struct
irq_data
*
d
,
unsigned
int
on
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
unsigned
long
flags
;
/* Handler is registered in all cases. */
if
(
nmk_chip
->
is_mobileye_soc
)
return
-
ENXIO
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_gpio_slpm_lock
,
flags
);
spin_lock
(
&
nmk_chip
->
lock
);
if
(
irqd_irq_disabled
(
d
))
__nmk_gpio_set_wake
(
nmk_chip
,
d
->
hwirq
,
on
);
if
(
on
)
nmk_chip
->
real_wake
|=
BIT
(
d
->
hwirq
);
else
nmk_chip
->
real_wake
&=
~
BIT
(
d
->
hwirq
);
spin_unlock
(
&
nmk_chip
->
lock
);
spin_unlock_irqrestore
(
&
nmk_gpio_slpm_lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
int
nmk_gpio_irq_set_type
(
struct
irq_data
*
d
,
unsigned
int
type
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
bool
enabled
=
!
irqd_irq_disabled
(
d
);
bool
wake
=
irqd_is_wakeup_set
(
d
);
unsigned
long
flags
;
if
(
type
&
IRQ_TYPE_LEVEL_HIGH
)
return
-
EINVAL
;
if
(
type
&
IRQ_TYPE_LEVEL_LOW
)
return
-
EINVAL
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_chip
->
lock
,
flags
);
if
(
enabled
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
false
);
if
(
!
nmk_chip
->
is_mobileye_soc
&&
(
enabled
||
wake
))
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
WAKE
,
false
);
nmk_chip
->
edge_rising
&=
~
BIT
(
d
->
hwirq
);
if
(
type
&
IRQ_TYPE_EDGE_RISING
)
nmk_chip
->
edge_rising
|=
BIT
(
d
->
hwirq
);
nmk_chip
->
edge_falling
&=
~
BIT
(
d
->
hwirq
);
if
(
type
&
IRQ_TYPE_EDGE_FALLING
)
nmk_chip
->
edge_falling
|=
BIT
(
d
->
hwirq
);
if
(
enabled
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
true
);
if
(
!
nmk_chip
->
is_mobileye_soc
&&
(
enabled
||
wake
))
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
WAKE
,
true
);
spin_unlock_irqrestore
(
&
nmk_chip
->
lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
unsigned
int
nmk_gpio_irq_startup
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
clk_enable
(
nmk_chip
->
clk
);
nmk_gpio_irq_unmask
(
d
);
return
0
;
}
static
void
nmk_gpio_irq_shutdown
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
nmk_gpio_irq_mask
(
d
);
clk_disable
(
nmk_chip
->
clk
);
}
static
irqreturn_t
nmk_gpio_irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
dev_id
;
struct
gpio_chip
*
chip
=
&
nmk_chip
->
chip
;
unsigned
long
mask
=
GENMASK
(
chip
->
ngpio
-
1
,
0
);
unsigned
long
status
;
int
bit
;
clk_enable
(
nmk_chip
->
clk
);
status
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_IS
);
/* Ensure we cannot leave pending bits; this should never occur. */
if
(
unlikely
(
status
&
~
mask
))
writel
(
status
&
~
mask
,
nmk_chip
->
addr
+
NMK_GPIO_IC
);
clk_disable
(
nmk_chip
->
clk
);
for_each_set_bit
(
bit
,
&
status
,
chip
->
ngpio
)
generic_handle_domain_irq_safe
(
chip
->
irq
.
domain
,
bit
);
return
IRQ_RETVAL
((
status
&
mask
)
!=
0
);
}
/* I/O Functions */
static
int
nmk_gpio_get_dir
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
dir
;
clk_enable
(
nmk_chip
->
clk
);
dir
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DIR
)
&
BIT
(
offset
);
clk_disable
(
nmk_chip
->
clk
);
if
(
dir
)
return
GPIO_LINE_DIRECTION_OUT
;
return
GPIO_LINE_DIRECTION_IN
;
}
static
int
nmk_gpio_make_input
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DIRC
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
int
nmk_gpio_get_input
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
value
;
clk_enable
(
nmk_chip
->
clk
);
value
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DAT
)
&
BIT
(
offset
));
clk_disable
(
nmk_chip
->
clk
);
return
value
;
}
static
void
nmk_gpio_set_output
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
int
val
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
__nmk_gpio_set_output
(
nmk_chip
,
offset
,
val
);
clk_disable
(
nmk_chip
->
clk
);
}
static
int
nmk_gpio_make_output
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
int
val
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
__nmk_gpio_make_output
(
nmk_chip
,
offset
,
val
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
#ifdef CONFIG_DEBUG_FS
static
int
nmk_gpio_get_mode
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
)
{
u32
afunc
,
bfunc
;
/* We don't support modes. */
if
(
nmk_chip
->
is_mobileye_soc
)
return
NMK_GPIO_ALT_GPIO
;
clk_enable
(
nmk_chip
->
clk
);
afunc
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_AFSLA
)
&
BIT
(
offset
);
bfunc
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_AFSLB
)
&
BIT
(
offset
);
clk_disable
(
nmk_chip
->
clk
);
return
(
afunc
?
NMK_GPIO_ALT_A
:
0
)
|
(
bfunc
?
NMK_GPIO_ALT_B
:
0
);
}
void
nmk_gpio_dbg_show_one
(
struct
seq_file
*
s
,
struct
pinctrl_dev
*
pctldev
,
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
unsigned
int
gpio
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
mode
;
bool
is_out
;
bool
data_out
;
bool
pull
;
static
const
char
*
const
modes
[]
=
{
[
NMK_GPIO_ALT_GPIO
]
=
"gpio"
,
[
NMK_GPIO_ALT_A
]
=
"altA"
,
[
NMK_GPIO_ALT_B
]
=
"altB"
,
[
NMK_GPIO_ALT_C
]
=
"altC"
,
[
NMK_GPIO_ALT_C
+
1
]
=
"altC1"
,
[
NMK_GPIO_ALT_C
+
2
]
=
"altC2"
,
[
NMK_GPIO_ALT_C
+
3
]
=
"altC3"
,
[
NMK_GPIO_ALT_C
+
4
]
=
"altC4"
,
};
char
*
label
=
gpiochip_dup_line_label
(
chip
,
offset
);
if
(
IS_ERR
(
label
))
return
;
clk_enable
(
nmk_chip
->
clk
);
is_out
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DIR
)
&
BIT
(
offset
));
pull
=
!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_PDIS
)
&
BIT
(
offset
));
data_out
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DAT
)
&
BIT
(
offset
));
mode
=
nmk_gpio_get_mode
(
nmk_chip
,
offset
);
#ifdef CONFIG_PINCTRL_NOMADIK
if
(
mode
==
NMK_GPIO_ALT_C
&&
pctldev
)
mode
=
nmk_prcm_gpiocr_get_mode
(
pctldev
,
gpio
);
#endif
if
(
is_out
)
{
seq_printf
(
s
,
" gpio-%-3d (%-20.20s) out %s %s"
,
gpio
,
label
?:
"(none)"
,
data_out
?
"hi"
:
"lo"
,
(
mode
<
0
)
?
"unknown"
:
modes
[
mode
]);
}
else
{
int
irq
=
chip
->
to_irq
(
chip
,
offset
);
const
int
pullidx
=
pull
?
1
:
0
;
int
val
;
static
const
char
*
const
pulls
[]
=
{
"none "
,
"pull enabled"
,
};
seq_printf
(
s
,
" gpio-%-3d (%-20.20s) in %s %s"
,
gpio
,
label
?:
"(none)"
,
pulls
[
pullidx
],
(
mode
<
0
)
?
"unknown"
:
modes
[
mode
]);
val
=
nmk_gpio_get_input
(
chip
,
offset
);
seq_printf
(
s
,
" VAL %d"
,
val
);
/*
* This races with request_irq(), set_irq_type(),
* and set_irq_wake() ... but those are "rare".
*/
if
(
irq
>
0
&&
irq_has_action
(
irq
))
{
char
*
trigger
;
bool
wake
;
if
(
nmk_chip
->
edge_rising
&
BIT
(
offset
))
trigger
=
"edge-rising"
;
else
if
(
nmk_chip
->
edge_falling
&
BIT
(
offset
))
trigger
=
"edge-falling"
;
else
trigger
=
"edge-undefined"
;
wake
=
!!
(
nmk_chip
->
real_wake
&
BIT
(
offset
));
seq_printf
(
s
,
" irq-%d %s%s"
,
irq
,
trigger
,
wake
?
" wakeup"
:
""
);
}
}
clk_disable
(
nmk_chip
->
clk
);
}
static
void
nmk_gpio_dbg_show
(
struct
seq_file
*
s
,
struct
gpio_chip
*
chip
)
{
unsigned
int
i
,
gpio
=
chip
->
base
;
for
(
i
=
0
;
i
<
chip
->
ngpio
;
i
++
,
gpio
++
)
{
nmk_gpio_dbg_show_one
(
s
,
NULL
,
chip
,
i
,
gpio
);
seq_puts
(
s
,
"
\n
"
);
}
}
#else
static
inline
void
nmk_gpio_dbg_show_one
(
struct
seq_file
*
s
,
struct
pinctrl_dev
*
pctldev
,
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
unsigned
int
gpio
)
{
}
#define nmk_gpio_dbg_show NULL
#endif
/*
* We will allocate memory for the state container using devm* allocators
* binding to the first device reaching this point, it doesn't matter if
* it is the pin controller or GPIO driver. However we need to use the right
* platform device when looking up resources so pay attention to pdev.
*/
struct
nmk_gpio_chip
*
nmk_gpio_populate_chip
(
struct
fwnode_handle
*
fwnode
,
struct
platform_device
*
pdev
)
{
struct
nmk_gpio_chip
*
nmk_chip
;
struct
platform_device
*
gpio_pdev
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
reset_control
*
reset
;
struct
device
*
gpio_dev
;
struct
gpio_chip
*
chip
;
struct
resource
*
res
;
struct
clk
*
clk
;
void
__iomem
*
base
;
u32
id
,
ngpio
;
int
ret
;
gpio_dev
=
bus_find_device_by_fwnode
(
&
platform_bus_type
,
fwnode
);
if
(
!
gpio_dev
)
{
dev_err
(
dev
,
"populate
\"
%pfwP
\"
: device not found
\n
"
,
fwnode
);
return
ERR_PTR
(
-
ENODEV
);
}
gpio_pdev
=
to_platform_device
(
gpio_dev
);
if
(
device_property_read_u32
(
gpio_dev
,
"gpio-bank"
,
&
id
))
{
dev_err
(
dev
,
"populate: gpio-bank property not found
\n
"
);
platform_device_put
(
gpio_pdev
);
return
ERR_PTR
(
-
EINVAL
);
}
#ifdef CONFIG_PINCTRL_NOMADIK
/* Already populated? */
nmk_chip
=
nmk_gpio_chips
[
id
];
if
(
nmk_chip
)
{
platform_device_put
(
gpio_pdev
);
return
nmk_chip
;
}
#endif
nmk_chip
=
devm_kzalloc
(
dev
,
sizeof
(
*
nmk_chip
),
GFP_KERNEL
);
if
(
!
nmk_chip
)
{
platform_device_put
(
gpio_pdev
);
return
ERR_PTR
(
-
ENOMEM
);
}
if
(
device_property_read_u32
(
gpio_dev
,
"ngpios"
,
&
ngpio
))
{
ngpio
=
NMK_GPIO_PER_CHIP
;
dev_dbg
(
dev
,
"populate: using default ngpio (%u)
\n
"
,
ngpio
);
}
nmk_chip
->
is_mobileye_soc
=
device_is_compatible
(
gpio_dev
,
"mobileye,eyeq5-gpio"
);
nmk_chip
->
bank
=
id
;
chip
=
&
nmk_chip
->
chip
;
chip
->
base
=
-
1
;
chip
->
ngpio
=
ngpio
;
chip
->
label
=
dev_name
(
gpio_dev
);
chip
->
parent
=
gpio_dev
;
/* NOTE: different devices! No devm_platform_ioremap_resource() here! */
res
=
platform_get_resource
(
gpio_pdev
,
IORESOURCE_MEM
,
0
);
base
=
devm_ioremap_resource
(
dev
,
res
);
if
(
IS_ERR
(
base
))
{
platform_device_put
(
gpio_pdev
);
return
ERR_CAST
(
base
);
}
nmk_chip
->
addr
=
base
;
/* NOTE: do not use devm_ here! */
clk
=
clk_get_optional
(
gpio_dev
,
NULL
);
if
(
IS_ERR
(
clk
))
{
platform_device_put
(
gpio_pdev
);
return
ERR_CAST
(
clk
);
}
clk_prepare
(
clk
);
nmk_chip
->
clk
=
clk
;
/* NOTE: do not use devm_ here! */
reset
=
reset_control_get_optional_shared
(
gpio_dev
,
NULL
);
if
(
IS_ERR
(
reset
))
{
clk_unprepare
(
clk
);
clk_put
(
clk
);
platform_device_put
(
gpio_pdev
);
dev_err
(
dev
,
"failed getting reset control: %pe
\n
"
,
reset
);
return
ERR_CAST
(
reset
);
}
/*
* Reset might be shared and asserts/deasserts calls are unbalanced. We
* only support sharing this reset with other gpio-nomadik devices that
* use this reset to ensure deassertion at probe.
*/
ret
=
reset_control_deassert
(
reset
);
if
(
ret
)
{
reset_control_put
(
reset
);
clk_unprepare
(
clk
);
clk_put
(
clk
);
platform_device_put
(
gpio_pdev
);
dev_err
(
dev
,
"failed reset deassert: %d
\n
"
,
ret
);
return
ERR_PTR
(
ret
);
}
#ifdef CONFIG_PINCTRL_NOMADIK
BUG_ON
(
nmk_chip
->
bank
>=
ARRAY_SIZE
(
nmk_gpio_chips
));
nmk_gpio_chips
[
id
]
=
nmk_chip
;
#endif
return
nmk_chip
;
}
static
void
nmk_gpio_irq_print_chip
(
struct
irq_data
*
d
,
struct
seq_file
*
p
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
seq_printf
(
p
,
"nmk%u-%u-%u"
,
nmk_chip
->
bank
,
gc
->
base
,
gc
->
base
+
gc
->
ngpio
-
1
);
}
static
const
struct
irq_chip
nmk_irq_chip
=
{
.
irq_ack
=
nmk_gpio_irq_ack
,
.
irq_mask
=
nmk_gpio_irq_mask
,
.
irq_unmask
=
nmk_gpio_irq_unmask
,
.
irq_set_type
=
nmk_gpio_irq_set_type
,
.
irq_set_wake
=
nmk_gpio_irq_set_wake
,
.
irq_startup
=
nmk_gpio_irq_startup
,
.
irq_shutdown
=
nmk_gpio_irq_shutdown
,
.
irq_print_chip
=
nmk_gpio_irq_print_chip
,
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
|
IRQCHIP_IMMUTABLE
,
GPIOCHIP_IRQ_RESOURCE_HELPERS
,
};
static
int
nmk_gpio_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
nmk_gpio_chip
*
nmk_chip
;
struct
gpio_irq_chip
*
girq
;
bool
supports_sleepmode
;
struct
gpio_chip
*
chip
;
int
irq
;
int
ret
;
nmk_chip
=
nmk_gpio_populate_chip
(
dev_fwnode
(
dev
),
pdev
);
if
(
IS_ERR
(
nmk_chip
))
{
dev_err
(
dev
,
"could not populate nmk chip struct
\n
"
);
return
PTR_ERR
(
nmk_chip
);
}
supports_sleepmode
=
device_property_read_bool
(
dev
,
"st,supports-sleepmode"
);
/* Correct platform device ID */
pdev
->
id
=
nmk_chip
->
bank
;
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
return
irq
;
/*
* The virt address in nmk_chip->addr is in the nomadik register space,
* so we can simply convert the resource address, without remapping
*/
nmk_chip
->
sleepmode
=
supports_sleepmode
;
spin_lock_init
(
&
nmk_chip
->
lock
);
chip
=
&
nmk_chip
->
chip
;
chip
->
parent
=
dev
;
chip
->
request
=
gpiochip_generic_request
;
chip
->
free
=
gpiochip_generic_free
;
chip
->
get_direction
=
nmk_gpio_get_dir
;
chip
->
direction_input
=
nmk_gpio_make_input
;
chip
->
get
=
nmk_gpio_get_input
;
chip
->
direction_output
=
nmk_gpio_make_output
;
chip
->
set
=
nmk_gpio_set_output
;
chip
->
dbg_show
=
nmk_gpio_dbg_show
;
chip
->
can_sleep
=
false
;
chip
->
owner
=
THIS_MODULE
;
girq
=
&
chip
->
irq
;
gpio_irq_chip_set_chip
(
girq
,
&
nmk_irq_chip
);
girq
->
parent_handler
=
NULL
;
girq
->
num_parents
=
0
;
girq
->
parents
=
NULL
;
girq
->
default_type
=
IRQ_TYPE_NONE
;
girq
->
handler
=
handle_edge_irq
;
ret
=
devm_request_irq
(
dev
,
irq
,
nmk_gpio_irq_handler
,
IRQF_SHARED
,
dev_name
(
dev
),
nmk_chip
);
if
(
ret
)
{
dev_err
(
dev
,
"failed requesting IRQ
\n
"
);
return
ret
;
}
if
(
!
nmk_chip
->
is_mobileye_soc
)
{
clk_enable
(
nmk_chip
->
clk
);
nmk_chip
->
lowemi
=
readl_relaxed
(
nmk_chip
->
addr
+
NMK_GPIO_LOWEMI
);
clk_disable
(
nmk_chip
->
clk
);
}
ret
=
gpiochip_add_data
(
chip
,
nmk_chip
);
if
(
ret
)
return
ret
;
platform_set_drvdata
(
pdev
,
nmk_chip
);
dev_info
(
dev
,
"chip registered
\n
"
);
return
0
;
}
static
const
struct
of_device_id
nmk_gpio_match
[]
=
{
{
.
compatible
=
"st,nomadik-gpio"
,
},
{
.
compatible
=
"mobileye,eyeq5-gpio"
,
},
{}
};
static
struct
platform_driver
nmk_gpio_driver
=
{
.
driver
=
{
.
name
=
"nomadik-gpio"
,
.
of_match_table
=
nmk_gpio_match
,
.
suppress_bind_attrs
=
true
,
},
.
probe
=
nmk_gpio_probe
,
};
static
int
__init
nmk_gpio_init
(
void
)
{
return
platform_driver_register
(
&
nmk_gpio_driver
);
}
subsys_initcall
(
nmk_gpio_init
);
drivers/pinctrl/nomadik/Kconfig
View file @
64df5ea9
...
...
@@ -18,15 +18,15 @@ config PINCTRL_AB8505
endif
if (ARCH_U8500 || ARCH_NOMADIK)
if (ARCH_U8500 || ARCH_NOMADIK
|| COMPILE_TEST
)
config PINCTRL_NOMADIK
bool "Nomadik pin controller driver"
depends on OF
&& GPIOLIB
depends on OF
select PINMUX
select PINCONF
select
OF_GPIO
select GPIO
LIB_IRQCHIP
select
GPIOLIB
select GPIO
_NOMADIK
config PINCTRL_STN8815
bool "STN8815 pin controller driver"
...
...
drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c
View file @
64df5ea9
...
...
@@ -3,8 +3,9 @@
#include <linux/types.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/gpio/driver.h>
#include
"pinctrl-nomadik.h"
#include
<linux/gpio/gpio-nomadik.h>
/* All the pins that can be used for GPIO and some other functions */
#define _GPIO(offset) (offset)
...
...
drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
View file @
64df5ea9
...
...
@@ -3,8 +3,9 @@
#include <linux/types.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/gpio/driver.h>
#include
"pinctrl-nomadik.h"
#include
<linux/gpio/gpio-nomadik.h>
/* All the pins that can be used for GPIO and some other functions */
#define _GPIO(offset) (offset)
...
...
drivers/pinctrl/nomadik/pinctrl-nomadik.c
View file @
64df5ea9
// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic GPIO driver for logic cells found in the Nomadik SoC
* Pinmux & pinconf driver for the IP block found in the Nomadik SoC. This
* depends on gpio-nomadik and some handling is intertwined; see nmk_gpio_chips
* which is used by this driver to access the GPIO banks array.
*
* Copyright (C) 2008,2009 STMicroelectronics
* Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
* Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
* Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
...
...
@@ -25,6 +28,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
/* Since we request GPIOs from ourself */
#include <linux/pinctrl/consumer.h>
...
...
@@ -36,15 +40,7 @@
#include "../core.h"
#include "../pinctrl-utils.h"
#include "pinctrl-nomadik.h"
/*
* The GPIO module in the Nomadik family of Systems-on-Chip is an
* AMBA device, managing 32 pins and alternate functions. The logic block
* is currently used in the Nomadik and ux500.
*
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
#include <linux/gpio/gpio-nomadik.h>
/*
* pin configurations are represented by 32-bit integers:
...
...
@@ -76,8 +72,6 @@
* PIN_CFG - default config with alternate function
*/
typedef
unsigned
long
pin_cfg_t
;
#define PIN_NUM_MASK 0x1ff
#define PIN_NUM(x) ((x) & PIN_NUM_MASK)
...
...
@@ -172,7 +166,6 @@ typedef unsigned long pin_cfg_t;
#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT)
#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT)
/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */
#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN)
#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP)
...
...
@@ -200,75 +193,6 @@ typedef unsigned long pin_cfg_t;
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val))
/*
* "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving
* the "gpio" namespace for generic and cross-machine functions
*/
#define GPIO_BLOCK_SHIFT 5
#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT)
#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP)
/* Register in the logic block */
#define NMK_GPIO_DAT 0x00
#define NMK_GPIO_DATS 0x04
#define NMK_GPIO_DATC 0x08
#define NMK_GPIO_PDIS 0x0c
#define NMK_GPIO_DIR 0x10
#define NMK_GPIO_DIRS 0x14
#define NMK_GPIO_DIRC 0x18
#define NMK_GPIO_SLPC 0x1c
#define NMK_GPIO_AFSLA 0x20
#define NMK_GPIO_AFSLB 0x24
#define NMK_GPIO_LOWEMI 0x28
#define NMK_GPIO_RIMSC 0x40
#define NMK_GPIO_FIMSC 0x44
#define NMK_GPIO_IS 0x48
#define NMK_GPIO_IC 0x4c
#define NMK_GPIO_RWIMSC 0x50
#define NMK_GPIO_FWIMSC 0x54
#define NMK_GPIO_WKS 0x58
/* These appear in DB8540 and later ASICs */
#define NMK_GPIO_EDGELEVEL 0x5C
#define NMK_GPIO_LEVEL 0x60
/* Pull up/down values */
enum
nmk_gpio_pull
{
NMK_GPIO_PULL_NONE
,
NMK_GPIO_PULL_UP
,
NMK_GPIO_PULL_DOWN
,
};
/* Sleep mode */
enum
nmk_gpio_slpm
{
NMK_GPIO_SLPM_INPUT
,
NMK_GPIO_SLPM_WAKEUP_ENABLE
=
NMK_GPIO_SLPM_INPUT
,
NMK_GPIO_SLPM_NOCHANGE
,
NMK_GPIO_SLPM_WAKEUP_DISABLE
=
NMK_GPIO_SLPM_NOCHANGE
,
};
struct
nmk_gpio_chip
{
struct
gpio_chip
chip
;
void
__iomem
*
addr
;
struct
clk
*
clk
;
unsigned
int
bank
;
void
(
*
set_ioforce
)(
bool
enable
);
spinlock_t
lock
;
bool
sleepmode
;
/* Keep track of configured edges */
u32
edge_rising
;
u32
edge_falling
;
u32
real_wake
;
u32
rwimsc
;
u32
fwimsc
;
u32
rimsc
;
u32
fimsc
;
u32
pull_up
;
u32
lowemi
;
};
/**
* struct nmk_pinctrl - state container for the Nomadik pin controller
* @dev: containing device pointer
...
...
@@ -283,14 +207,13 @@ struct nmk_pinctrl {
void
__iomem
*
prcm_base
;
};
static
struct
nmk_gpio_chip
*
nmk_gpio_chips
[
NMK_MAX_BANKS
];
/* See nmk_gpio_populate_chip() that fills this array. */
struct
nmk_gpio_chip
*
nmk_gpio_chips
[
NMK_MAX_BANKS
];
static
DEFINE_SPINLOCK
(
nmk_gpio_slpm_lock
);
#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips)
DEFINE_SPINLOCK
(
nmk_gpio_slpm_lock
);
static
void
__nmk_gpio_set_mode
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
int
gpio_mode
)
unsigned
int
offset
,
int
gpio_mode
)
{
u32
afunc
,
bfunc
;
...
...
@@ -304,21 +227,8 @@ static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
writel
(
bfunc
,
nmk_chip
->
addr
+
NMK_GPIO_AFSLB
);
}
static
void
__nmk_gpio_set_slpm
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
enum
nmk_gpio_slpm
mode
)
{
u32
slpm
;
slpm
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_SLPC
);
if
(
mode
==
NMK_GPIO_SLPM_NOCHANGE
)
slpm
|=
BIT
(
offset
);
else
slpm
&=
~
BIT
(
offset
);
writel
(
slpm
,
nmk_chip
->
addr
+
NMK_GPIO_SLPC
);
}
static
void
__nmk_gpio_set_pull
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
enum
nmk_gpio_pull
pull
)
unsigned
int
offset
,
enum
nmk_gpio_pull
pull
)
{
u32
pdis
;
...
...
@@ -342,7 +252,7 @@ static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
}
static
void
__nmk_gpio_set_lowemi
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
bool
lowemi
)
unsigned
int
offset
,
bool
lowemi
)
{
bool
enabled
=
nmk_chip
->
lowemi
&
BIT
(
offset
);
...
...
@@ -359,29 +269,13 @@ static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip,
}
static
void
__nmk_gpio_make_input
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
)
unsigned
int
offset
)
{
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DIRC
);
}
static
void
__nmk_gpio_set_output
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
int
val
)
{
if
(
val
)
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DATS
);
else
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DATC
);
}
static
void
__nmk_gpio_make_output
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
int
val
)
{
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DIRS
);
__nmk_gpio_set_output
(
nmk_chip
,
offset
,
val
);
}
static
void
__nmk_gpio_set_mode_safe
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
,
int
gpio_mode
,
unsigned
int
offset
,
int
gpio_mode
,
bool
glitch
)
{
u32
rwimsc
=
nmk_chip
->
rwimsc
;
...
...
@@ -408,7 +302,7 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
}
static
void
nmk_gpio_disable_lazy_irq
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
offset
)
nmk_gpio_disable_lazy_irq
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
)
{
u32
falling
=
nmk_chip
->
fimsc
&
BIT
(
offset
);
u32
rising
=
nmk_chip
->
rimsc
&
BIT
(
offset
);
...
...
@@ -447,7 +341,7 @@ static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
}
static
void
nmk_prcm_altcx_set_mode
(
struct
nmk_pinctrl
*
npct
,
unsigned
offset
,
unsigned
alt_num
)
unsigned
int
offset
,
unsigned
int
alt_num
)
{
int
i
;
u16
reg
;
...
...
@@ -484,14 +378,14 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
*/
if
(
!
alt_num
)
{
for
(
i
=
0
;
i
<
PRCM_IDX_GPIOCR_ALTC_MAX
;
i
++
)
{
if
(
pin_desc
->
altcx
[
i
].
used
==
true
)
{
if
(
pin_desc
->
altcx
[
i
].
used
)
{
reg
=
gpiocr_regs
[
pin_desc
->
altcx
[
i
].
reg_index
];
bit
=
pin_desc
->
altcx
[
i
].
control_bit
;
if
(
readl
(
npct
->
prcm_base
+
reg
)
&
BIT
(
bit
))
{
nmk_write_masked
(
npct
->
prcm_base
+
reg
,
BIT
(
bit
),
0
);
dev_dbg
(
npct
->
dev
,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled
\n
"
,
offset
,
i
+
1
);
offset
,
i
+
1
);
}
}
}
...
...
@@ -499,10 +393,10 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
}
alt_index
=
alt_num
-
1
;
if
(
pin_desc
->
altcx
[
alt_index
].
used
==
false
)
{
if
(
!
pin_desc
->
altcx
[
alt_index
].
used
)
{
dev_warn
(
npct
->
dev
,
"PRCM GPIOCR: pin %i: alternate-C%i does not exist
\n
"
,
offset
,
alt_num
);
"PRCM GPIOCR: pin %i: alternate-C%i does not exist
\n
"
,
offset
,
alt_num
);
return
;
}
...
...
@@ -513,14 +407,14 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
for
(
i
=
0
;
i
<
PRCM_IDX_GPIOCR_ALTC_MAX
;
i
++
)
{
if
(
i
==
alt_index
)
continue
;
if
(
pin_desc
->
altcx
[
i
].
used
==
true
)
{
if
(
pin_desc
->
altcx
[
i
].
used
)
{
reg
=
gpiocr_regs
[
pin_desc
->
altcx
[
i
].
reg_index
];
bit
=
pin_desc
->
altcx
[
i
].
control_bit
;
if
(
readl
(
npct
->
prcm_base
+
reg
)
&
BIT
(
bit
))
{
nmk_write_masked
(
npct
->
prcm_base
+
reg
,
BIT
(
bit
),
0
);
dev_dbg
(
npct
->
dev
,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled
\n
"
,
offset
,
i
+
1
);
offset
,
i
+
1
);
}
}
}
...
...
@@ -528,7 +422,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
reg
=
gpiocr_regs
[
pin_desc
->
altcx
[
alt_index
].
reg_index
];
bit
=
pin_desc
->
altcx
[
alt_index
].
control_bit
;
dev_dbg
(
npct
->
dev
,
"PRCM GPIOCR: pin %i: alternate-C%i has been selected
\n
"
,
offset
,
alt_index
+
1
);
offset
,
alt_index
+
1
);
nmk_write_masked
(
npct
->
prcm_base
+
reg
,
BIT
(
bit
),
BIT
(
bit
));
}
...
...
@@ -548,7 +442,7 @@ static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
{
int
i
;
for
(
i
=
0
;
i
<
N
UM
_BANKS
;
i
++
)
{
for
(
i
=
0
;
i
<
N
MK_MAX
_BANKS
;
i
++
)
{
struct
nmk_gpio_chip
*
chip
=
nmk_gpio_chips
[
i
];
unsigned
int
temp
=
slpm
[
i
];
...
...
@@ -566,7 +460,7 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
{
int
i
;
for
(
i
=
0
;
i
<
N
UM
_BANKS
;
i
++
)
{
for
(
i
=
0
;
i
<
N
MK_MAX
_BANKS
;
i
++
)
{
struct
nmk_gpio_chip
*
chip
=
nmk_gpio_chips
[
i
];
if
(
!
chip
)
...
...
@@ -578,7 +472,8 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
}
}
static
int
__maybe_unused
nmk_prcm_gpiocr_get_mode
(
struct
pinctrl_dev
*
pctldev
,
int
gpio
)
/* Only called by gpio-nomadik but requires knowledge of struct nmk_pinctrl. */
int
__maybe_unused
nmk_prcm_gpiocr_get_mode
(
struct
pinctrl_dev
*
pctldev
,
int
gpio
)
{
int
i
;
u16
reg
;
...
...
@@ -600,586 +495,16 @@ static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev,
pin_desc
=
npct
->
soc
->
altcx_pins
+
i
;
gpiocr_regs
=
npct
->
soc
->
prcm_gpiocr_registers
;
for
(
i
=
0
;
i
<
PRCM_IDX_GPIOCR_ALTC_MAX
;
i
++
)
{
if
(
pin_desc
->
altcx
[
i
].
used
==
true
)
{
if
(
pin_desc
->
altcx
[
i
].
used
)
{
reg
=
gpiocr_regs
[
pin_desc
->
altcx
[
i
].
reg_index
];
bit
=
pin_desc
->
altcx
[
i
].
control_bit
;
if
(
readl
(
npct
->
prcm_base
+
reg
)
&
BIT
(
bit
))
return
NMK_GPIO_ALT_C
+
i
+
1
;
return
NMK_GPIO_ALT_C
+
i
+
1
;
}
}
return
NMK_GPIO_ALT_C
;
}
/* IRQ functions */
static
void
nmk_gpio_irq_ack
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
clk_enable
(
nmk_chip
->
clk
);
writel
(
BIT
(
d
->
hwirq
),
nmk_chip
->
addr
+
NMK_GPIO_IC
);
clk_disable
(
nmk_chip
->
clk
);
}
enum
nmk_gpio_irq_type
{
NORMAL
,
WAKE
,
};
static
void
__nmk_gpio_irq_modify
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
,
enum
nmk_gpio_irq_type
which
,
bool
enable
)
{
u32
*
rimscval
;
u32
*
fimscval
;
u32
rimscreg
;
u32
fimscreg
;
if
(
which
==
NORMAL
)
{
rimscreg
=
NMK_GPIO_RIMSC
;
fimscreg
=
NMK_GPIO_FIMSC
;
rimscval
=
&
nmk_chip
->
rimsc
;
fimscval
=
&
nmk_chip
->
fimsc
;
}
else
{
rimscreg
=
NMK_GPIO_RWIMSC
;
fimscreg
=
NMK_GPIO_FWIMSC
;
rimscval
=
&
nmk_chip
->
rwimsc
;
fimscval
=
&
nmk_chip
->
fwimsc
;
}
/* we must individually set/clear the two edges */
if
(
nmk_chip
->
edge_rising
&
BIT
(
offset
))
{
if
(
enable
)
*
rimscval
|=
BIT
(
offset
);
else
*
rimscval
&=
~
BIT
(
offset
);
writel
(
*
rimscval
,
nmk_chip
->
addr
+
rimscreg
);
}
if
(
nmk_chip
->
edge_falling
&
BIT
(
offset
))
{
if
(
enable
)
*
fimscval
|=
BIT
(
offset
);
else
*
fimscval
&=
~
BIT
(
offset
);
writel
(
*
fimscval
,
nmk_chip
->
addr
+
fimscreg
);
}
}
static
void
__nmk_gpio_set_wake
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
,
bool
on
)
{
/*
* Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is
* disabled, since setting SLPM to 1 increases power consumption, and
* wakeup is anyhow controlled by the RIMSC and FIMSC registers.
*/
if
(
nmk_chip
->
sleepmode
&&
on
)
{
__nmk_gpio_set_slpm
(
nmk_chip
,
offset
,
NMK_GPIO_SLPM_WAKEUP_ENABLE
);
}
__nmk_gpio_irq_modify
(
nmk_chip
,
offset
,
WAKE
,
on
);
}
static
void
nmk_gpio_irq_maskunmask
(
struct
nmk_gpio_chip
*
nmk_chip
,
struct
irq_data
*
d
,
bool
enable
)
{
unsigned
long
flags
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_gpio_slpm_lock
,
flags
);
spin_lock
(
&
nmk_chip
->
lock
);
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
enable
);
if
(
!
(
nmk_chip
->
real_wake
&
BIT
(
d
->
hwirq
)))
__nmk_gpio_set_wake
(
nmk_chip
,
d
->
hwirq
,
enable
);
spin_unlock
(
&
nmk_chip
->
lock
);
spin_unlock_irqrestore
(
&
nmk_gpio_slpm_lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
}
static
void
nmk_gpio_irq_mask
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
nmk_gpio_irq_maskunmask
(
nmk_chip
,
d
,
false
);
gpiochip_disable_irq
(
gc
,
irqd_to_hwirq
(
d
));
}
static
void
nmk_gpio_irq_unmask
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
gpiochip_enable_irq
(
gc
,
irqd_to_hwirq
(
d
));
nmk_gpio_irq_maskunmask
(
nmk_chip
,
d
,
true
);
}
static
int
nmk_gpio_irq_set_wake
(
struct
irq_data
*
d
,
unsigned
int
on
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
unsigned
long
flags
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_gpio_slpm_lock
,
flags
);
spin_lock
(
&
nmk_chip
->
lock
);
if
(
irqd_irq_disabled
(
d
))
__nmk_gpio_set_wake
(
nmk_chip
,
d
->
hwirq
,
on
);
if
(
on
)
nmk_chip
->
real_wake
|=
BIT
(
d
->
hwirq
);
else
nmk_chip
->
real_wake
&=
~
BIT
(
d
->
hwirq
);
spin_unlock
(
&
nmk_chip
->
lock
);
spin_unlock_irqrestore
(
&
nmk_gpio_slpm_lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
int
nmk_gpio_irq_set_type
(
struct
irq_data
*
d
,
unsigned
int
type
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
bool
enabled
=
!
irqd_irq_disabled
(
d
);
bool
wake
=
irqd_is_wakeup_set
(
d
);
unsigned
long
flags
;
if
(
type
&
IRQ_TYPE_LEVEL_HIGH
)
return
-
EINVAL
;
if
(
type
&
IRQ_TYPE_LEVEL_LOW
)
return
-
EINVAL
;
clk_enable
(
nmk_chip
->
clk
);
spin_lock_irqsave
(
&
nmk_chip
->
lock
,
flags
);
if
(
enabled
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
false
);
if
(
enabled
||
wake
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
WAKE
,
false
);
nmk_chip
->
edge_rising
&=
~
BIT
(
d
->
hwirq
);
if
(
type
&
IRQ_TYPE_EDGE_RISING
)
nmk_chip
->
edge_rising
|=
BIT
(
d
->
hwirq
);
nmk_chip
->
edge_falling
&=
~
BIT
(
d
->
hwirq
);
if
(
type
&
IRQ_TYPE_EDGE_FALLING
)
nmk_chip
->
edge_falling
|=
BIT
(
d
->
hwirq
);
if
(
enabled
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
NORMAL
,
true
);
if
(
enabled
||
wake
)
__nmk_gpio_irq_modify
(
nmk_chip
,
d
->
hwirq
,
WAKE
,
true
);
spin_unlock_irqrestore
(
&
nmk_chip
->
lock
,
flags
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
unsigned
int
nmk_gpio_irq_startup
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
clk_enable
(
nmk_chip
->
clk
);
nmk_gpio_irq_unmask
(
d
);
return
0
;
}
static
void
nmk_gpio_irq_shutdown
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
nmk_gpio_irq_mask
(
d
);
clk_disable
(
nmk_chip
->
clk
);
}
static
void
nmk_gpio_irq_handler
(
struct
irq_desc
*
desc
)
{
struct
irq_chip
*
host_chip
=
irq_desc_get_chip
(
desc
);
struct
gpio_chip
*
chip
=
irq_desc_get_handler_data
(
desc
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
u32
status
;
chained_irq_enter
(
host_chip
,
desc
);
clk_enable
(
nmk_chip
->
clk
);
status
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_IS
);
clk_disable
(
nmk_chip
->
clk
);
while
(
status
)
{
int
bit
=
__ffs
(
status
);
generic_handle_domain_irq
(
chip
->
irq
.
domain
,
bit
);
status
&=
~
BIT
(
bit
);
}
chained_irq_exit
(
host_chip
,
desc
);
}
/* I/O Functions */
static
int
nmk_gpio_get_dir
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
dir
;
clk_enable
(
nmk_chip
->
clk
);
dir
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DIR
)
&
BIT
(
offset
);
clk_disable
(
nmk_chip
->
clk
);
if
(
dir
)
return
GPIO_LINE_DIRECTION_OUT
;
return
GPIO_LINE_DIRECTION_IN
;
}
static
int
nmk_gpio_make_input
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
writel
(
BIT
(
offset
),
nmk_chip
->
addr
+
NMK_GPIO_DIRC
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
static
int
nmk_gpio_get_input
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
value
;
clk_enable
(
nmk_chip
->
clk
);
value
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DAT
)
&
BIT
(
offset
));
clk_disable
(
nmk_chip
->
clk
);
return
value
;
}
static
void
nmk_gpio_set_output
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
val
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
__nmk_gpio_set_output
(
nmk_chip
,
offset
,
val
);
clk_disable
(
nmk_chip
->
clk
);
}
static
int
nmk_gpio_make_output
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
val
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
clk_enable
(
nmk_chip
->
clk
);
__nmk_gpio_make_output
(
nmk_chip
,
offset
,
val
);
clk_disable
(
nmk_chip
->
clk
);
return
0
;
}
#ifdef CONFIG_DEBUG_FS
static
int
nmk_gpio_get_mode
(
struct
nmk_gpio_chip
*
nmk_chip
,
int
offset
)
{
u32
afunc
,
bfunc
;
clk_enable
(
nmk_chip
->
clk
);
afunc
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_AFSLA
)
&
BIT
(
offset
);
bfunc
=
readl
(
nmk_chip
->
addr
+
NMK_GPIO_AFSLB
)
&
BIT
(
offset
);
clk_disable
(
nmk_chip
->
clk
);
return
(
afunc
?
NMK_GPIO_ALT_A
:
0
)
|
(
bfunc
?
NMK_GPIO_ALT_B
:
0
);
}
static
void
nmk_gpio_dbg_show_one
(
struct
seq_file
*
s
,
struct
pinctrl_dev
*
pctldev
,
struct
gpio_chip
*
chip
,
unsigned
offset
,
unsigned
gpio
)
{
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
chip
);
int
mode
;
bool
is_out
;
bool
data_out
;
bool
pull
;
const
char
*
modes
[]
=
{
[
NMK_GPIO_ALT_GPIO
]
=
"gpio"
,
[
NMK_GPIO_ALT_A
]
=
"altA"
,
[
NMK_GPIO_ALT_B
]
=
"altB"
,
[
NMK_GPIO_ALT_C
]
=
"altC"
,
[
NMK_GPIO_ALT_C
+
1
]
=
"altC1"
,
[
NMK_GPIO_ALT_C
+
2
]
=
"altC2"
,
[
NMK_GPIO_ALT_C
+
3
]
=
"altC3"
,
[
NMK_GPIO_ALT_C
+
4
]
=
"altC4"
,
};
char
*
label
=
gpiochip_dup_line_label
(
chip
,
offset
);
if
(
IS_ERR
(
label
))
return
;
clk_enable
(
nmk_chip
->
clk
);
is_out
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DIR
)
&
BIT
(
offset
));
pull
=
!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_PDIS
)
&
BIT
(
offset
));
data_out
=
!!
(
readl
(
nmk_chip
->
addr
+
NMK_GPIO_DAT
)
&
BIT
(
offset
));
mode
=
nmk_gpio_get_mode
(
nmk_chip
,
offset
);
if
((
mode
==
NMK_GPIO_ALT_C
)
&&
pctldev
)
mode
=
nmk_prcm_gpiocr_get_mode
(
pctldev
,
gpio
);
if
(
is_out
)
{
seq_printf
(
s
,
" gpio-%-3d (%-20.20s) out %s %s"
,
gpio
,
label
?:
"(none)"
,
data_out
?
"hi"
:
"lo"
,
(
mode
<
0
)
?
"unknown"
:
modes
[
mode
]);
}
else
{
int
irq
=
chip
->
to_irq
(
chip
,
offset
);
const
int
pullidx
=
pull
?
1
:
0
;
int
val
;
static
const
char
*
const
pulls
[]
=
{
"none "
,
"pull enabled"
,
};
seq_printf
(
s
,
" gpio-%-3d (%-20.20s) in %s %s"
,
gpio
,
label
?:
"(none)"
,
pulls
[
pullidx
],
(
mode
<
0
)
?
"unknown"
:
modes
[
mode
]);
val
=
nmk_gpio_get_input
(
chip
,
offset
);
seq_printf
(
s
,
" VAL %d"
,
val
);
/*
* This races with request_irq(), set_irq_type(),
* and set_irq_wake() ... but those are "rare".
*/
if
(
irq
>
0
&&
irq_has_action
(
irq
))
{
char
*
trigger
;
bool
wake
;
if
(
nmk_chip
->
edge_rising
&
BIT
(
offset
))
trigger
=
"edge-rising"
;
else
if
(
nmk_chip
->
edge_falling
&
BIT
(
offset
))
trigger
=
"edge-falling"
;
else
trigger
=
"edge-undefined"
;
wake
=
!!
(
nmk_chip
->
real_wake
&
BIT
(
offset
));
seq_printf
(
s
,
" irq-%d %s%s"
,
irq
,
trigger
,
wake
?
" wakeup"
:
""
);
}
}
clk_disable
(
nmk_chip
->
clk
);
}
static
void
nmk_gpio_dbg_show
(
struct
seq_file
*
s
,
struct
gpio_chip
*
chip
)
{
unsigned
i
;
unsigned
gpio
=
chip
->
base
;
for
(
i
=
0
;
i
<
chip
->
ngpio
;
i
++
,
gpio
++
)
{
nmk_gpio_dbg_show_one
(
s
,
NULL
,
chip
,
i
,
gpio
);
seq_printf
(
s
,
"
\n
"
);
}
}
#else
static
inline
void
nmk_gpio_dbg_show_one
(
struct
seq_file
*
s
,
struct
pinctrl_dev
*
pctldev
,
struct
gpio_chip
*
chip
,
unsigned
offset
,
unsigned
gpio
)
{
}
#define nmk_gpio_dbg_show NULL
#endif
/*
* We will allocate memory for the state container using devm* allocators
* binding to the first device reaching this point, it doesn't matter if
* it is the pin controller or GPIO driver. However we need to use the right
* platform device when looking up resources so pay attention to pdev.
*/
static
struct
nmk_gpio_chip
*
nmk_gpio_populate_chip
(
struct
device_node
*
np
,
struct
platform_device
*
pdev
)
{
struct
nmk_gpio_chip
*
nmk_chip
;
struct
platform_device
*
gpio_pdev
;
struct
gpio_chip
*
chip
;
struct
resource
*
res
;
struct
clk
*
clk
;
void
__iomem
*
base
;
u32
id
;
gpio_pdev
=
of_find_device_by_node
(
np
);
if
(
!
gpio_pdev
)
{
pr_err
(
"populate
\"
%pOFn
\"
: device not found
\n
"
,
np
);
return
ERR_PTR
(
-
ENODEV
);
}
if
(
of_property_read_u32
(
np
,
"gpio-bank"
,
&
id
))
{
dev_err
(
&
pdev
->
dev
,
"populate: gpio-bank property not found
\n
"
);
platform_device_put
(
gpio_pdev
);
return
ERR_PTR
(
-
EINVAL
);
}
/* Already populated? */
nmk_chip
=
nmk_gpio_chips
[
id
];
if
(
nmk_chip
)
{
platform_device_put
(
gpio_pdev
);
return
nmk_chip
;
}
nmk_chip
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
nmk_chip
),
GFP_KERNEL
);
if
(
!
nmk_chip
)
{
platform_device_put
(
gpio_pdev
);
return
ERR_PTR
(
-
ENOMEM
);
}
nmk_chip
->
bank
=
id
;
chip
=
&
nmk_chip
->
chip
;
chip
->
base
=
id
*
NMK_GPIO_PER_CHIP
;
chip
->
ngpio
=
NMK_GPIO_PER_CHIP
;
chip
->
label
=
dev_name
(
&
gpio_pdev
->
dev
);
chip
->
parent
=
&
gpio_pdev
->
dev
;
res
=
platform_get_resource
(
gpio_pdev
,
IORESOURCE_MEM
,
0
);
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
base
))
{
platform_device_put
(
gpio_pdev
);
return
ERR_CAST
(
base
);
}
nmk_chip
->
addr
=
base
;
clk
=
clk_get
(
&
gpio_pdev
->
dev
,
NULL
);
if
(
IS_ERR
(
clk
))
{
platform_device_put
(
gpio_pdev
);
return
(
void
*
)
clk
;
}
clk_prepare
(
clk
);
nmk_chip
->
clk
=
clk
;
BUG_ON
(
nmk_chip
->
bank
>=
ARRAY_SIZE
(
nmk_gpio_chips
));
nmk_gpio_chips
[
id
]
=
nmk_chip
;
return
nmk_chip
;
}
static
void
nmk_gpio_irq_print_chip
(
struct
irq_data
*
d
,
struct
seq_file
*
p
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
nmk_gpio_chip
*
nmk_chip
=
gpiochip_get_data
(
gc
);
seq_printf
(
p
,
"nmk%u-%u-%u"
,
nmk_chip
->
bank
,
gc
->
base
,
gc
->
base
+
gc
->
ngpio
-
1
);
}
static
const
struct
irq_chip
nmk_irq_chip
=
{
.
irq_ack
=
nmk_gpio_irq_ack
,
.
irq_mask
=
nmk_gpio_irq_mask
,
.
irq_unmask
=
nmk_gpio_irq_unmask
,
.
irq_set_type
=
nmk_gpio_irq_set_type
,
.
irq_set_wake
=
nmk_gpio_irq_set_wake
,
.
irq_startup
=
nmk_gpio_irq_startup
,
.
irq_shutdown
=
nmk_gpio_irq_shutdown
,
.
irq_print_chip
=
nmk_gpio_irq_print_chip
,
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
|
IRQCHIP_IMMUTABLE
,
GPIOCHIP_IRQ_RESOURCE_HELPERS
,
};
static
int
nmk_gpio_probe
(
struct
platform_device
*
dev
)
{
struct
device_node
*
np
=
dev
->
dev
.
of_node
;
struct
nmk_gpio_chip
*
nmk_chip
;
struct
gpio_chip
*
chip
;
struct
gpio_irq_chip
*
girq
;
bool
supports_sleepmode
;
int
irq
;
int
ret
;
nmk_chip
=
nmk_gpio_populate_chip
(
np
,
dev
);
if
(
IS_ERR
(
nmk_chip
))
{
dev_err
(
&
dev
->
dev
,
"could not populate nmk chip struct
\n
"
);
return
PTR_ERR
(
nmk_chip
);
}
supports_sleepmode
=
of_property_read_bool
(
np
,
"st,supports-sleepmode"
);
/* Correct platform device ID */
dev
->
id
=
nmk_chip
->
bank
;
irq
=
platform_get_irq
(
dev
,
0
);
if
(
irq
<
0
)
return
irq
;
/*
* The virt address in nmk_chip->addr is in the nomadik register space,
* so we can simply convert the resource address, without remapping
*/
nmk_chip
->
sleepmode
=
supports_sleepmode
;
spin_lock_init
(
&
nmk_chip
->
lock
);
chip
=
&
nmk_chip
->
chip
;
chip
->
parent
=
&
dev
->
dev
;
chip
->
request
=
gpiochip_generic_request
;
chip
->
free
=
gpiochip_generic_free
;
chip
->
get_direction
=
nmk_gpio_get_dir
;
chip
->
direction_input
=
nmk_gpio_make_input
;
chip
->
get
=
nmk_gpio_get_input
;
chip
->
direction_output
=
nmk_gpio_make_output
;
chip
->
set
=
nmk_gpio_set_output
;
chip
->
dbg_show
=
nmk_gpio_dbg_show
;
chip
->
can_sleep
=
false
;
chip
->
owner
=
THIS_MODULE
;
girq
=
&
chip
->
irq
;
gpio_irq_chip_set_chip
(
girq
,
&
nmk_irq_chip
);
girq
->
parent_handler
=
nmk_gpio_irq_handler
;
girq
->
num_parents
=
1
;
girq
->
parents
=
devm_kcalloc
(
&
dev
->
dev
,
1
,
sizeof
(
*
girq
->
parents
),
GFP_KERNEL
);
if
(
!
girq
->
parents
)
return
-
ENOMEM
;
girq
->
parents
[
0
]
=
irq
;
girq
->
default_type
=
IRQ_TYPE_NONE
;
girq
->
handler
=
handle_edge_irq
;
clk_enable
(
nmk_chip
->
clk
);
nmk_chip
->
lowemi
=
readl_relaxed
(
nmk_chip
->
addr
+
NMK_GPIO_LOWEMI
);
clk_disable
(
nmk_chip
->
clk
);
ret
=
gpiochip_add_data
(
chip
,
nmk_chip
);
if
(
ret
)
return
ret
;
platform_set_drvdata
(
dev
,
nmk_chip
);
dev_info
(
&
dev
->
dev
,
"chip registered
\n
"
);
return
0
;
}
static
int
nmk_get_groups_cnt
(
struct
pinctrl_dev
*
pctldev
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
...
...
@@ -1188,43 +513,51 @@ static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
}
static
const
char
*
nmk_get_group_name
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
)
unsigned
int
selector
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
npct
->
soc
->
groups
[
selector
].
grp
.
name
;
}
static
int
nmk_get_group_pins
(
struct
pinctrl_dev
*
pctldev
,
unsigned
selector
,
const
unsigned
**
pins
,
unsigned
*
n
pins
)
static
int
nmk_get_group_pins
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
selector
,
const
unsigned
int
**
pins
,
unsigned
int
*
num_
pins
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
*
pins
=
npct
->
soc
->
groups
[
selector
].
grp
.
pins
;
*
npins
=
npct
->
soc
->
groups
[
selector
].
grp
.
npins
;
*
n
um_
pins
=
npct
->
soc
->
groups
[
selector
].
grp
.
npins
;
return
0
;
}
static
struct
nmk_gpio_chip
*
find_nmk_gpio_from_pin
(
unsigned
pin
)
/* This makes the mapping from pin number to a GPIO chip. We also return the pin
* offset in the GPIO chip for convenience (and to avoid a second loop).
*/
static
struct
nmk_gpio_chip
*
find_nmk_gpio_from_pin
(
unsigned
int
pin
,
unsigned
int
*
offset
)
{
int
i
;
int
i
,
j
=
0
;
struct
nmk_gpio_chip
*
nmk_gpio
;
for
(
i
=
0
;
i
<
NMK_MAX_BANKS
;
i
++
)
{
/* We assume that pins are allocated in bank order. */
for
(
i
=
0
;
i
<
NMK_MAX_BANKS
;
i
++
)
{
nmk_gpio
=
nmk_gpio_chips
[
i
];
if
(
!
nmk_gpio
)
continue
;
if
(
pin
>=
nmk_gpio
->
chip
.
base
&&
pin
<
nmk_gpio
->
chip
.
base
+
nmk_gpio
->
chip
.
ngpio
)
if
(
pin
>=
j
&&
pin
<
j
+
nmk_gpio
->
chip
.
ngpio
)
{
if
(
offset
)
*
offset
=
pin
-
j
;
return
nmk_gpio
;
}
j
+=
nmk_gpio
->
chip
.
ngpio
;
}
return
NULL
;
}
static
struct
gpio_chip
*
find_gc_from_pin
(
unsigned
pin
)
static
struct
gpio_chip
*
find_gc_from_pin
(
unsigned
int
pin
)
{
struct
nmk_gpio_chip
*
nmk_gpio
=
find_nmk_gpio_from_pin
(
pin
);
struct
nmk_gpio_chip
*
nmk_gpio
=
find_nmk_gpio_from_pin
(
pin
,
NULL
);
if
(
nmk_gpio
)
return
&
nmk_gpio
->
chip
;
...
...
@@ -1232,7 +565,7 @@ static struct gpio_chip *find_gc_from_pin(unsigned pin)
}
static
void
nmk_pin_dbg_show
(
struct
pinctrl_dev
*
pctldev
,
struct
seq_file
*
s
,
unsigned
offset
)
unsigned
int
offset
)
{
struct
gpio_chip
*
chip
=
find_gc_from_pin
(
offset
);
...
...
@@ -1243,9 +576,9 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
nmk_gpio_dbg_show_one
(
s
,
pctldev
,
chip
,
offset
-
chip
->
base
,
offset
);
}
static
int
nmk_dt_add_map_mux
(
struct
pinctrl_map
**
map
,
unsigned
*
reserved_maps
,
unsigned
*
num_maps
,
const
char
*
group
,
const
char
*
function
)
static
int
nmk_dt_add_map_mux
(
struct
pinctrl_map
**
map
,
unsigned
int
*
reserved_maps
,
unsigned
int
*
num_maps
,
const
char
*
group
,
const
char
*
function
)
{
if
(
*
num_maps
==
*
reserved_maps
)
return
-
ENOSPC
;
...
...
@@ -1259,9 +592,9 @@ static int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
}
static
int
nmk_dt_add_map_configs
(
struct
pinctrl_map
**
map
,
unsigned
*
reserved_maps
,
unsigned
*
num_maps
,
const
char
*
group
,
unsigned
long
*
configs
,
unsigned
num_configs
)
unsigned
int
*
reserved_maps
,
unsigned
int
*
num_maps
,
const
char
*
group
,
unsigned
long
*
configs
,
unsigned
int
num_configs
)
{
unsigned
long
*
dup_configs
;
...
...
@@ -1352,9 +685,9 @@ static const struct nmk_cfg_param nmk_cfg_params[] = {
static
int
nmk_dt_pin_config
(
int
index
,
int
val
,
unsigned
long
*
config
)
{
if
(
nmk_cfg_params
[
index
].
choice
==
NULL
)
if
(
!
nmk_cfg_params
[
index
].
choice
)
{
*
config
=
nmk_cfg_params
[
index
].
config
;
else
{
}
else
{
/* test if out of range */
if
(
val
<
nmk_cfg_params
[
index
].
size
)
{
*
config
=
nmk_cfg_params
[
index
].
config
|
...
...
@@ -1377,15 +710,14 @@ static const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pi
}
static
bool
nmk_pinctrl_dt_get_config
(
struct
device_node
*
np
,
unsigned
long
*
configs
)
unsigned
long
*
configs
)
{
bool
has_config
=
0
;
unsigned
long
cfg
=
0
;
int
i
,
val
,
ret
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
nmk_cfg_params
);
i
++
)
{
ret
=
of_property_read_u32
(
np
,
nmk_cfg_params
[
i
].
property
,
&
val
);
ret
=
of_property_read_u32
(
np
,
nmk_cfg_params
[
i
].
property
,
&
val
);
if
(
ret
!=
-
EINVAL
)
{
if
(
nmk_dt_pin_config
(
i
,
val
,
&
cfg
)
==
0
)
{
*
configs
|=
cfg
;
...
...
@@ -1398,10 +730,10 @@ static bool nmk_pinctrl_dt_get_config(struct device_node *np,
}
static
int
nmk_pinctrl_dt_subnode_to_map
(
struct
pinctrl_dev
*
pctldev
,
struct
device_node
*
np
,
struct
pinctrl_map
**
map
,
unsigned
*
reserved_maps
,
unsigned
*
num_maps
)
struct
device_node
*
np
,
struct
pinctrl_map
**
map
,
unsigned
int
*
reserved_maps
,
unsigned
int
*
num_maps
)
{
int
ret
;
const
char
*
function
=
NULL
;
...
...
@@ -1426,7 +758,7 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
of_property_for_each_string
(
np
,
"groups"
,
prop
,
group
)
{
ret
=
nmk_dt_add_map_mux
(
map
,
reserved_maps
,
num_maps
,
group
,
function
);
group
,
function
);
if
(
ret
<
0
)
goto
exit
;
}
...
...
@@ -1467,10 +799,11 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
}
static
int
nmk_pinctrl_dt_node_to_map
(
struct
pinctrl_dev
*
pctldev
,
struct
device_node
*
np_config
,
struct
pinctrl_map
**
map
,
unsigned
*
num_maps
)
struct
device_node
*
np_config
,
struct
pinctrl_map
**
map
,
unsigned
int
*
num_maps
)
{
unsigned
reserved_maps
;
unsigned
int
reserved_maps
;
struct
device_node
*
np
;
int
ret
;
...
...
@@ -1480,7 +813,7 @@ static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
for_each_child_of_node
(
np_config
,
np
)
{
ret
=
nmk_pinctrl_dt_subnode_to_map
(
pctldev
,
np
,
map
,
&
reserved_maps
,
num_maps
);
&
reserved_maps
,
num_maps
);
if
(
ret
<
0
)
{
pinctrl_utils_free_map
(
pctldev
,
*
map
,
*
num_maps
);
of_node_put
(
np
);
...
...
@@ -1508,7 +841,7 @@ static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
}
static
const
char
*
nmk_pmx_get_func_name
(
struct
pinctrl_dev
*
pctldev
,
unsigned
function
)
unsigned
int
function
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
...
...
@@ -1516,7 +849,7 @@ static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev,
}
static
int
nmk_pmx_get_func_groups
(
struct
pinctrl_dev
*
pctldev
,
unsigned
function
,
unsigned
int
function
,
const
char
*
const
**
groups
,
unsigned
*
const
num_groups
)
{
...
...
@@ -1528,12 +861,12 @@ static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
return
0
;
}
static
int
nmk_pmx_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
function
,
unsigned
group
)
static
int
nmk_pmx_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
function
,
unsigned
int
group
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
const
struct
nmk_pingroup
*
g
;
static
unsigned
int
slpm
[
N
UM
_BANKS
];
static
unsigned
int
slpm
[
N
MK_MAX
_BANKS
];
unsigned
long
flags
=
0
;
bool
glitch
;
int
ret
=
-
EINVAL
;
...
...
@@ -1544,7 +877,7 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function,
if
(
g
->
altsetting
<
0
)
return
-
EINVAL
;
dev_dbg
(
npct
->
dev
,
"enable group %s, %u pins
\n
"
,
g
->
grp
.
name
,
g
->
grp
.
npins
);
dev_dbg
(
npct
->
dev
,
"enable group %s, %
z
u pins
\n
"
,
g
->
grp
.
name
,
g
->
grp
.
npins
);
/*
* If we're setting altfunc C by setting both AFSLA and AFSLB to 1,
...
...
@@ -1579,26 +912,38 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function,
* Then mask the pins that need to be sleeping now when we're
* switching to the ALT C function.
*/
for
(
i
=
0
;
i
<
g
->
grp
.
npins
;
i
++
)
slpm
[
g
->
grp
.
pins
[
i
]
/
NMK_GPIO_PER_CHIP
]
&=
~
BIT
(
g
->
grp
.
pins
[
i
]);
for
(
i
=
0
;
i
<
g
->
grp
.
npins
;
i
++
)
{
struct
nmk_gpio_chip
*
nmk_chip
;
unsigned
int
bit
;
nmk_chip
=
find_nmk_gpio_from_pin
(
g
->
grp
.
pins
[
i
],
&
bit
);
if
(
!
nmk_chip
)
{
dev_err
(
npct
->
dev
,
"invalid pin offset %d in group %s at index %d
\n
"
,
g
->
grp
.
pins
[
i
],
g
->
grp
.
name
,
i
);
goto
out_pre_slpm_init
;
}
slpm
[
nmk_chip
->
bank
]
&=
~
BIT
(
bit
);
}
nmk_gpio_glitch_slpm_init
(
slpm
);
}
for
(
i
=
0
;
i
<
g
->
grp
.
npins
;
i
++
)
{
struct
nmk_gpio_chip
*
nmk_chip
;
unsigned
bit
;
unsigned
int
bit
;
nmk_chip
=
find_nmk_gpio_from_pin
(
g
->
grp
.
pins
[
i
]);
nmk_chip
=
find_nmk_gpio_from_pin
(
g
->
grp
.
pins
[
i
]
,
&
bit
);
if
(
!
nmk_chip
)
{
dev_err
(
npct
->
dev
,
"invalid pin offset %d in group %s at index %d
\n
"
,
g
->
grp
.
pins
[
i
],
g
->
grp
.
name
,
i
);
goto
out_glitch
;
}
dev_dbg
(
npct
->
dev
,
"setting pin %d to altsetting %d
\n
"
,
g
->
grp
.
pins
[
i
],
g
->
altsetting
);
dev_dbg
(
npct
->
dev
,
"setting pin %d to altsetting %d
\n
"
,
g
->
grp
.
pins
[
i
],
g
->
altsetting
);
clk_enable
(
nmk_chip
->
clk
);
bit
=
g
->
grp
.
pins
[
i
]
%
NMK_GPIO_PER_CHIP
;
/*
* If the pin is switching to altfunc, and there was an
* interrupt installed on it which has been lazy disabled,
...
...
@@ -1609,7 +954,7 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function,
nmk_gpio_disable_lazy_irq
(
nmk_chip
,
bit
);
__nmk_gpio_set_mode_safe
(
nmk_chip
,
bit
,
(
g
->
altsetting
&
NMK_GPIO_ALT_C
),
glitch
);
(
g
->
altsetting
&
NMK_GPIO_ALT_C
),
glitch
);
clk_disable
(
nmk_chip
->
clk
);
/*
...
...
@@ -1622,29 +967,30 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function,
*/
if
((
g
->
altsetting
&
NMK_GPIO_ALT_C
)
==
NMK_GPIO_ALT_C
)
nmk_prcm_altcx_set_mode
(
npct
,
g
->
grp
.
pins
[
i
],
g
->
altsetting
>>
NMK_GPIO_ALT_CX_SHIFT
);
g
->
altsetting
>>
NMK_GPIO_ALT_CX_SHIFT
);
}
/* When all pins are successfully reconfigured we get here */
ret
=
0
;
out_glitch:
if
(
glitch
)
{
if
(
glitch
)
nmk_gpio_glitch_slpm_restore
(
slpm
);
out_pre_slpm_init:
if
(
glitch
)
spin_unlock_irqrestore
(
&
nmk_gpio_slpm_lock
,
flags
);
}
return
ret
;
}
static
int
nmk_gpio_request_enable
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_gpio_range
*
range
,
unsigned
offset
)
unsigned
int
pin
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
nmk_gpio_chip
*
nmk_chip
;
struct
gpio_chip
*
chip
;
unsigned
bit
;
unsigned
int
bit
;
if
(
!
range
)
{
dev_err
(
npct
->
dev
,
"invalid range
\n
"
);
...
...
@@ -1657,10 +1003,11 @@ static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
chip
=
range
->
gc
;
nmk_chip
=
gpiochip_get_data
(
chip
);
dev_dbg
(
npct
->
dev
,
"enable pin %u as GPIO
\n
"
,
offset
);
dev_dbg
(
npct
->
dev
,
"enable pin %u as GPIO
\n
"
,
pin
);
find_nmk_gpio_from_pin
(
pin
,
&
bit
);
clk_enable
(
nmk_chip
->
clk
);
bit
=
offset
%
NMK_GPIO_PER_CHIP
;
/* There is no glitch when converting any pin to GPIO */
__nmk_gpio_set_mode
(
nmk_chip
,
bit
,
NMK_GPIO_ALT_GPIO
);
clk_disable
(
nmk_chip
->
clk
);
...
...
@@ -1670,11 +1017,11 @@ static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
static
void
nmk_gpio_disable_free
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_gpio_range
*
range
,
unsigned
offset
)
unsigned
int
pin
)
{
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
dev_dbg
(
npct
->
dev
,
"disable pin %u as GPIO
\n
"
,
offset
);
dev_dbg
(
npct
->
dev
,
"disable pin %u as GPIO
\n
"
,
pin
);
/* Set the pin to some default state, GPIO is usually default */
}
...
...
@@ -1688,34 +1035,34 @@ static const struct pinmux_ops nmk_pinmux_ops = {
.
strict
=
true
,
};
static
int
nmk_pin_config_get
(
struct
pinctrl_dev
*
pctldev
,
unsigned
pin
,
static
int
nmk_pin_config_get
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
pin
,
unsigned
long
*
config
)
{
/* Not implemented */
return
-
EINVAL
;
}
static
int
nmk_pin_config_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
pin
,
unsigned
long
*
configs
,
unsigned
num_configs
)
static
int
nmk_pin_config_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
pin
,
unsigned
long
*
configs
,
unsigned
int
num_configs
)
{
static
const
char
*
pullnames
[]
=
{
static
const
char
*
const
pullnames
[]
=
{
[
NMK_GPIO_PULL_NONE
]
=
"none"
,
[
NMK_GPIO_PULL_UP
]
=
"up"
,
[
NMK_GPIO_PULL_DOWN
]
=
"down"
,
[
3
]
/* illegal */
=
"??"
};
static
const
char
*
slpmnames
[]
=
{
static
const
char
*
const
slpmnames
[]
=
{
[
NMK_GPIO_SLPM_INPUT
]
=
"input/wakeup"
,
[
NMK_GPIO_SLPM_NOCHANGE
]
=
"no-change/no-wakeup"
,
};
struct
nmk_pinctrl
*
npct
=
pinctrl_dev_get_drvdata
(
pctldev
);
struct
nmk_gpio_chip
*
nmk_chip
;
unsigned
bit
;
pin_cfg_t
cfg
;
unsigned
int
bit
;
unsigned
long
cfg
;
int
pull
,
slpm
,
output
,
val
,
i
;
bool
lowemi
,
gpiomode
,
sleep
;
nmk_chip
=
find_nmk_gpio_from_pin
(
pin
);
nmk_chip
=
find_nmk_gpio_from_pin
(
pin
,
&
bit
);
if
(
!
nmk_chip
)
{
dev_err
(
npct
->
dev
,
"invalid pin offset %d
\n
"
,
pin
);
...
...
@@ -1728,7 +1075,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
* here we just ignore that part. It's being handled by the
* framework and pinmux callback respectively.
*/
cfg
=
(
pin_cfg_t
)
configs
[
i
];
cfg
=
configs
[
i
];
pull
=
PIN_PULL
(
cfg
);
slpm
=
PIN_SLPM
(
cfg
);
output
=
PIN_DIR
(
cfg
);
...
...
@@ -1773,13 +1120,12 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
lowemi
?
"on"
:
"off"
);
clk_enable
(
nmk_chip
->
clk
);
bit
=
pin
%
NMK_GPIO_PER_CHIP
;
if
(
gpiomode
)
/* No glitch when going to GPIO mode */
__nmk_gpio_set_mode
(
nmk_chip
,
bit
,
NMK_GPIO_ALT_GPIO
);
if
(
output
)
if
(
output
)
{
__nmk_gpio_make_output
(
nmk_chip
,
bit
,
val
);
else
{
}
else
{
__nmk_gpio_make_input
(
nmk_chip
,
bit
);
__nmk_gpio_set_pull
(
nmk_chip
,
bit
,
pull
);
}
...
...
@@ -1844,17 +1190,17 @@ static int nmk_pinctrl_resume(struct device *dev)
static
int
nmk_pinctrl_probe
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
struct
device_node
*
prcm_np
;
struct
fwnode_handle
*
fwnode
=
dev_fwnode
(
&
pdev
->
dev
)
;
struct
fwnode_handle
*
prcm_fwnode
;
struct
nmk_pinctrl
*
npct
;
u
nsigned
in
t
version
=
0
;
u
intptr_
t
version
=
0
;
int
i
;
npct
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
npct
),
GFP_KERNEL
);
if
(
!
npct
)
return
-
ENOMEM
;
version
=
(
u
nsigned
in
t
)
device_get_match_data
(
&
pdev
->
dev
);
version
=
(
u
intptr_
t
)
device_get_match_data
(
&
pdev
->
dev
);
/* Poke in other ASIC variants here */
if
(
version
==
PINCTRL_NMK_STN8815
)
...
...
@@ -1870,33 +1216,33 @@ static int nmk_pinctrl_probe(struct platform_device *pdev)
* or after this point: it shouldn't matter as the APIs are orthogonal.
*/
for
(
i
=
0
;
i
<
NMK_MAX_BANKS
;
i
++
)
{
struct
device_node
*
gpio_np
;
struct
fwnode_handle
*
gpio_fwnode
;
struct
nmk_gpio_chip
*
nmk_chip
;
gpio_np
=
of_parse_phandle
(
np
,
"nomadik-gpio-chips"
,
i
);
if
(
gpio_np
)
{
dev_info
(
&
pdev
->
dev
,
"populate NMK GPIO %d
\"
%pOFn
\"\n
"
,
i
,
gpio_np
);
nmk_chip
=
nmk_gpio_populate_chip
(
gpio_np
,
pdev
);
if
(
IS_ERR
(
nmk_chip
))
dev_err
(
&
pdev
->
dev
,
"could not populate nmk chip struct "
"- continue anyway
\n
"
);
of_node_put
(
gpio_np
);
}
gpio_fwnode
=
fwnode_find_reference
(
fwnode
,
"nomadik-gpio-chips"
,
i
);
if
(
IS_ERR
(
gpio_fwnode
))
continue
;
dev_info
(
&
pdev
->
dev
,
"populate NMK GPIO %d
\"
%pfwP
\"\n
"
,
i
,
gpio_fwnode
);
nmk_chip
=
nmk_gpio_populate_chip
(
gpio_fwnode
,
pdev
);
if
(
IS_ERR
(
nmk_chip
))
dev_err
(
&
pdev
->
dev
,
"could not populate nmk chip struct - continue anyway
\n
"
);
else
/* We are NOT compatible with mobileye,eyeq5-gpio. */
BUG_ON
(
nmk_chip
->
is_mobileye_soc
);
fwnode_handle_put
(
gpio_fwnode
);
}
prcm_
np
=
of_parse_phandle
(
np
,
"prcm"
,
0
);
if
(
prcm_np
)
{
npct
->
prcm_base
=
of_iomap
(
prcm_np
,
0
);
of_node_put
(
prcm_np
);
prcm_
fwnode
=
fwnode_find_reference
(
fwnode
,
"prcm"
,
0
);
if
(
!
IS_ERR
(
prcm_fwnode
)
)
{
npct
->
prcm_base
=
fwnode_iomap
(
prcm_fwnode
,
0
);
fwnode_handle_put
(
prcm_fwnode
);
}
if
(
!
npct
->
prcm_base
)
{
if
(
version
==
PINCTRL_NMK_STN8815
)
{
dev_info
(
&
pdev
->
dev
,
"No PRCM base, "
"assuming no ALT-Cx control is available
\n
"
);
"No PRCM base, assuming no ALT-Cx control is available
\n
"
);
}
else
{
dev_err
(
&
pdev
->
dev
,
"missing PRCM base address
\n
"
);
return
-
EINVAL
;
...
...
@@ -1919,19 +1265,6 @@ static int nmk_pinctrl_probe(struct platform_device *pdev)
return
0
;
}
static
const
struct
of_device_id
nmk_gpio_match
[]
=
{
{
.
compatible
=
"st,nomadik-gpio"
,
},
{}
};
static
struct
platform_driver
nmk_gpio_driver
=
{
.
driver
=
{
.
name
=
"gpio"
,
.
of_match_table
=
nmk_gpio_match
,
},
.
probe
=
nmk_gpio_probe
,
};
static
SIMPLE_DEV_PM_OPS
(
nmk_pinctrl_pm_ops
,
nmk_pinctrl_suspend
,
nmk_pinctrl_resume
);
...
...
@@ -1945,12 +1278,6 @@ static struct platform_driver nmk_pinctrl_driver = {
.
probe
=
nmk_pinctrl_probe
,
};
static
int
__init
nmk_gpio_init
(
void
)
{
return
platform_driver_register
(
&
nmk_gpio_driver
);
}
subsys_initcall
(
nmk_gpio_init
);
static
int
__init
nmk_pinctrl_init
(
void
)
{
return
platform_driver_register
(
&
nmk_pinctrl_driver
);
...
...
drivers/pinctrl/nomadik/pinctrl
-nomadik.h
→
include/linux/gpio/gpio
-nomadik.h
View file @
64df5ea9
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef
PINCTRL_PINCTRL
_NOMADIK_H
#define
PINCTRL_PINCTRL
_NOMADIK_H
#ifndef
__LINUX_GPIO
_NOMADIK_H
#define
__LINUX_GPIO
_NOMADIK_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pinctrl/pinctrl.h>
struct
fwnode_handle
;
/* Package definitions */
#define PINCTRL_NMK_STN8815 0
#define PINCTRL_NMK_DB8500 1
#define GPIO_BLOCK_SHIFT 5
#define NMK_GPIO_PER_CHIP BIT(GPIO_BLOCK_SHIFT)
#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP)
/* Register in the logic block */
#define NMK_GPIO_DAT 0x00
#define NMK_GPIO_DATS 0x04
#define NMK_GPIO_DATC 0x08
#define NMK_GPIO_PDIS 0x0c
#define NMK_GPIO_DIR 0x10
#define NMK_GPIO_DIRS 0x14
#define NMK_GPIO_DIRC 0x18
#define NMK_GPIO_SLPC 0x1c
#define NMK_GPIO_AFSLA 0x20
#define NMK_GPIO_AFSLB 0x24
#define NMK_GPIO_LOWEMI 0x28
#define NMK_GPIO_RIMSC 0x40
#define NMK_GPIO_FIMSC 0x44
#define NMK_GPIO_IS 0x48
#define NMK_GPIO_IC 0x4c
#define NMK_GPIO_RWIMSC 0x50
#define NMK_GPIO_FWIMSC 0x54
#define NMK_GPIO_WKS 0x58
/* These appear in DB8540 and later ASICs */
#define NMK_GPIO_EDGELEVEL 0x5C
#define NMK_GPIO_LEVEL 0x60
/* Pull up/down values */
enum
nmk_gpio_pull
{
NMK_GPIO_PULL_NONE
,
NMK_GPIO_PULL_UP
,
NMK_GPIO_PULL_DOWN
,
};
/* Sleep mode */
enum
nmk_gpio_slpm
{
NMK_GPIO_SLPM_INPUT
,
NMK_GPIO_SLPM_WAKEUP_ENABLE
=
NMK_GPIO_SLPM_INPUT
,
NMK_GPIO_SLPM_NOCHANGE
,
NMK_GPIO_SLPM_WAKEUP_DISABLE
=
NMK_GPIO_SLPM_NOCHANGE
,
};
struct
nmk_gpio_chip
{
struct
gpio_chip
chip
;
void
__iomem
*
addr
;
struct
clk
*
clk
;
unsigned
int
bank
;
void
(
*
set_ioforce
)(
bool
enable
);
spinlock_t
lock
;
bool
sleepmode
;
bool
is_mobileye_soc
;
/* Keep track of configured edges */
u32
edge_rising
;
u32
edge_falling
;
u32
real_wake
;
u32
rwimsc
;
u32
fwimsc
;
u32
rimsc
;
u32
fimsc
;
u32
pull_up
;
u32
lowemi
;
};
/* Alternate functions: function C is set in hw by setting both A and B */
#define NMK_GPIO_ALT_GPIO 0
#define NMK_GPIO_ALT_A 1
...
...
@@ -104,7 +165,7 @@ struct prcm_gpiocr_altcx_pin_desc {
struct
nmk_function
{
const
char
*
name
;
const
char
*
const
*
groups
;
unsigned
ngroups
;
unsigned
int
ngroups
;
};
/**
...
...
@@ -141,13 +202,13 @@ struct nmk_pingroup {
*/
struct
nmk_pinctrl_soc_data
{
const
struct
pinctrl_pin_desc
*
pins
;
unsigned
npins
;
unsigned
int
npins
;
const
struct
nmk_function
*
functions
;
unsigned
nfunctions
;
unsigned
int
nfunctions
;
const
struct
nmk_pingroup
*
groups
;
unsigned
ngroups
;
unsigned
int
ngroups
;
const
struct
prcm_gpiocr_altcx_pin_desc
*
altcx_pins
;
unsigned
npins_altcx
;
unsigned
int
npins_altcx
;
const
u16
*
prcm_gpiocr_registers
;
};
...
...
@@ -177,4 +238,42 @@ nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
#endif
#endif
/* PINCTRL_PINCTRL_NOMADIK_H */
#ifdef CONFIG_PINCTRL_DB8540
void
nmk_pinctrl_db8540_init
(
const
struct
nmk_pinctrl_soc_data
**
soc
);
#else
static
inline
void
nmk_pinctrl_db8540_init
(
const
struct
nmk_pinctrl_soc_data
**
soc
)
{
}
#endif
struct
platform_device
;
/*
* Symbols declared in gpio-nomadik used by pinctrl-nomadik. If pinctrl-nomadik
* is enabled, then gpio-nomadik is enabled as well; the reverse if not always
* true.
*/
void
nmk_gpio_dbg_show_one
(
struct
seq_file
*
s
,
struct
pinctrl_dev
*
pctldev
,
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
unsigned
int
gpio
);
void
__nmk_gpio_make_output
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
,
int
val
);
void
__nmk_gpio_set_slpm
(
struct
nmk_gpio_chip
*
nmk_chip
,
unsigned
int
offset
,
enum
nmk_gpio_slpm
mode
);
struct
nmk_gpio_chip
*
nmk_gpio_populate_chip
(
struct
fwnode_handle
*
fwnode
,
struct
platform_device
*
pdev
);
/* Symbols declared in pinctrl-nomadik used by gpio-nomadik. */
#ifdef CONFIG_PINCTRL_NOMADIK
extern
struct
nmk_gpio_chip
*
nmk_gpio_chips
[
NMK_MAX_BANKS
];
extern
spinlock_t
nmk_gpio_slpm_lock
;
int
__maybe_unused
nmk_prcm_gpiocr_get_mode
(
struct
pinctrl_dev
*
pctldev
,
int
gpio
);
#endif
#endif
/* __LINUX_GPIO_NOMADIK_H */
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