1696 lines
52 KiB
C
Executable File
1696 lines
52 KiB
C
Executable File
/*
|
|
* Allwinner SoCs pinctrl driver.
|
|
*
|
|
* Copyright (C) 2013 Shaorui Huang
|
|
*
|
|
* Shaorui Huang<huangshr@allwinnertech.com>
|
|
* 2013-06-10 add sunxi pinctrl testing case.
|
|
*
|
|
* WimHuang<huangwei@allwinnertech.com>
|
|
* 2015-07-20 transplant it from linux-3.4 to linux-3.10.
|
|
*
|
|
* This file is licensed under the terms of the GNU General Public
|
|
* License version 2. This program is licensed "as is" without any
|
|
* warranty of any kind, whether express or implied.
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/sunxi-gpio.h>
|
|
|
|
#include "../core.h"
|
|
|
|
#define SUNXI_DEV_NAME_MAX_LEN 20
|
|
#define SUNXI_FUNC_NAME_MAX_LEN 80
|
|
|
|
struct sunxi_pctrltest_data {
|
|
char dev_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
char exec[SUNXI_FUNC_NAME_MAX_LEN];
|
|
struct completion done;
|
|
int result;
|
|
int gpio_index;
|
|
int funcs;
|
|
int pull;
|
|
int data;
|
|
int dlevel;
|
|
};
|
|
|
|
struct sunxi_pctrltest_case {
|
|
const char *name;
|
|
int (*func)(void);
|
|
};
|
|
|
|
/*
|
|
* struct sunxi_gpio_config - gpio config info
|
|
* @name: gpio name
|
|
* @mul_sel: multi sel val: 0 - input, 1 - output.
|
|
* @pull: pull val: 0 - pull up/down disable, 1 - pull up
|
|
* @drive: driver level val: 0 - level 0, 1 - level 1
|
|
* @data: data val: 0 - low, 1 - high, only valid when mul_sel is input/output
|
|
*/
|
|
struct sunxi_gpio_config {
|
|
const char *name;
|
|
u32 mulsel;
|
|
u32 pull;
|
|
u32 drive;
|
|
u32 data;
|
|
};
|
|
|
|
static struct sunxi_pctrltest_data *sunxi_ptest_data;
|
|
|
|
static int dt_node_to_gpio(struct device_node *np_cfg,
|
|
struct sunxi_gpio_config **gpio_list,
|
|
unsigned *gpio_count)
|
|
{
|
|
struct property *prop = NULL;
|
|
const char *name = NULL;
|
|
int val;
|
|
int i = 0;
|
|
|
|
*gpio_count = of_property_count_strings(np_cfg, "allwinner,pins");
|
|
if (*gpio_count < 0) {
|
|
pr_warn("missing allwinner,pins property in node %s\n",
|
|
np_cfg->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
*gpio_list = kmalloc_array(*gpio_count, sizeof(struct sunxi_gpio_config), GFP_KERNEL);
|
|
if (!*gpio_list) {
|
|
pr_warn("No enougt memory for gpio_list\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
of_property_for_each_string(np_cfg, "allwinner,pins", prop, name) {
|
|
(*gpio_list)[i].name = name;
|
|
|
|
if (of_property_read_u32(np_cfg, "allwinner,muxsel", &val)) {
|
|
pr_warn("missing allwinner,mux property in node %s\n",
|
|
np_cfg->name);
|
|
return -EINVAL;
|
|
}
|
|
(*gpio_list)[i].mulsel = val;
|
|
|
|
if (of_property_read_u32(np_cfg, "allwinner,drive", &val)) {
|
|
pr_warn("missing allwinner,dirve property in node %s\n",
|
|
np_cfg->name);
|
|
return -EINVAL;
|
|
}
|
|
(*gpio_list)[i].drive = val;
|
|
|
|
if (of_property_read_u32(np_cfg, "allwinner,pull", &val)) {
|
|
pr_warn("missing allwinner,pull property in node %s\n",
|
|
np_cfg->name);
|
|
return -EINVAL;
|
|
}
|
|
(*gpio_list)[i].pull = val;
|
|
|
|
if (of_property_read_u32(np_cfg, "allwinner,data", &val)) {
|
|
pr_warn("missing allwinner,data property in node %s\n",
|
|
np_cfg->name);
|
|
return -EINVAL;
|
|
}
|
|
(*gpio_list)[i].data = val;
|
|
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dt_get_gpio_list(struct device_node *np,
|
|
struct sunxi_gpio_config **gpio_list,
|
|
unsigned *gpio_count)
|
|
{
|
|
struct property *prop;
|
|
int size;
|
|
const __be32 *list;
|
|
struct device_node *np_cfg;
|
|
phandle phandle;
|
|
int ret;
|
|
int i;
|
|
|
|
/* only need pin whose state is default */
|
|
prop = of_find_property(np, "pinctrl-0", &size);
|
|
if (!prop) {
|
|
pr_warn("missing pinctrl-0 property in node %s\n", np->name);
|
|
return -EINVAL;
|
|
}
|
|
list = prop->value;
|
|
size /= sizeof(*list);
|
|
|
|
/* For every referenced pin configuration node in it */
|
|
for (i = 0; i < size; i++) {
|
|
phandle = be32_to_cpup(list++);
|
|
|
|
/* Look up the pin configuration node */
|
|
np_cfg = of_find_node_by_phandle(phandle);
|
|
if (!np_cfg) {
|
|
pr_warn("prop %s index 0 invalid phandle\n", prop->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Parse the node */
|
|
ret = dt_node_to_gpio(np_cfg, gpio_list, gpio_count);
|
|
if (ret < 0)
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static irqreturn_t sunxi_pinctrl_irq_handler_demo1(int irq, void *dev_id)
|
|
{
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("%s: demo1 for test pinctrl repeat eint api.\n", __func__);
|
|
pr_warn("-----------------------------------------------\n");
|
|
disable_irq_nosync(irq);
|
|
complete(&sunxi_ptest_data->done);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t sunxi_pinctrl_irq_handler_demo2(int irq, void *dev_id)
|
|
{
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("%s: demo2 for test pinctrl repeat eint api.\n", __func__);
|
|
pr_warn("-----------------------------------------------\n");
|
|
disable_irq_nosync(irq);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int pctrltest_request_all_resource(void)
|
|
{
|
|
struct device *dev;
|
|
struct device_node *node;
|
|
struct pinctrl *pinctrl;
|
|
struct sunxi_gpio_config *gpio_list = NULL;
|
|
struct sunxi_gpio_config *gpio_cfg;
|
|
unsigned gpio_count = 0;
|
|
unsigned gpio_index;
|
|
unsigned long config;
|
|
int ret;
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
node = of_find_node_by_type(NULL, dev_name(dev));
|
|
if (!node) {
|
|
pr_warn("find node for device [%s] failed...\n", dev_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
dev->of_node = node;
|
|
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] all pin resource we want to request\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: request pin all resource.\n");
|
|
pinctrl = devm_pinctrl_get_select_default(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn("request pinctrl handle for device [%s] failed...\n", dev_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: get device[%s] pin count.\n", dev_name(dev));
|
|
ret = dt_get_gpio_list(node, &gpio_list, &gpio_count);
|
|
if (ret < 0 || gpio_count == 0) {
|
|
pr_warn(" devices own 0 pin resource or look for main key failed!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: get device[%s] pin configure and check.\n", dev_name(dev));
|
|
for (gpio_index = 0; gpio_index < gpio_count; gpio_index++) {
|
|
gpio_cfg = &gpio_list[gpio_index];
|
|
|
|
/*check function config */
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config);
|
|
if (gpio_cfg->mulsel != SUNXI_PINCFG_UNPACK_VALUE(config)) {
|
|
pr_warn("failed! mul value isn't equal as dt.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*check pull config */
|
|
if (gpio_cfg->pull != GPIO_PULL_DEFAULT) {
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config);
|
|
if (gpio_cfg->pull != SUNXI_PINCFG_UNPACK_VALUE(config)) {
|
|
pr_warn("failed! pull value isn't equal as dt.\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
/*check dlevel config */
|
|
if (gpio_cfg->drive != GPIO_DRVLVL_DEFAULT) {
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config);
|
|
if (gpio_cfg->drive != SUNXI_PINCFG_UNPACK_VALUE(config)) {
|
|
pr_warn("failed! dlevel value isn't equal as dt.\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
/*check data config */
|
|
if (gpio_cfg->data != GPIO_DATA_DEFAULT) {
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config);
|
|
if (gpio_cfg->data != SUNXI_PINCFG_UNPACK_VALUE(config)) {
|
|
pr_warn("failed! pin data value isn't equal as dt.\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl request all resource success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_re_request_all_resource(void)
|
|
{
|
|
struct device *dev;
|
|
struct device_node *node;
|
|
struct pinctrl *pinctrl_1;
|
|
struct pinctrl *pinctrl_2;
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
node = of_find_node_by_type(NULL, dev_name(dev));
|
|
if (!node) {
|
|
pr_warn("find node for device [%s] failed...\n", dev_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
dev->of_node = node;
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] all pin resource we want to repeat request\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: first time request pin all resource.\n");
|
|
/*request all resource */
|
|
pinctrl_1 = devm_pinctrl_get_select_default(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl_1)) {
|
|
pr_warn("request pinctrl handle for device [%s] failed!\n", dev_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*repeat request */
|
|
pr_warn("step2: secondary request pin all resource.\n");
|
|
pinctrl_2 = devm_pinctrl_get_select_default(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl_2)) {
|
|
pr_warn("repeat request device[%s] all pin resource failed\n", dev_name(dev));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl repeat request all resource success.\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_request_gpio(void)
|
|
{
|
|
int req_status;
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
/* request signal pin as gpio*/
|
|
pr_warn("step1: pinctrl request gpio[%s]\n", pin_name);
|
|
req_status = pinctrl_request_gpio(gpio_index);
|
|
if (req_status != 0) {
|
|
pr_warn("pinctrl request gpio failed! return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" pinctrl request gpio[%s] success\n", pin_name);
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl request gpio api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_free_gpio(void)
|
|
{
|
|
int req_status;
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
/*request signal pin as gpio*/
|
|
pr_warn("step1: pinctrl request gpio[%s]\n", pin_name);
|
|
req_status = pinctrl_request_gpio(gpio_index);
|
|
if (req_status != 0) {
|
|
pr_warn("pinctrl request gpio failed !return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" pinctrl request gpio[%s]success\n", pin_name);
|
|
|
|
pr_warn("step2: pinctrl free gpio[%s]\n", pin_name);
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
pr_warn("step3: pinctrl request the same gpio[%s] again..\n", pin_name);
|
|
req_status = pinctrl_request_gpio(gpio_index);
|
|
if (req_status != 0) {
|
|
pr_warn("pinctrl request gpio failed !return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" pinctrl request gpio[%s] again success.\n", pin_name);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl free gpio api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_lookup_state(void)
|
|
{
|
|
struct device *dev;
|
|
struct pinctrl *pinctrl;
|
|
struct pinctrl_state *state;
|
|
char device_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_set_name(dev, sunxi_ptest_data->dev_name);
|
|
strcpy(device_name, sunxi_ptest_data->dev_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] test lookup state api\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: get pinctrl handle.\n");
|
|
pinctrl = pinctrl_get(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn("get pinctrl handle [%s] failed...,return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: printk pinctrl current state.\n");
|
|
pr_warn(" device: %s current state: %s\n", dev_name(pinctrl->dev),
|
|
pinctrl->state ? pinctrl->state->name : "none");
|
|
|
|
pr_warn("step3: pinctrl lookup state(default state name: default).\n");
|
|
state = pinctrl_lookup_state(pinctrl, "default");
|
|
if (IS_ERR(state)) {
|
|
pr_warn("can not find state: default.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: check the state we lookup if the one needed.\n");
|
|
if (strcmp(state->name, "default")) {
|
|
pr_warn("find state,but isn't the one we need.\n");
|
|
return -EINVAL;
|
|
}
|
|
pinctrl_put(pinctrl);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl look up state api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_select_state(void)
|
|
{
|
|
struct device *dev;
|
|
struct pinctrl *pinctrl;
|
|
struct pinctrl_state *state;
|
|
char device_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
int req_status;
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_set_name(dev, sunxi_ptest_data->dev_name);
|
|
strcpy(device_name, sunxi_ptest_data->dev_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] test select state api\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: get pinctrl handle.\n");
|
|
pinctrl = pinctrl_get(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn("get pinctrl handle [%s] failed..., return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: printk pinctrl current state.\n");
|
|
pr_warn(" device: %s current state: %s\n", dev_name(pinctrl->dev),
|
|
pinctrl->state ? pinctrl->state->name : "none");
|
|
|
|
pr_warn("step3: pinctrl lookup state(default state name: default).\n");
|
|
state = pinctrl_lookup_state(pinctrl, "default");
|
|
if (IS_ERR(state)) {
|
|
pinctrl_put(pinctrl);
|
|
pr_warn("can not find state: default.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: check the state we lookup if the one needed.\n");
|
|
if (strcmp(state->name, "default")) {
|
|
pinctrl_put(pinctrl);
|
|
pr_warn("find state,but isn't the one we need.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step5: select state for pinctrl handle.\n");
|
|
req_status = pinctrl_select_state(pinctrl, state);
|
|
if (req_status < 0) {
|
|
pinctrl_put(pinctrl);
|
|
pr_warn("pinctrl select state failed. return value %d.\n", req_status);
|
|
}
|
|
pinctrl_put(pinctrl);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl select state api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_get(void)
|
|
{
|
|
struct device *dev;
|
|
struct pinctrl *pinctrl;
|
|
struct pinctrl_state *state;
|
|
struct pinctrl_setting *setting;
|
|
char device_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_set_name(dev, sunxi_ptest_data->dev_name);
|
|
strcpy(device_name, sunxi_ptest_data->dev_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] test pinctrl get api\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: get pinctrl handle.\n");
|
|
pinctrl = pinctrl_get(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn("get pinctrl handle [%s] failed..., return value %ld\n",
|
|
dev_name(dev), PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: check pinctrl handle we have getted.\n");
|
|
if (dev_name(dev) != dev_name(pinctrl->dev)) {
|
|
pinctrl_put(pinctrl);
|
|
pr_warn("check: pinctrl handle isn't that one we want\n ");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: get current statep.\n");
|
|
pr_warn(" device: %s current state: %s\n", dev_name(pinctrl->dev),
|
|
pinctrl->state ? pinctrl->state->name : "none");
|
|
list_for_each_entry(state, &pinctrl->states, node) {
|
|
pr_warn("state: %s\n", state->name);
|
|
list_for_each_entry(setting, &state->settings, node) {
|
|
struct pinctrl_dev *pctldev = setting->pctldev;
|
|
|
|
pr_warn(" setting type: %d pin controller %s\n",
|
|
setting->type, pinctrl_dev_get_name(pctldev));
|
|
}
|
|
}
|
|
pinctrl_put(pinctrl);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl get api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_put(void)
|
|
{
|
|
struct device *dev;
|
|
struct pinctrl *pinctrl;
|
|
struct pinctrl_state *state;
|
|
struct pinctrl_setting *setting;
|
|
char device_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_set_name(dev, sunxi_ptest_data->dev_name);
|
|
strcpy(device_name, sunxi_ptest_data->dev_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] test pinctrl put api\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: get pinctrl handle.\n");
|
|
pinctrl = pinctrl_get(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn("get pinctrl handle [%s] failed...,return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: check pinctrl handle we have getted.\n");
|
|
if (dev_name(dev) != dev_name(pinctrl->dev)) {
|
|
pinctrl_put(pinctrl);
|
|
pr_warn("check: pinctrl handle isn't that one we want\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: get current statep.\n");
|
|
pr_warn(" device: %s current state: %s\n", dev_name(pinctrl->dev),
|
|
pinctrl->state ? pinctrl->state->name : "none");
|
|
list_for_each_entry(state, &pinctrl->states, node) {
|
|
pr_warn("state: %s\n", state->name);
|
|
list_for_each_entry(setting, &state->settings, node) {
|
|
struct pinctrl_dev *pctldev = setting->pctldev;
|
|
|
|
pr_warn(" setting type: %d pin controller %s\n",
|
|
setting->type, pinctrl_dev_get_name(pctldev));
|
|
}
|
|
}
|
|
|
|
pr_warn("step4: free pinctrl handle we have getted.\n");
|
|
pinctrl_put(pinctrl);
|
|
|
|
pr_warn("step5: then repeat get. if get success, previous free operate success.\n");
|
|
pinctrl = pinctrl_get(dev);
|
|
if (IS_ERR_OR_NULL(pinctrl)) {
|
|
pr_warn(" after free, we repeat get pinctrl handle [%s] failed..., return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
pinctrl_put(pinctrl);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl put api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_devm_get_and_put(void)
|
|
{
|
|
struct device *dev;
|
|
struct pinctrl *pinctrl;
|
|
struct pinctrl_state *state;
|
|
struct pinctrl_setting *setting;
|
|
char device_name[SUNXI_DEV_NAME_MAX_LEN];
|
|
|
|
dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name);
|
|
if (!dev) {
|
|
pr_warn("find device [%s] failed...\n", sunxi_ptest_data->dev_name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_set_name(dev, sunxi_ptest_data->dev_name);
|
|
strcpy(device_name, sunxi_ptest_data->dev_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("device[%s] test pinctrl devm get and put api\n", dev_name(dev));
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: devm get pinctrl handle.\n");
|
|
pinctrl = devm_pinctrl_get(dev);
|
|
if (IS_ERR(pinctrl)) {
|
|
pr_warn("get pinctrl handle [%s] failed..., return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: check pinctrl handle we have getted.\n");
|
|
if (dev_name(dev) != dev_name(pinctrl->dev)) {
|
|
devm_pinctrl_put(pinctrl);
|
|
pr_warn("check: pinctrl handle isn't that one we want\n ");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: get current statep.\n");
|
|
pr_warn(" device: %s current state: %s\n", dev_name(pinctrl->dev),
|
|
pinctrl->state ? pinctrl->state->name : "none");
|
|
list_for_each_entry(state, &pinctrl->states, node) {
|
|
pr_warn("state: %s\n", state->name);
|
|
list_for_each_entry(setting, &state->settings, node) {
|
|
struct pinctrl_dev *pctldev = setting->pctldev;
|
|
|
|
pr_warn(" setting type: %d pin controller %s\n",
|
|
setting->type, pinctrl_dev_get_name(pctldev));
|
|
}
|
|
}
|
|
|
|
pr_warn("step4: devm free pinctrl handle we have getted.\n");
|
|
devm_pinctrl_put(pinctrl);
|
|
|
|
pr_warn("step5: then repeat get. if get success, previous free operate success.\n");
|
|
pinctrl = devm_pinctrl_get(dev);
|
|
if (IS_ERR(pinctrl)) {
|
|
pr_warn(" after free,we repeat get pinctrl handle [%s] failed..., return value %ld\n",
|
|
device_name, PTR_ERR(pinctrl));
|
|
return -EINVAL;
|
|
}
|
|
devm_pinctrl_put(pinctrl);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl devm get and put api success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_function_set(void)
|
|
{
|
|
unsigned long config_set;
|
|
unsigned long config_get;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int func;
|
|
|
|
func = sunxi_ptest_data->funcs;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("pin function we want to set:\n");
|
|
pr_warn(" gpio name: %s gpio index: %d gpio function: %d\n",
|
|
pin_name, sunxi_ptest_data->gpio_index, func);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*check if pin mul setting right */
|
|
pr_warn("step1: get [%s] function value.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
pr_warn(" [%s] function value: %ld\n", pin_name, SUNXI_PINCFG_UNPACK_VALUE(config_get));
|
|
|
|
pr_warn("step2: set [%s] function value to %d\n", pin_name, func);
|
|
config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, func);
|
|
pin_config_set(SUNXI_PINCTRL, pin_name, config_set);
|
|
|
|
pr_warn("step3: get [%s] function value and check.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
if (func != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {
|
|
pr_warn("test pin config for mul setting failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl function set success !\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_data_set(void)
|
|
{
|
|
unsigned long config_set;
|
|
unsigned long config_get;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int data;
|
|
|
|
data = sunxi_ptest_data->data;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("pin data we want to set:\n");
|
|
pr_warn(" gpio name: %s gpio index: %d gpio data: %d\n",
|
|
pin_name, sunxi_ptest_data->gpio_index, data);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*check if pin data setting right */
|
|
pr_warn("step1: get [%s] data value.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
pr_warn(" [%s] data value: %ld\n", pin_name, SUNXI_PINCFG_UNPACK_VALUE(config_get));
|
|
|
|
pr_warn("step2: set [%s] data value to %d\n", pin_name, data);
|
|
config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, data);
|
|
pin_config_set(SUNXI_PINCTRL, pin_name, config_set);
|
|
|
|
pr_warn("step3: get [%s] data value and check.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
if (data != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {
|
|
pr_warn("test pin config for dlevel setting failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl data set success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_pull_set(void)
|
|
{
|
|
unsigned long config_set;
|
|
unsigned long config_get;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int pull;
|
|
|
|
pull = sunxi_ptest_data->pull;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("pin data we want to set:\n");
|
|
pr_warn(" gpio name: %s gpio index: %d gpio pull: %d\n",
|
|
pin_name, sunxi_ptest_data->gpio_index, pull);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*check if pin pull setting right */
|
|
pr_warn("step1: get [%s] pull value.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
pr_warn(" [%s] pull value: %ld\n", pin_name, SUNXI_PINCFG_UNPACK_VALUE(config_get));
|
|
|
|
pr_warn("step2: set [%s] pull value to %d\n", pin_name, pull);
|
|
config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pull);
|
|
pin_config_set(SUNXI_PINCTRL, pin_name, config_set);
|
|
|
|
pr_warn("step3: get [%s] function value and check.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
if (pull != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {
|
|
pr_warn("test pin config for pull setting failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl pull set success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_dlevel_set(void)
|
|
{
|
|
unsigned long config_set;
|
|
unsigned long config_get;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int dlevel;
|
|
|
|
dlevel = sunxi_ptest_data->dlevel;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("pin data we want to set:\n");
|
|
pr_warn(" gpio name: %s gpio index: %d gpio dlevel: %d\n",
|
|
pin_name, sunxi_ptest_data->gpio_index, dlevel);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*check if pin dlevel setting right */
|
|
pr_warn("step1: get [%s] dlevel value.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
pr_warn(" [%s] dlevel value: %ld\n", pin_name, SUNXI_PINCFG_UNPACK_VALUE(config_get));
|
|
|
|
pr_warn("step2: set [%s] dlevel value to %d\n", pin_name, dlevel);
|
|
config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, dlevel);
|
|
pin_config_set(SUNXI_PINCTRL, pin_name, config_set);
|
|
|
|
pr_warn("step3: get [%s] dlevel value and check.\n", pin_name);
|
|
config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, 0XFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config_get);
|
|
if (dlevel != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {
|
|
pr_warn("test pin config for dlevel setting failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pinctrl drive level set success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_direction_input(void)
|
|
{
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int req_status;
|
|
int direct_status;
|
|
unsigned long config;
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pinctrl_free_gpio(gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: Pinctrl request gpio.\n");
|
|
req_status = pinctrl_request_gpio(gpio_index);
|
|
if (req_status != 0) {
|
|
pr_warn("pinctrl request gpio failed !return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: Set gpio direction input.\n");
|
|
direct_status = pinctrl_gpio_direction_input(gpio_index);
|
|
if (IS_ERR_VALUE(direct_status)) {
|
|
pr_warn("set pinctrl gpio direction input failed! return value: %d\n",
|
|
direct_status);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: Get pin mux value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 0) {
|
|
pr_warn("check: set pin direction input failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: Pinctrl free gpio.\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio direction input success!\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_direction_output(void)
|
|
{
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int req_status;
|
|
int direct_status;
|
|
unsigned long config;
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
pr_warn("step1: Pinctrl request gpio.\n");
|
|
req_status = pinctrl_request_gpio(gpio_index);
|
|
if (req_status != 0) {
|
|
pr_warn("pinctrl request gpio failed !return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: Set gpio direction output.\n");
|
|
direct_status = pinctrl_gpio_direction_output(gpio_index);
|
|
if (IS_ERR_VALUE(direct_status)) {
|
|
pr_warn("set pinctrl gpio direction output failed! return value: %d\n",
|
|
direct_status);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: Get pin mux value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 1) {
|
|
pr_warn("check: set pinctrl gpio direction output failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: Pinctrl free gpio.\n");
|
|
pinctrl_free_gpio(gpio_index);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio direction output success!\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_request_eint(void)
|
|
{
|
|
int ret;
|
|
int virq;
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int trigger;
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
reinit_completion(&sunxi_ptest_data->done);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: request gpio [%s].\n", pin_name);
|
|
ret = gpio_request(gpio_index, NULL);
|
|
if (ret != 0) {
|
|
pr_warn("gpio request failed\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
gpio_direction_input(gpio_index);
|
|
trigger = gpio_get_value_cansleep(gpio_index);
|
|
pr_warn("step2: get gpio[%s] trigger level:0x%x\n", pin_name, trigger);
|
|
trigger = trigger ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW;
|
|
gpio_free(gpio_index);
|
|
|
|
pr_warn("step3: generate virtual irq number.\n");
|
|
virq = gpio_to_irq(gpio_index);
|
|
if (IS_ERR_VALUE(virq)) {
|
|
pr_warn("map gpio [%d] to virq [%d] failed !\n ", gpio_index, virq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: request irq(%s level).\n",
|
|
trigger == IRQF_TRIGGER_HIGH ? "high" : "low");
|
|
ret = request_irq(virq, sunxi_pinctrl_irq_handler_demo1,
|
|
trigger, "PIN_EINT", NULL);
|
|
if (IS_ERR_VALUE(ret)) {
|
|
pr_warn("request irq failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step5: wait for irq.\n");
|
|
ret = wait_for_completion_timeout(&sunxi_ptest_data->done, HZ);
|
|
if (ret == 0) {
|
|
pr_warn("wait for irq timeout!\n");
|
|
free_irq(virq, NULL);
|
|
return -EINVAL;
|
|
}
|
|
|
|
free_irq(virq, NULL);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test pin eint success !\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pctrltest_re_request_eint(void)
|
|
{
|
|
int ret;
|
|
int virq;
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int trigger;
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: request gpio [%s].\n", pin_name);
|
|
ret = gpio_request(gpio_index, NULL);
|
|
if (ret != 0) {
|
|
pr_warn("gpio request failed\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
gpio_direction_input(gpio_index);
|
|
trigger = gpio_get_value_cansleep(gpio_index);
|
|
pr_warn("step2: get gpio[%s] trigger level:0x%x\n", pin_name, trigger);
|
|
trigger = trigger ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW;
|
|
gpio_free(gpio_index);
|
|
|
|
pr_warn("step3: generate virtual irq number.\n");
|
|
virq = gpio_to_irq(gpio_index);
|
|
if (IS_ERR_VALUE(virq)) {
|
|
pr_warn("map gpio [%d] to virq [%d] failed !\n ", gpio_index, virq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step4: first time request irq(%s level trigger).\n",
|
|
trigger == IRQF_TRIGGER_HIGH ? "high" : "low");
|
|
|
|
ret = request_irq(virq, sunxi_pinctrl_irq_handler_demo1,
|
|
trigger, "PIN_EINT", NULL);
|
|
if (IS_ERR_VALUE(ret)) {
|
|
free_irq(virq, NULL);
|
|
pr_warn("test pin request irq failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step5: repeat request irq(%s level trigger).\n",
|
|
trigger == IRQF_TRIGGER_HIGH ? "high" : "low");
|
|
ret = request_irq(virq, sunxi_pinctrl_irq_handler_demo2,
|
|
trigger, "PIN_EINT", NULL);
|
|
free_irq(virq, NULL);
|
|
if (!IS_ERR_VALUE(ret)) {
|
|
pr_warn(" repeat request irq success!\n\n");
|
|
pr_warn("test failed! for repeat request is umpermitted.\n");
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" repeat request irq failed!\n");
|
|
pr_warn("test success! for repeat request is umpermitted.\n");
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test picntrl repeat eint success!\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int gpiotest_request_free(void)
|
|
{
|
|
int gpio_index;
|
|
int req_status;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: request gpio[%s]\n", pin_name);
|
|
gpio_free(gpio_index);
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed !return value %d\n", req_status);
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" request gpio[%s] success\n", pin_name);
|
|
|
|
pr_warn("step2: free gpio[%s]\n", pin_name);
|
|
gpio_free(gpio_index);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio request and free success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int gpiotest_re_request_free(void)
|
|
{
|
|
int gpio_index;
|
|
int req_status;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
pr_warn("step1: first time request gpio[%s]\n", pin_name);
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn(" first time request gpio [%s]failed !\n", pin_name);
|
|
return -EINVAL;
|
|
}
|
|
pr_warn(" first time request gpio[%s] success!\n", pin_name);
|
|
|
|
pr_warn("step2: repeat request gpio[%s]\n", pin_name);
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (!req_status) {
|
|
pr_warn(" repeat request gpio[%s] success.\n", pin_name);
|
|
pr_warn("test failed: for repeat request is unpermitted.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn(" repeat request gpio [%s] failed.\n", pin_name);
|
|
pr_warn("test success: for repeat request is unpermitted.\n");
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio repeat request and free success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
gpio_free(gpio_index);
|
|
return 0;
|
|
}
|
|
|
|
static int gpiotest_set_debounce(void)
|
|
{
|
|
int gpio_index;
|
|
int req_status;
|
|
int get_status;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*
|
|
* test gpio set debounce api
|
|
*/
|
|
pr_warn("step1: request gpio.\n");
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: set gpio debounce value 0x11.\n");
|
|
get_status = gpio_set_debounce(gpio_index, 0x11);
|
|
if (get_status) {
|
|
pr_warn(" gpio set debounce failed! return value: %d\n", get_status);
|
|
gpio_free(gpio_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step3: gpio free.\n");
|
|
gpio_free(gpio_index);
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio set debounce success!\n");
|
|
pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
}
|
|
|
|
static int gpiotest_gpiolib(void)
|
|
{
|
|
int gpio_index;
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
int req_status;
|
|
int set_direct_status;
|
|
unsigned long config;
|
|
int val;
|
|
|
|
gpio_index = sunxi_ptest_data->gpio_index;
|
|
sunxi_gpio_to_name(gpio_index, pin_name);
|
|
|
|
pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++\n", __func__);
|
|
pr_warn("gpio name is : %s gpio index is : %d\n", pin_name, gpio_index);
|
|
pr_warn("-----------------------------------------------\n");
|
|
|
|
/*
|
|
* test gpio set direction input api
|
|
*/
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("1. test gpio direction input api:\n");
|
|
pr_warn("step1: request gpio.\n");
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed !\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: set gpio direction input.\n");
|
|
set_direct_status = gpio_direction_input(gpio_index);
|
|
if (IS_ERR_VALUE(set_direct_status)) {
|
|
pr_warn("set gpio direction input failed!\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step3: get gpio mux value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 0) {
|
|
pr_warn("test gpio set direction input failed !\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
gpio_free(gpio_index);
|
|
pr_warn("step4: gpio free.\n");
|
|
pr_warn("finish API(gpio_direction_input)testing.\n");
|
|
pr_warn("-----------------------------------------------\n\n");
|
|
|
|
/*
|
|
* test gpio set direction output api
|
|
*/
|
|
pr_warn("2. test gpio direction output api:\n");
|
|
pr_warn("step1: request gpio.\n");
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: set gpio direction output(data value 1).\n");
|
|
set_direct_status = gpio_direction_output(gpio_index, 1);
|
|
if (IS_ERR_VALUE(set_direct_status)) {
|
|
pr_warn("set gpio direction output failed!\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step3: get gpio mux value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 1) {
|
|
pr_warn("faile!FUNC value not the same as expectation.\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step4: get gpio data value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 1) {
|
|
pr_warn("failed!DATA value not the same as expectation(1).\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step5: set gpio direction output(data value 0).\n");
|
|
set_direct_status = gpio_direction_output(gpio_index, 0);
|
|
if (IS_ERR_VALUE(set_direct_status)) {
|
|
pr_warn("set gpio direction output failed!\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step6: get gpio data value and check.\n");
|
|
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0xFFFF);
|
|
pin_config_get(SUNXI_PINCTRL, pin_name, &config);
|
|
if (SUNXI_PINCFG_UNPACK_VALUE(config) != 0) {
|
|
pr_warn("failed!DATA value not the same as expectation(0).\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
gpio_free(gpio_index);
|
|
pr_warn("step7: gpio free.\n");
|
|
pr_warn("finish API(gpio_direction_output)testing.\n");
|
|
pr_warn("-----------------------------------------------\n\n");
|
|
|
|
/*
|
|
* test gpio get value api
|
|
*/
|
|
pr_warn("3. test gpio get value api:\n");
|
|
pr_warn("step1: request gpio.\n");
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: set gpio direction output(data value 0).\n");
|
|
set_direct_status = gpio_direction_output(gpio_index, 0);
|
|
if (IS_ERR_VALUE(set_direct_status)) {
|
|
pr_warn("set gpio direction output failed !\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
pr_warn("step3: get gpio data value and check.\n");
|
|
val = __gpio_get_value(gpio_index);
|
|
pr_warn(" gpio data value : %d\n", val);
|
|
if (val != 0) {
|
|
pr_warn("failed!DATA value not the same as expectation.\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
gpio_free(gpio_index);
|
|
pr_warn("step4: gpio free.\n");
|
|
pr_warn("finish API(gpio_get_value)testing.\n");
|
|
pr_warn("-----------------------------------------------\n\n");
|
|
|
|
/*
|
|
* test gpio set value api
|
|
*/
|
|
pr_warn("4. test gpio set value api:\n");
|
|
pr_warn("step1: request gpio.\n");
|
|
req_status = gpio_request(gpio_index, NULL);
|
|
if (req_status != 0) {
|
|
pr_warn("gpio request failed!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pr_warn("step2: set gpio direction output(set data value 0).\n");
|
|
set_direct_status = gpio_direction_output(gpio_index, 0);
|
|
if (IS_ERR_VALUE(set_direct_status)) {
|
|
pr_warn("set gpio direction output failed\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step3: get gpio data value,then set 1 and check.\n");
|
|
val = __gpio_get_value(gpio_index);
|
|
pr_warn(" get gpio data value : %d\n", val);
|
|
__gpio_set_value(gpio_index, 1);
|
|
pr_warn(" set gpio data value : 1\n");
|
|
val = __gpio_get_value(gpio_index);
|
|
pr_warn(" get gpio data value : %d\n", val);
|
|
if (val != 1) {
|
|
pr_warn("test gpio set dat value 1 failed !\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
pr_warn("step4: get gpio data value,then set 0 and check.\n");
|
|
val = __gpio_get_value(gpio_index);
|
|
pr_warn(" get gpio data value : %d\n", val);
|
|
__gpio_set_value(gpio_index, 0);
|
|
pr_warn(" set gpio data value : 0\n");
|
|
val = __gpio_get_value(gpio_index);
|
|
pr_warn(" get gpio data value : %d\n", val);
|
|
if (val != 0) {
|
|
pr_warn("test gpio set dat value 0 failed!\n");
|
|
goto test_gpiolib_api_failed;
|
|
}
|
|
|
|
gpio_free(gpio_index);
|
|
pr_warn("step5: gpio free.\n");
|
|
pr_warn("finish API(gpio_set_value)testing.\n");
|
|
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio gpiolib success!\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
return 0;
|
|
|
|
test_gpiolib_api_failed:
|
|
pr_warn("-----------------------------------------------\n");
|
|
pr_warn("test gpio gpiolib failed!\n");
|
|
pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++\n\n");
|
|
gpio_free(gpio_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static struct sunxi_pctrltest_case sunxi_ptest_case[] = {
|
|
{"pctrltest_request_all_resource", pctrltest_request_all_resource},
|
|
{"pctrltest_re_request_all_resource", pctrltest_re_request_all_resource},
|
|
{"pctrltest_request_gpio", pctrltest_request_gpio},
|
|
{"pctrltest_free_gpio", pctrltest_free_gpio},
|
|
{"pctrltest_lookup_state", pctrltest_lookup_state},
|
|
{"pctrltest_select_state", pctrltest_select_state},
|
|
{"pctrltest_get", pctrltest_get},
|
|
{"pctrltest_put", pctrltest_put},
|
|
{"pctrltest_devm_get_and_put", pctrltest_devm_get_and_put},
|
|
{"pctrltest_function_set", pctrltest_function_set},
|
|
{"pctrltest_data_set", pctrltest_data_set},
|
|
{"pctrltest_pull_set", pctrltest_pull_set},
|
|
{"pctrltest_dlevel_set", pctrltest_dlevel_set},
|
|
{"pctrltest_direction_input", pctrltest_direction_input},
|
|
{"pctrltest_direction_output", pctrltest_direction_output},
|
|
{"pctrltest_request_eint", pctrltest_request_eint},
|
|
{"pctrltest_re_request_eint", pctrltest_re_request_eint},
|
|
{"gpiotest_request_free", gpiotest_request_free},
|
|
{"gpiotest_re_request_free", gpiotest_re_request_free},
|
|
{"gpiotest_set_debounce", gpiotest_set_debounce},
|
|
{"gpiotest_gpiolib", gpiotest_gpiolib},
|
|
};
|
|
|
|
static ssize_t show_funcs(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", sunxi_ptest_data->funcs);
|
|
}
|
|
|
|
static ssize_t show_data(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", sunxi_ptest_data->data);
|
|
}
|
|
|
|
static ssize_t show_pull(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", sunxi_ptest_data->pull);
|
|
}
|
|
|
|
static ssize_t show_dlevel(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", sunxi_ptest_data->dlevel);
|
|
}
|
|
|
|
static ssize_t show_gpio_index(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
char pin_name[SUNXI_PIN_NAME_MAX_LEN];
|
|
|
|
sunxi_gpio_to_name(sunxi_ptest_data->gpio_index, pin_name);
|
|
return sprintf(buf, "%s\n", pin_name);
|
|
}
|
|
|
|
static ssize_t show_dev_name(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%s\n", sunxi_ptest_data->dev_name);
|
|
}
|
|
|
|
static ssize_t show_result(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return sprintf(buf, "%d\n", sunxi_ptest_data->result);
|
|
}
|
|
|
|
static ssize_t show_exec(struct class *class, struct class_attribute *attr,
|
|
char *buf)
|
|
{
|
|
int i;
|
|
int total_len = 0;
|
|
struct sunxi_pctrltest_case *p = sunxi_ptest_case;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sunxi_ptest_case); i++, p++) {
|
|
total_len += snprintf(buf + total_len, SUNXI_FUNC_NAME_MAX_LEN,
|
|
"%s\n", p->name);
|
|
if (total_len > PAGE_SIZE - SUNXI_FUNC_NAME_MAX_LEN) {
|
|
pr_warn("can't show so many exec funcs.\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return total_len;
|
|
}
|
|
|
|
static int get_parameter(const char *buf, int *data, size_t size)
|
|
{
|
|
char *after;
|
|
size_t count;
|
|
int tmp;
|
|
|
|
tmp = simple_strtoul(buf, &after, 10);
|
|
count = after - buf;
|
|
|
|
if (isspace(*after))
|
|
count++;
|
|
|
|
if (count == size) {
|
|
*data = tmp;
|
|
return size;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int get_exec_number(void)
|
|
{
|
|
int i;
|
|
struct sunxi_pctrltest_case *p = sunxi_ptest_case;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sunxi_ptest_case); i++, p++) {
|
|
if (strcmp(p->name, sunxi_ptest_data->exec) == 0)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t store_funcs(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->funcs, count);
|
|
}
|
|
|
|
static ssize_t store_data(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->data, count);
|
|
}
|
|
|
|
static ssize_t store_pull(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->pull, count);
|
|
}
|
|
|
|
static ssize_t store_dlevel(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->dlevel, count);
|
|
}
|
|
|
|
static ssize_t store_gpio_index(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->gpio_index, count);
|
|
}
|
|
|
|
static ssize_t store_dev_name(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
|
|
if (count > SUNXI_DEV_NAME_MAX_LEN) {
|
|
pr_warn("sunxi dev name max len less than 20 char.\n");
|
|
return -EINVAL;
|
|
}
|
|
ret = strlcpy(sunxi_ptest_data->dev_name, buf, count);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t store_result(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
return get_parameter(buf, &sunxi_ptest_data->result, count);
|
|
}
|
|
|
|
static ssize_t store_exec(struct class *class, struct class_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
int ret;
|
|
int number;
|
|
|
|
if (count > SUNXI_FUNC_NAME_MAX_LEN) {
|
|
pr_warn("sunxi func name max len less than 80 char.\n");
|
|
return -EINVAL;
|
|
}
|
|
ret = strlcpy(sunxi_ptest_data->exec, buf, count);
|
|
number = get_exec_number();
|
|
if (number < 0) {
|
|
pr_warn("can't find exec number.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
sunxi_ptest_data->result = sunxi_ptest_case[number].func();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct class_attribute sunxi_pctrltest_attrs[] = {
|
|
__ATTR(data, S_IRUGO | S_IWUSR, show_data, store_data),
|
|
__ATTR(dlevel, S_IRUGO | S_IWUSR, show_dlevel, store_dlevel),
|
|
__ATTR(funcs, S_IRUGO | S_IWUSR, show_funcs, store_funcs),
|
|
__ATTR(pull, S_IRUGO | S_IWUSR, show_pull, store_pull),
|
|
__ATTR(gpio_index, S_IRUGO | S_IWUSR, show_gpio_index, store_gpio_index),
|
|
__ATTR(dev_name, S_IRUGO | S_IWUSR, show_dev_name, store_dev_name),
|
|
__ATTR(exec, S_IRUGO | S_IWUSR, show_exec, store_exec),
|
|
__ATTR(result, S_IRUGO, show_result, store_result),
|
|
__ATTR_NULL,
|
|
};
|
|
|
|
static struct class sunxi_pctrltest_class = {
|
|
.name = "sunxi_pinctrl_test",
|
|
.owner = THIS_MODULE,
|
|
.class_attrs = sunxi_pctrltest_attrs,
|
|
};
|
|
|
|
static int sunxi_pctrltest_probe(struct platform_device *pdev)
|
|
{
|
|
struct device_node *np = pdev->dev.of_node;
|
|
struct gpio_config config;
|
|
int gpio;
|
|
int ret;
|
|
|
|
if (np == NULL) {
|
|
pr_err("Vdevice failed to get of_node\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
gpio = of_get_named_gpio_flags(np, "test-gpios", 0,
|
|
(enum of_gpio_flags *)&config);
|
|
if (!gpio_is_valid(gpio)) {
|
|
pr_err("Vdevice failed to get test-gpios\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
sunxi_ptest_data = devm_kzalloc(&pdev->dev,
|
|
sizeof(struct sunxi_pctrltest_data),
|
|
GFP_KERNEL);
|
|
if (!sunxi_ptest_data)
|
|
return -ENOMEM;
|
|
|
|
ret = class_register(&sunxi_pctrltest_class);
|
|
if (ret < 0) {
|
|
pr_err("register sunxi pinctrl test class failed: %d\n", ret);
|
|
return -EBUSY;
|
|
}
|
|
|
|
pdev->dev.class = &sunxi_pctrltest_class;
|
|
dev_set_name(&pdev->dev, "Vdevice");
|
|
platform_set_drvdata(pdev, sunxi_ptest_data);
|
|
|
|
/* Set default parameters */
|
|
strlcpy(sunxi_ptest_data->dev_name, "Vdevice", SUNXI_DEV_NAME_MAX_LEN);
|
|
sunxi_ptest_data->result = -1;
|
|
sunxi_ptest_data->gpio_index = config.gpio;
|
|
sunxi_ptest_data->funcs = config.mul_sel;
|
|
sunxi_ptest_data->pull = config.pull;
|
|
sunxi_ptest_data->dlevel = config.drv_level;
|
|
sunxi_ptest_data->data = config.data;
|
|
init_completion(&sunxi_ptest_data->done);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int sunxi_pctrltest_remove(struct platform_device *pdev)
|
|
{
|
|
class_unregister(&sunxi_pctrltest_class);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id sunxi_pctrltest_match[] = {
|
|
{ .compatible = "allwinner,sun8i-vdevice"},
|
|
{ .compatible = "allwinner,sun50i-vdevice"},
|
|
{}
|
|
};
|
|
|
|
static struct platform_driver sunxi_pctrltest_driver = {
|
|
.probe = sunxi_pctrltest_probe,
|
|
.remove = sunxi_pctrltest_remove,
|
|
.driver = {
|
|
.name = "Vdevice",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = sunxi_pctrltest_match,
|
|
},
|
|
};
|
|
|
|
static int __init sunxi_pctrltest_init(void)
|
|
{
|
|
int ret;
|
|
ret = platform_driver_register(&sunxi_pctrltest_driver);
|
|
if (IS_ERR_VALUE(ret)) {
|
|
pr_warn("register sunxi pinctrl platform driver failed\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit sunxi_pctrltest_exit(void)
|
|
{
|
|
platform_driver_unregister(&sunxi_pctrltest_driver);
|
|
}
|
|
|
|
module_init(sunxi_pctrltest_init);
|
|
module_exit(sunxi_pctrltest_exit);
|
|
MODULE_AUTHOR("Wim Hwang<huangwei@allwinnertech.com");
|
|
MODULE_AUTHOR("Huangshr<huangshr@allwinnertech.com");
|
|
MODULE_DESCRIPTION("Allwinner SUNXI Pinctrl driver test");
|
|
MODULE_LICENSE("GPL");
|