Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
110e2a38
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
110e2a38
编写于
12月 07, 2017
作者:
L
Linus Walleij
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'ib-move-axp209' into devel
上级
4070a534
e1190083
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
534 addition
and
197 deletion
+534
-197
Documentation/devicetree/bindings/gpio/gpio-axp209.txt
Documentation/devicetree/bindings/gpio/gpio-axp209.txt
+47
-2
drivers/gpio/Kconfig
drivers/gpio/Kconfig
+0
-6
drivers/gpio/Makefile
drivers/gpio/Makefile
+0
-1
drivers/gpio/gpio-axp209.c
drivers/gpio/gpio-axp209.c
+0
-188
drivers/pinctrl/Kconfig
drivers/pinctrl/Kconfig
+10
-0
drivers/pinctrl/Makefile
drivers/pinctrl/Makefile
+1
-0
drivers/pinctrl/pinctrl-axp209.c
drivers/pinctrl/pinctrl-axp209.c
+476
-0
未找到文件。
Documentation/devicetree/bindings/gpio/gpio-axp209.txt
浏览文件 @
110e2a38
AXP209 GPIO controller
AXP209 GPIO
& pinctrl
controller
This driver follows the usual GPIO bindings found in
Documentation/devicetree/bindings/gpio/gpio.txt
This driver follows the usual pinctrl bindings found in
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
This driver employs the per-pin muxing pattern.
Required properties:
- compatible: Should be "x-powers,axp209-gpio"
- compatible: Should be one of:
- "x-powers,axp209-gpio"
- "x-powers,axp813-gpio"
- #gpio-cells: Should be two. The first cell is the pin number and the
second is the GPIO flags.
- gpio-controller: Marks the device node as a GPIO controller.
...
...
@@ -28,3 +35,41 @@ axp209: pmic@34 {
#gpio-cells = <2>;
};
};
The GPIOs can be muxed to other functions and therefore, must be a subnode of
axp_gpio.
Example:
&axp_gpio {
gpio0_adc: gpio0-adc {
pins = "GPIO0";
function = "adc";
};
};
&example_node {
pinctrl-names = "default";
pinctrl-0 = <&gpio0_adc>;
};
GPIOs and their functions
-------------------------
Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does
not force GPIO1 and GPIO2 to be in gpio_in function as well).
axp209
------
GPIO | Functions
------------------------
GPIO0 | gpio_in, gpio_out, ldo, adc
GPIO1 | gpio_in, gpio_out, ldo, adc
GPIO2 | gpio_in, gpio_out
axp813
------
GPIO | Functions
------------------------
GPIO0 | gpio_in, gpio_out, ldo, adc
GPIO1 | gpio_in, gpio_out, ldo
drivers/gpio/Kconfig
浏览文件 @
110e2a38
...
...
@@ -122,12 +122,6 @@ config GPIO_ATH79
Select this option to enable GPIO driver for
Atheros AR71XX/AR724X/AR913X SoC devices.
config GPIO_AXP209
tristate "X-Powers AXP209 PMIC GPIO Support"
depends on MFD_AXP20X
help
Say yes to enable GPIO support for the AXP209 PMIC
config GPIO_BCM_KONA
bool "Broadcom Kona GPIO"
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
...
...
drivers/gpio/Makefile
浏览文件 @
110e2a38
...
...
@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA)
+=
gpio-arizona.o
obj-$(CONFIG_GPIO_ATH79)
+=
gpio-ath79.o
obj-$(CONFIG_GPIO_ASPEED)
+=
gpio-aspeed.o
obj-$(CONFIG_GPIO_AXP209)
+=
gpio-axp209.o
obj-$(CONFIG_GPIO_BCM_KONA)
+=
gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD9571MWV)
+=
gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB)
+=
gpio-brcmstb.o
...
...
drivers/gpio/gpio-axp209.c
已删除
100644 → 0
浏览文件 @
4070a534
/*
* AXP20x GPIO driver
*
* Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define AXP20X_GPIO_FUNCTIONS 0x7
#define AXP20X_GPIO_FUNCTION_OUT_LOW 0
#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1
#define AXP20X_GPIO_FUNCTION_INPUT 2
struct
axp20x_gpio
{
struct
gpio_chip
chip
;
struct
regmap
*
regmap
;
};
static
int
axp20x_gpio_get_reg
(
unsigned
offset
)
{
switch
(
offset
)
{
case
0
:
return
AXP20X_GPIO0_CTRL
;
case
1
:
return
AXP20X_GPIO1_CTRL
;
case
2
:
return
AXP20X_GPIO2_CTRL
;
}
return
-
EINVAL
;
}
static
int
axp20x_gpio_input
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
axp20x_gpio
*
gpio
=
gpiochip_get_data
(
chip
);
int
reg
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
reg
;
return
regmap_update_bits
(
gpio
->
regmap
,
reg
,
AXP20X_GPIO_FUNCTIONS
,
AXP20X_GPIO_FUNCTION_INPUT
);
}
static
int
axp20x_gpio_get
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
axp20x_gpio
*
gpio
=
gpiochip_get_data
(
chip
);
unsigned
int
val
;
int
ret
;
ret
=
regmap_read
(
gpio
->
regmap
,
AXP20X_GPIO20_SS
,
&
val
);
if
(
ret
)
return
ret
;
return
!!
(
val
&
BIT
(
offset
+
4
));
}
static
int
axp20x_gpio_get_direction
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
{
struct
axp20x_gpio
*
gpio
=
gpiochip_get_data
(
chip
);
unsigned
int
val
;
int
reg
,
ret
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
reg
;
ret
=
regmap_read
(
gpio
->
regmap
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
/*
* This shouldn't really happen if the pin is in use already,
* or if it's not in use yet, it doesn't matter since we're
* going to change the value soon anyway. Default to output.
*/
if
((
val
&
AXP20X_GPIO_FUNCTIONS
)
>
2
)
return
0
;
/*
* The GPIO directions are the three lowest values.
* 2 is input, 0 and 1 are output
*/
return
val
&
2
;
}
static
int
axp20x_gpio_output
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
value
)
{
struct
axp20x_gpio
*
gpio
=
gpiochip_get_data
(
chip
);
int
reg
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
reg
;
return
regmap_update_bits
(
gpio
->
regmap
,
reg
,
AXP20X_GPIO_FUNCTIONS
,
value
?
AXP20X_GPIO_FUNCTION_OUT_HIGH
:
AXP20X_GPIO_FUNCTION_OUT_LOW
);
}
static
void
axp20x_gpio_set
(
struct
gpio_chip
*
chip
,
unsigned
offset
,
int
value
)
{
axp20x_gpio_output
(
chip
,
offset
,
value
);
}
static
int
axp20x_gpio_probe
(
struct
platform_device
*
pdev
)
{
struct
axp20x_dev
*
axp20x
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
axp20x_gpio
*
gpio
;
int
ret
;
if
(
!
of_device_is_available
(
pdev
->
dev
.
of_node
))
return
-
ENODEV
;
if
(
!
axp20x
)
{
dev_err
(
&
pdev
->
dev
,
"Parent drvdata not set
\n
"
);
return
-
EINVAL
;
}
gpio
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
gpio
),
GFP_KERNEL
);
if
(
!
gpio
)
return
-
ENOMEM
;
gpio
->
chip
.
base
=
-
1
;
gpio
->
chip
.
can_sleep
=
true
;
gpio
->
chip
.
parent
=
&
pdev
->
dev
;
gpio
->
chip
.
label
=
dev_name
(
&
pdev
->
dev
);
gpio
->
chip
.
owner
=
THIS_MODULE
;
gpio
->
chip
.
get
=
axp20x_gpio_get
;
gpio
->
chip
.
get_direction
=
axp20x_gpio_get_direction
;
gpio
->
chip
.
set
=
axp20x_gpio_set
;
gpio
->
chip
.
direction_input
=
axp20x_gpio_input
;
gpio
->
chip
.
direction_output
=
axp20x_gpio_output
;
gpio
->
chip
.
ngpio
=
3
;
gpio
->
regmap
=
axp20x
->
regmap
;
ret
=
devm_gpiochip_add_data
(
&
pdev
->
dev
,
&
gpio
->
chip
,
gpio
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to register GPIO chip
\n
"
);
return
ret
;
}
dev_info
(
&
pdev
->
dev
,
"AXP209 GPIO driver loaded
\n
"
);
return
0
;
}
static
const
struct
of_device_id
axp20x_gpio_match
[]
=
{
{
.
compatible
=
"x-powers,axp209-gpio"
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
axp20x_gpio_match
);
static
struct
platform_driver
axp20x_gpio_driver
=
{
.
probe
=
axp20x_gpio_probe
,
.
driver
=
{
.
name
=
"axp20x-gpio"
,
.
of_match_table
=
axp20x_gpio_match
,
},
};
module_platform_driver
(
axp20x_gpio_driver
);
MODULE_AUTHOR
(
"Maxime Ripard <maxime.ripard@free-electrons.com>"
);
MODULE_DESCRIPTION
(
"AXP20x PMIC GPIO driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/pinctrl/Kconfig
浏览文件 @
110e2a38
...
...
@@ -63,6 +63,16 @@ config PINCTRL_AS3722
open drain configuration for the GPIO pins of AS3722 devices. It also
supports the GPIO functionality through gpiolib.
config PINCTRL_AXP209
tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support"
depends on MFD_AXP20X
help
AXP PMICs provides multiple GPIOs that can be muxed for different
functions. This driver bundles a pinctrl driver to select the function
muxing and a GPIO driver to handle the GPIO when the GPIO function is
selected.
Say yes to enable pinctrl and GPIO support for the AXP209 PMIC
config PINCTRL_BF54x
def_bool y if BF54x
select PINCTRL_ADI2
...
...
drivers/pinctrl/Makefile
浏览文件 @
110e2a38
...
...
@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_PINCTRL_ADI2)
+=
pinctrl-adi2.o
obj-$(CONFIG_PINCTRL_ARTPEC6)
+=
pinctrl-artpec6.o
obj-$(CONFIG_PINCTRL_AS3722)
+=
pinctrl-as3722.o
obj-$(CONFIG_PINCTRL_AXP209)
+=
pinctrl-axp209.o
obj-$(CONFIG_PINCTRL_BF54x)
+=
pinctrl-adi2-bf54x.o
obj-$(CONFIG_PINCTRL_BF60x)
+=
pinctrl-adi2-bf60x.o
obj-$(CONFIG_PINCTRL_AT91)
+=
pinctrl-at91.o
...
...
drivers/pinctrl/pinctrl-axp209.c
0 → 100644
浏览文件 @
110e2a38
/*
* AXP20x pinctrl and GPIO driver
*
* Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
* Copyright (C) 2017 Quentin Schulz <quentin.schulz@free-electrons.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define AXP20X_GPIO_FUNCTIONS 0x7
#define AXP20X_GPIO_FUNCTION_OUT_LOW 0
#define AXP20X_GPIO_FUNCTION_OUT_HIGH 1
#define AXP20X_GPIO_FUNCTION_INPUT 2
#define AXP20X_FUNC_GPIO_OUT 0
#define AXP20X_FUNC_GPIO_IN 1
#define AXP20X_FUNC_LDO 2
#define AXP20X_FUNC_ADC 3
#define AXP20X_FUNCS_NB 4
#define AXP20X_MUX_GPIO_OUT 0
#define AXP20X_MUX_GPIO_IN BIT(1)
#define AXP20X_MUX_ADC BIT(2)
#define AXP813_MUX_ADC (BIT(2) | BIT(0))
struct
axp20x_pctrl_desc
{
const
struct
pinctrl_pin_desc
*
pins
;
unsigned
int
npins
;
/* Stores the pins supporting LDO function. Bit offset is pin number. */
u8
ldo_mask
;
/* Stores the pins supporting ADC function. Bit offset is pin number. */
u8
adc_mask
;
u8
gpio_status_offset
;
u8
adc_mux
;
};
struct
axp20x_pinctrl_function
{
const
char
*
name
;
unsigned
int
muxval
;
const
char
**
groups
;
unsigned
int
ngroups
;
};
struct
axp20x_pctl
{
struct
gpio_chip
chip
;
struct
regmap
*
regmap
;
struct
pinctrl_dev
*
pctl_dev
;
struct
device
*
dev
;
const
struct
axp20x_pctrl_desc
*
desc
;
struct
axp20x_pinctrl_function
funcs
[
AXP20X_FUNCS_NB
];
};
static
const
struct
pinctrl_pin_desc
axp209_pins
[]
=
{
PINCTRL_PIN
(
0
,
"GPIO0"
),
PINCTRL_PIN
(
1
,
"GPIO1"
),
PINCTRL_PIN
(
2
,
"GPIO2"
),
};
static
const
struct
pinctrl_pin_desc
axp813_pins
[]
=
{
PINCTRL_PIN
(
0
,
"GPIO0"
),
PINCTRL_PIN
(
1
,
"GPIO1"
),
};
static
const
struct
axp20x_pctrl_desc
axp20x_data
=
{
.
pins
=
axp209_pins
,
.
npins
=
ARRAY_SIZE
(
axp209_pins
),
.
ldo_mask
=
BIT
(
0
)
|
BIT
(
1
),
.
adc_mask
=
BIT
(
0
)
|
BIT
(
1
),
.
gpio_status_offset
=
4
,
.
adc_mux
=
AXP20X_MUX_ADC
,
};
static
const
struct
axp20x_pctrl_desc
axp813_data
=
{
.
pins
=
axp813_pins
,
.
npins
=
ARRAY_SIZE
(
axp813_pins
),
.
ldo_mask
=
BIT
(
0
)
|
BIT
(
1
),
.
adc_mask
=
BIT
(
0
),
.
gpio_status_offset
=
0
,
.
adc_mux
=
AXP813_MUX_ADC
,
};
static
int
axp20x_gpio_get_reg
(
unsigned
int
offset
)
{
switch
(
offset
)
{
case
0
:
return
AXP20X_GPIO0_CTRL
;
case
1
:
return
AXP20X_GPIO1_CTRL
;
case
2
:
return
AXP20X_GPIO2_CTRL
;
}
return
-
EINVAL
;
}
static
int
axp20x_gpio_input
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
return
pinctrl_gpio_direction_input
(
chip
->
base
+
offset
);
}
static
int
axp20x_gpio_get
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
axp20x_pctl
*
pctl
=
gpiochip_get_data
(
chip
);
unsigned
int
val
;
int
ret
;
ret
=
regmap_read
(
pctl
->
regmap
,
AXP20X_GPIO20_SS
,
&
val
);
if
(
ret
)
return
ret
;
return
!!
(
val
&
BIT
(
offset
+
pctl
->
desc
->
gpio_status_offset
));
}
static
int
axp20x_gpio_get_direction
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
)
{
struct
axp20x_pctl
*
pctl
=
gpiochip_get_data
(
chip
);
unsigned
int
val
;
int
reg
,
ret
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
reg
;
ret
=
regmap_read
(
pctl
->
regmap
,
reg
,
&
val
);
if
(
ret
)
return
ret
;
/*
* This shouldn't really happen if the pin is in use already,
* or if it's not in use yet, it doesn't matter since we're
* going to change the value soon anyway. Default to output.
*/
if
((
val
&
AXP20X_GPIO_FUNCTIONS
)
>
2
)
return
0
;
/*
* The GPIO directions are the three lowest values.
* 2 is input, 0 and 1 are output
*/
return
val
&
2
;
}
static
int
axp20x_gpio_output
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
int
value
)
{
chip
->
set
(
chip
,
offset
,
value
);
return
0
;
}
static
void
axp20x_gpio_set
(
struct
gpio_chip
*
chip
,
unsigned
int
offset
,
int
value
)
{
struct
axp20x_pctl
*
pctl
=
gpiochip_get_data
(
chip
);
int
reg
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
;
regmap_update_bits
(
pctl
->
regmap
,
reg
,
AXP20X_GPIO_FUNCTIONS
,
value
?
AXP20X_GPIO_FUNCTION_OUT_HIGH
:
AXP20X_GPIO_FUNCTION_OUT_LOW
);
}
static
int
axp20x_pmx_set
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
offset
,
u8
config
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
int
reg
;
reg
=
axp20x_gpio_get_reg
(
offset
);
if
(
reg
<
0
)
return
reg
;
return
regmap_update_bits
(
pctl
->
regmap
,
reg
,
AXP20X_GPIO_FUNCTIONS
,
config
);
}
static
int
axp20x_pmx_func_cnt
(
struct
pinctrl_dev
*
pctldev
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
ARRAY_SIZE
(
pctl
->
funcs
);
}
static
const
char
*
axp20x_pmx_func_name
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
selector
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
pctl
->
funcs
[
selector
].
name
;
}
static
int
axp20x_pmx_func_groups
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
selector
,
const
char
*
const
**
groups
,
unsigned
int
*
num_groups
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
*
groups
=
pctl
->
funcs
[
selector
].
groups
;
*
num_groups
=
pctl
->
funcs
[
selector
].
ngroups
;
return
0
;
}
static
int
axp20x_pmx_set_mux
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
function
,
unsigned
int
group
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
unsigned
int
mask
;
/* Every pin supports GPIO_OUT and GPIO_IN functions */
if
(
function
<=
AXP20X_FUNC_GPIO_IN
)
return
axp20x_pmx_set
(
pctldev
,
group
,
pctl
->
funcs
[
function
].
muxval
);
if
(
function
==
AXP20X_FUNC_LDO
)
mask
=
pctl
->
desc
->
ldo_mask
;
else
mask
=
pctl
->
desc
->
adc_mask
;
if
(
!
(
BIT
(
group
)
&
mask
))
return
-
EINVAL
;
/*
* We let the regulator framework handle the LDO muxing as muxing bits
* are basically also regulators on/off bits. It's better not to enforce
* any state of the regulator when selecting LDO mux so that we don't
* interfere with the regulator driver.
*/
if
(
function
==
AXP20X_FUNC_LDO
)
return
0
;
return
axp20x_pmx_set
(
pctldev
,
group
,
pctl
->
funcs
[
function
].
muxval
);
}
static
int
axp20x_pmx_gpio_set_direction
(
struct
pinctrl_dev
*
pctldev
,
struct
pinctrl_gpio_range
*
range
,
unsigned
int
offset
,
bool
input
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
if
(
input
)
return
axp20x_pmx_set
(
pctldev
,
offset
,
pctl
->
funcs
[
AXP20X_FUNC_GPIO_IN
].
muxval
);
return
axp20x_pmx_set
(
pctldev
,
offset
,
pctl
->
funcs
[
AXP20X_FUNC_GPIO_OUT
].
muxval
);
}
static
const
struct
pinmux_ops
axp20x_pmx_ops
=
{
.
get_functions_count
=
axp20x_pmx_func_cnt
,
.
get_function_name
=
axp20x_pmx_func_name
,
.
get_function_groups
=
axp20x_pmx_func_groups
,
.
set_mux
=
axp20x_pmx_set_mux
,
.
gpio_set_direction
=
axp20x_pmx_gpio_set_direction
,
.
strict
=
true
,
};
static
int
axp20x_groups_cnt
(
struct
pinctrl_dev
*
pctldev
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
pctl
->
desc
->
npins
;
}
static
int
axp20x_group_pins
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
selector
,
const
unsigned
int
**
pins
,
unsigned
int
*
num_pins
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
*
pins
=
(
unsigned
int
*
)
&
pctl
->
desc
->
pins
[
selector
];
*
num_pins
=
1
;
return
0
;
}
static
const
char
*
axp20x_group_name
(
struct
pinctrl_dev
*
pctldev
,
unsigned
int
selector
)
{
struct
axp20x_pctl
*
pctl
=
pinctrl_dev_get_drvdata
(
pctldev
);
return
pctl
->
desc
->
pins
[
selector
].
name
;
}
static
const
struct
pinctrl_ops
axp20x_pctrl_ops
=
{
.
dt_node_to_map
=
pinconf_generic_dt_node_to_map_group
,
.
dt_free_map
=
pinconf_generic_dt_free_map
,
.
get_groups_count
=
axp20x_groups_cnt
,
.
get_group_name
=
axp20x_group_name
,
.
get_group_pins
=
axp20x_group_pins
,
};
static
void
axp20x_funcs_groups_from_mask
(
struct
device
*
dev
,
unsigned
int
mask
,
unsigned
int
mask_len
,
struct
axp20x_pinctrl_function
*
func
,
const
struct
pinctrl_pin_desc
*
pins
)
{
unsigned
long
int
mask_cpy
=
mask
;
const
char
**
group
;
unsigned
int
ngroups
=
hweight8
(
mask
);
int
bit
;
func
->
ngroups
=
ngroups
;
if
(
func
->
ngroups
>
0
)
{
func
->
groups
=
devm_kzalloc
(
dev
,
ngroups
*
sizeof
(
const
char
*
),
GFP_KERNEL
);
group
=
func
->
groups
;
for_each_set_bit
(
bit
,
&
mask_cpy
,
mask_len
)
{
*
group
=
pins
[
bit
].
name
;
group
++
;
}
}
}
static
void
axp20x_build_funcs_groups
(
struct
platform_device
*
pdev
)
{
struct
axp20x_pctl
*
pctl
=
platform_get_drvdata
(
pdev
);
int
i
,
pin
,
npins
=
pctl
->
desc
->
npins
;
pctl
->
funcs
[
AXP20X_FUNC_GPIO_OUT
].
name
=
"gpio_out"
;
pctl
->
funcs
[
AXP20X_FUNC_GPIO_OUT
].
muxval
=
AXP20X_MUX_GPIO_OUT
;
pctl
->
funcs
[
AXP20X_FUNC_GPIO_IN
].
name
=
"gpio_in"
;
pctl
->
funcs
[
AXP20X_FUNC_GPIO_IN
].
muxval
=
AXP20X_MUX_GPIO_IN
;
pctl
->
funcs
[
AXP20X_FUNC_LDO
].
name
=
"ldo"
;
/*
* Muxval for LDO is useless as we won't use it.
* See comment in axp20x_pmx_set_mux.
*/
pctl
->
funcs
[
AXP20X_FUNC_ADC
].
name
=
"adc"
;
pctl
->
funcs
[
AXP20X_FUNC_ADC
].
muxval
=
pctl
->
desc
->
adc_mux
;
/* Every pin supports GPIO_OUT and GPIO_IN functions */
for
(
i
=
0
;
i
<=
AXP20X_FUNC_GPIO_IN
;
i
++
)
{
pctl
->
funcs
[
i
].
ngroups
=
npins
;
pctl
->
funcs
[
i
].
groups
=
devm_kzalloc
(
&
pdev
->
dev
,
npins
*
sizeof
(
char
*
),
GFP_KERNEL
);
for
(
pin
=
0
;
pin
<
npins
;
pin
++
)
pctl
->
funcs
[
i
].
groups
[
pin
]
=
pctl
->
desc
->
pins
[
pin
].
name
;
}
axp20x_funcs_groups_from_mask
(
&
pdev
->
dev
,
pctl
->
desc
->
ldo_mask
,
npins
,
&
pctl
->
funcs
[
AXP20X_FUNC_LDO
],
pctl
->
desc
->
pins
);
axp20x_funcs_groups_from_mask
(
&
pdev
->
dev
,
pctl
->
desc
->
adc_mask
,
npins
,
&
pctl
->
funcs
[
AXP20X_FUNC_ADC
],
pctl
->
desc
->
pins
);
}
static
const
struct
of_device_id
axp20x_pctl_match
[]
=
{
{
.
compatible
=
"x-powers,axp209-gpio"
,
.
data
=
&
axp20x_data
,
},
{
.
compatible
=
"x-powers,axp813-gpio"
,
.
data
=
&
axp813_data
,
},
{
}
};
MODULE_DEVICE_TABLE
(
of
,
axp20x_pctl_match
);
static
int
axp20x_pctl_probe
(
struct
platform_device
*
pdev
)
{
struct
axp20x_dev
*
axp20x
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
axp20x_pctl
*
pctl
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
pinctrl_desc
*
pctrl_desc
;
int
ret
;
if
(
!
of_device_is_available
(
pdev
->
dev
.
of_node
))
return
-
ENODEV
;
if
(
!
axp20x
)
{
dev_err
(
&
pdev
->
dev
,
"Parent drvdata not set
\n
"
);
return
-
EINVAL
;
}
pctl
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pctl
),
GFP_KERNEL
);
if
(
!
pctl
)
return
-
ENOMEM
;
pctl
->
chip
.
base
=
-
1
;
pctl
->
chip
.
can_sleep
=
true
;
pctl
->
chip
.
request
=
gpiochip_generic_request
;
pctl
->
chip
.
free
=
gpiochip_generic_free
;
pctl
->
chip
.
parent
=
&
pdev
->
dev
;
pctl
->
chip
.
label
=
dev_name
(
&
pdev
->
dev
);
pctl
->
chip
.
owner
=
THIS_MODULE
;
pctl
->
chip
.
get
=
axp20x_gpio_get
;
pctl
->
chip
.
get_direction
=
axp20x_gpio_get_direction
;
pctl
->
chip
.
set
=
axp20x_gpio_set
;
pctl
->
chip
.
direction_input
=
axp20x_gpio_input
;
pctl
->
chip
.
direction_output
=
axp20x_gpio_output
;
pctl
->
chip
.
ngpio
=
pctl
->
desc
->
npins
;
pctl
->
desc
=
(
struct
axp20x_pctrl_desc
*
)
of_device_get_match_data
(
dev
);
pctl
->
regmap
=
axp20x
->
regmap
;
pctl
->
dev
=
&
pdev
->
dev
;
platform_set_drvdata
(
pdev
,
pctl
);
axp20x_build_funcs_groups
(
pdev
);
pctrl_desc
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
pctrl_desc
),
GFP_KERNEL
);
if
(
!
pctrl_desc
)
return
-
ENOMEM
;
pctrl_desc
->
name
=
dev_name
(
&
pdev
->
dev
);
pctrl_desc
->
owner
=
THIS_MODULE
;
pctrl_desc
->
pins
=
pctl
->
desc
->
pins
;
pctrl_desc
->
npins
=
pctl
->
desc
->
npins
;
pctrl_desc
->
pctlops
=
&
axp20x_pctrl_ops
;
pctrl_desc
->
pmxops
=
&
axp20x_pmx_ops
;
pctl
->
pctl_dev
=
devm_pinctrl_register
(
&
pdev
->
dev
,
pctrl_desc
,
pctl
);
if
(
IS_ERR
(
pctl
->
pctl_dev
))
{
dev_err
(
&
pdev
->
dev
,
"couldn't register pinctrl driver
\n
"
);
return
PTR_ERR
(
pctl
->
pctl_dev
);
}
ret
=
devm_gpiochip_add_data
(
&
pdev
->
dev
,
&
pctl
->
chip
,
pctl
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to register GPIO chip
\n
"
);
return
ret
;
}
ret
=
gpiochip_add_pin_range
(
&
pctl
->
chip
,
dev_name
(
&
pdev
->
dev
),
pctl
->
desc
->
pins
->
number
,
pctl
->
desc
->
pins
->
number
,
pctl
->
desc
->
npins
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"failed to add pin range
\n
"
);
return
ret
;
}
dev_info
(
&
pdev
->
dev
,
"AXP209 pinctrl and GPIO driver loaded
\n
"
);
return
0
;
}
static
struct
platform_driver
axp20x_pctl_driver
=
{
.
probe
=
axp20x_pctl_probe
,
.
driver
=
{
.
name
=
"axp20x-gpio"
,
.
of_match_table
=
axp20x_pctl_match
,
},
};
module_platform_driver
(
axp20x_pctl_driver
);
MODULE_AUTHOR
(
"Maxime Ripard <maxime.ripard@free-electrons.com>"
);
MODULE_AUTHOR
(
"Quentin Schulz <quentin.schulz@free-electrons.com>"
);
MODULE_DESCRIPTION
(
"AXP20x PMIC pinctrl and GPIO driver"
);
MODULE_LICENSE
(
"GPL"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录