| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 | // SPDX-License-Identifier: GPL-2.0+/* * Copyright (c) 2013 Xilinx, Michal Simek */#include <common.h>#include <errno.h>#include <malloc.h>#include <linux/list.h>#include <asm/io.h>#include <asm/gpio.h>static LIST_HEAD(gpio_list);enum gpio_direction {	GPIO_DIRECTION_OUT = 0,	GPIO_DIRECTION_IN = 1,};/* Gpio simple map */struct gpio_regs {	u32 gpiodata;	u32 gpiodir;};#define GPIO_NAME_SIZE	10struct gpio_names {	char name[GPIO_NAME_SIZE];};/* Initialized, rxbd_current, rx_first_buf must be 0 after init */struct xilinx_gpio_priv {	struct gpio_regs *regs;	u32 gpio_min;	u32 gpio_max;	u32 gpiodata_store;	char name[GPIO_NAME_SIZE];	struct list_head list;	struct gpio_names *gpio_name;};/* Store number of allocated gpio pins */static u32 xilinx_gpio_max;/* Get associated gpio controller */static struct xilinx_gpio_priv *gpio_get_controller(unsigned gpio){	struct list_head *entry;	struct xilinx_gpio_priv *priv = NULL;	list_for_each(entry, &gpio_list) {		priv = list_entry(entry, struct xilinx_gpio_priv, list);		if (gpio >= priv->gpio_min && gpio <= priv->gpio_max) {			debug("%s: reg: %x, min-max: %d-%d\n", __func__,			      (u32)priv->regs, priv->gpio_min, priv->gpio_max);			return priv;		}	}	puts("!!!Can't get gpio controller!!!\n");	return NULL;}/* Get gpio pin name if used/setup */static char *get_name(unsigned gpio){	u32 gpio_priv;	struct xilinx_gpio_priv *priv;	debug("%s\n", __func__);	priv = gpio_get_controller(gpio);	if (priv) {		gpio_priv = gpio - priv->gpio_min;		return *priv->gpio_name[gpio_priv].name ?			priv->gpio_name[gpio_priv].name : "UNKNOWN";	}	return "UNKNOWN";}/* Get output value */static int gpio_get_output_value(unsigned gpio){	u32 val, gpio_priv;	struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);	if (priv) {		gpio_priv = gpio - priv->gpio_min;		val = !!(priv->gpiodata_store & (1 << gpio_priv));		debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,		      (u32)priv->regs, gpio_priv, val);		return val;	}	return -1;}/* Get input value */static int gpio_get_input_value(unsigned gpio){	u32 val, gpio_priv;	struct gpio_regs *regs;	struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);	if (priv) {		regs = priv->regs;		gpio_priv = gpio - priv->gpio_min;		val = readl(®s->gpiodata);		val = !!(val & (1 << gpio_priv));		debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,		      (u32)priv->regs, gpio_priv, val);		return val;	}	return -1;}/* Set gpio direction */static int gpio_set_direction(unsigned gpio, enum gpio_direction direction){	u32 val, gpio_priv;	struct gpio_regs *regs;	struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);	if (priv) {		regs = priv->regs;		val = readl(®s->gpiodir);		gpio_priv = gpio - priv->gpio_min;		if (direction == GPIO_DIRECTION_OUT)			val &= ~(1 << gpio_priv);		else			val |= 1 << gpio_priv;		writel(val, ®s->gpiodir);		debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,		      (u32)priv->regs, gpio_priv, val);		return 0;	}	return -1;}/* Get gpio direction */static int gpio_get_direction(unsigned gpio){	u32 val, gpio_priv;	struct gpio_regs *regs;	struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);	if (priv) {		regs = priv->regs;		gpio_priv = gpio - priv->gpio_min;		val = readl(®s->gpiodir);		val = !!(val & (1 << gpio_priv));		debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,		      (u32)priv->regs, gpio_priv, val);		return val;	}	return -1;}/* * Get input value * for example gpio setup to output only can't get input value * which is breaking gpio toggle command */int gpio_get_value(unsigned gpio){	u32 val;	if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)		val = gpio_get_output_value(gpio);	else		val = gpio_get_input_value(gpio);	return val;}/* Set output value */static int gpio_set_output_value(unsigned gpio, int value){	u32 val, gpio_priv;	struct gpio_regs *regs;	struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);	if (priv) {		regs = priv->regs;		gpio_priv = gpio - priv->gpio_min;		val = priv->gpiodata_store;		if (value)			val |= 1 << gpio_priv;		else			val &= ~(1 << gpio_priv);		writel(val, ®s->gpiodata);		debug("%s: reg: %x, gpio_no: %d, output_val: %d\n", __func__,		      (u32)priv->regs, gpio_priv, val);		priv->gpiodata_store = val;		return 0;	}	return -1;}int gpio_set_value(unsigned gpio, int value){	if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)		return gpio_set_output_value(gpio, value);	return -1;}/* Set GPIO as input */int gpio_direction_input(unsigned gpio){	debug("%s\n", __func__);	return gpio_set_direction(gpio, GPIO_DIRECTION_IN);}/* Setup GPIO as output and set output value */int gpio_direction_output(unsigned gpio, int value){	int ret = gpio_set_direction(gpio, GPIO_DIRECTION_OUT);	debug("%s\n", __func__);	if (ret < 0)		return ret;	return gpio_set_output_value(gpio, value);}/* Show gpio status */void gpio_info(void){	unsigned gpio;	struct list_head *entry;	struct xilinx_gpio_priv *priv = NULL;	list_for_each(entry, &gpio_list) {		priv = list_entry(entry, struct xilinx_gpio_priv, list);		printf("\n%s: %s/%x (%d-%d)\n", __func__, priv->name,		       (u32)priv->regs, priv->gpio_min, priv->gpio_max);		for (gpio = priv->gpio_min; gpio <= priv->gpio_max; gpio++) {			printf("GPIO_%d:\t%s is an ", gpio, get_name(gpio));			if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)				printf("OUTPUT value = %d\n",				       gpio_get_output_value(gpio));			else				printf("INPUT value = %d\n",				       gpio_get_input_value(gpio));		}	}}int gpio_request(unsigned gpio, const char *label){	u32 gpio_priv;	struct xilinx_gpio_priv *priv;	if (gpio >= xilinx_gpio_max)		return -EINVAL;	priv = gpio_get_controller(gpio);	if (priv) {		gpio_priv = gpio - priv->gpio_min;		if (label != NULL) {			strncpy(priv->gpio_name[gpio_priv].name, label,				GPIO_NAME_SIZE);			priv->gpio_name[gpio_priv].name[GPIO_NAME_SIZE - 1] =					'\0';		}		return 0;	}	return -1;}int gpio_free(unsigned gpio){	u32 gpio_priv;	struct xilinx_gpio_priv *priv;	if (gpio >= xilinx_gpio_max)		return -EINVAL;	priv = gpio_get_controller(gpio);	if (priv) {		gpio_priv = gpio - priv->gpio_min;		priv->gpio_name[gpio_priv].name[0] = '\0';		/* Do nothing here */		return 0;	}	return -1;}int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no){	struct xilinx_gpio_priv *priv;	priv = calloc(1, sizeof(struct xilinx_gpio_priv));	/* Setup gpio name */	if (name != NULL) {		strncpy(priv->name, name, GPIO_NAME_SIZE);		priv->name[GPIO_NAME_SIZE - 1] = '\0';	}	priv->regs = (struct gpio_regs *)baseaddr;	priv->gpio_min = xilinx_gpio_max;	xilinx_gpio_max = priv->gpio_min + gpio_no;	priv->gpio_max = xilinx_gpio_max - 1;	priv->gpio_name = calloc(gpio_no, sizeof(struct gpio_names));	INIT_LIST_HEAD(&priv->list);	list_add_tail(&priv->list, &gpio_list);	printf("%s: Add %s (%d-%d)\n", __func__, name,	       priv->gpio_min, priv->gpio_max);	/* Return the first gpio allocated for this device */	return priv->gpio_min;}/* Dual channel gpio is one IP with two independent channels */int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0, u32 gpio_no1){	int ret;	ret = gpio_alloc(baseaddr, name, gpio_no0);	gpio_alloc(baseaddr + 8, strcat((char *)name, "_1"), gpio_no1);	/* Return the first gpio allocated for this device */	return ret;}
 |