mirror of https://gitee.com/openkylin/linux.git
Merge branch 'gpio-reserved-ranges' into devel
This commit is contained in:
commit
89b0b4e2d3
|
@ -151,9 +151,9 @@ in a lot of designs, some using all 32 bits, some using 18 and some using
|
|||
first 18 GPIOs, at local offset 0 .. 17, are in use.
|
||||
|
||||
If these GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an
|
||||
additional bitmask is needed to specify which GPIOs are actually in use,
|
||||
and which are dummies. The bindings for this case has not yet been
|
||||
specified, but should be specified if/when such hardware appears.
|
||||
additional set of tuples is needed to specify which GPIOs are unusable, with
|
||||
the gpio-reserved-ranges binding. This property indicates the start and size
|
||||
of the GPIOs that can't be used.
|
||||
|
||||
Optionally, a GPIO controller may have a "gpio-line-names" property. This is
|
||||
an array of strings defining the names of the GPIO lines going out of the
|
||||
|
@ -178,6 +178,7 @@ gpio-controller@00000000 {
|
|||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <18>;
|
||||
gpio-reserved-ranges = <0 4>, <12 2>;
|
||||
gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
|
||||
"LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
|
||||
"Row A", "Row B", "Row C", "Row D", "NMI button",
|
||||
|
|
|
@ -511,6 +511,28 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
|
|||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_remove);
|
||||
|
||||
static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
|
||||
{
|
||||
int len, i;
|
||||
u32 start, count;
|
||||
struct device_node *np = chip->of_node;
|
||||
|
||||
len = of_property_count_u32_elems(np, "gpio-reserved-ranges");
|
||||
if (len < 0 || len % 2 != 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
of_property_read_u32_index(np, "gpio-reserved-ranges",
|
||||
i, &start);
|
||||
of_property_read_u32_index(np, "gpio-reserved-ranges",
|
||||
i + 1, &count);
|
||||
if (start >= chip->ngpio || start + count >= chip->ngpio)
|
||||
continue;
|
||||
|
||||
bitmap_clear(chip->valid_mask, start, count);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
{
|
||||
|
@ -615,6 +637,8 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
|
||||
return -EINVAL;
|
||||
|
||||
of_gpiochip_init_valid_mask(chip);
|
||||
|
||||
status = of_gpiochip_add_pin_range(chip);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
|
@ -337,6 +337,57 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
|
||||
{
|
||||
unsigned long *p;
|
||||
|
||||
p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
bitmap_fill(p, chip->ngpio);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
int size;
|
||||
struct device_node *np = gpiochip->of_node;
|
||||
|
||||
size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
|
||||
if (size > 0 && size % 2 == 0)
|
||||
gpiochip->need_valid_mask = true;
|
||||
#endif
|
||||
|
||||
if (!gpiochip->need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip);
|
||||
if (!gpiochip->valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
kfree(gpiochip->valid_mask);
|
||||
gpiochip->valid_mask = NULL;
|
||||
}
|
||||
|
||||
bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->valid_mask))
|
||||
return true;
|
||||
return test_bit(offset, gpiochip->valid_mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
|
||||
|
||||
/*
|
||||
* GPIO line handle management
|
||||
*/
|
||||
|
@ -1261,6 +1312,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
|||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = gpiochip_init_valid_mask(chip);
|
||||
if (status)
|
||||
goto err_remove_irqchip_mask;
|
||||
|
||||
status = gpiochip_add_irqchip(chip, lock_key, request_key);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
|
@ -1290,6 +1345,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
|||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_free_hogs(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
err_remove_irqchip_mask:
|
||||
gpiochip_irqchip_free_valid_mask(chip);
|
||||
err_remove_from_list:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
@ -1346,6 +1403,7 @@ void gpiochip_remove(struct gpio_chip *chip)
|
|||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
/*
|
||||
* We accept no more calls into the driver from this point, so
|
||||
* NULL the driver data pointer
|
||||
|
@ -1506,14 +1564,10 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
|||
if (!gpiochip->irq.need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip);
|
||||
if (!gpiochip->irq.valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1526,6 +1580,8 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
|
|||
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (!gpiochip_line_is_valid(gpiochip, offset))
|
||||
return false;
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->irq.valid_mask))
|
||||
return true;
|
||||
|
|
|
@ -105,6 +105,14 @@ static const struct pinctrl_ops msm_pinctrl_ops = {
|
|||
.dt_free_map = pinctrl_utils_free_map,
|
||||
};
|
||||
|
||||
static int msm_pinmux_request(struct pinctrl_dev *pctldev, unsigned offset)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct gpio_chip *chip = &pctrl->chip;
|
||||
|
||||
return gpiochip_line_is_valid(chip, offset) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int msm_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
@ -166,6 +174,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|||
}
|
||||
|
||||
static const struct pinmux_ops msm_pinmux_ops = {
|
||||
.request = msm_pinmux_request,
|
||||
.get_functions_count = msm_get_functions_count,
|
||||
.get_function_name = msm_get_function_name,
|
||||
.get_function_groups = msm_get_function_groups,
|
||||
|
@ -506,6 +515,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
|||
"pull up"
|
||||
};
|
||||
|
||||
if (!gpiochip_line_is_valid(chip, offset))
|
||||
return;
|
||||
|
||||
g = &pctrl->soc->groups[offset];
|
||||
ctl_reg = readl(pctrl->regs + g->ctl_reg);
|
||||
|
||||
|
@ -517,6 +529,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
|||
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
|
||||
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
|
||||
seq_printf(s, " %s", pulls[pull]);
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
|
@ -524,10 +537,8 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
unsigned gpio = chip->base;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++) {
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++)
|
||||
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -808,6 +819,46 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
|
||||
struct msm_pinctrl *pctrl)
|
||||
{
|
||||
int ret;
|
||||
unsigned int len, i;
|
||||
unsigned int max_gpios = pctrl->soc->ngpios;
|
||||
u16 *tmp;
|
||||
|
||||
/* The number of GPIOs in the ACPI tables */
|
||||
len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (ret > max_gpios)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
|
||||
if (ret < 0) {
|
||||
dev_err(pctrl->dev, "could not read list of GPIOs\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
bitmap_zero(chip->valid_mask, max_gpios);
|
||||
for (i = 0; i < len; i++)
|
||||
set_bit(tmp[i], chip->valid_mask);
|
||||
|
||||
out:
|
||||
kfree(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
|
||||
{
|
||||
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
|
||||
}
|
||||
|
||||
static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
|
@ -824,6 +875,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|||
chip->parent = pctrl->dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->of_node = pctrl->dev->of_node;
|
||||
chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
|
||||
|
||||
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
||||
if (ret) {
|
||||
|
@ -831,6 +883,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = msm_gpio_init_valid_mask(chip, pctrl);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "Failed to add pin range\n");
|
||||
|
|
|
@ -288,6 +288,21 @@ struct gpio_chip {
|
|||
struct gpio_irq_chip irq;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @need_valid_mask:
|
||||
*
|
||||
* If set core allocates @valid_mask with all bits set to one.
|
||||
*/
|
||||
bool need_valid_mask;
|
||||
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
* If not %NULL holds bitmask of GPIOs which are valid to be used
|
||||
* from the chip.
|
||||
*/
|
||||
unsigned long *valid_mask;
|
||||
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
/*
|
||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||
|
@ -384,6 +399,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);
|
|||
|
||||
/* Sleep persistence inquiry for drivers */
|
||||
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
|
||||
bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
/* get driver data */
|
||||
void *gpiochip_get_data(struct gpio_chip *chip);
|
||||
|
|
Loading…
Reference in New Issue