Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ddf3a79 authored by Alban Bedel's avatar Alban Bedel Committed by Ralf Baechle
Browse files

MIPS: ath79: Add OF support to the GPIO driver



Replace the simple GPIO chip registration by a platform driver
and make ath79_gpio_init() just register the device.

Signed-off-by: default avatarAlban Bedel <albeu@free.fr>
Cc: linux-mips@linux-mips.org
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent d6743a49
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/platform_data/gpio-ath79.h>
#include <linux/serial_8250.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -106,3 +107,53 @@ void __init ath79_register_wdt(void)

	platform_device_register_simple("ath79-wdt", -1, &res, 1);
}

static struct ath79_gpio_platform_data ath79_gpio_pdata;

static struct resource ath79_gpio_resources[] = {
	{
		.flags = IORESOURCE_MEM,
		.start = AR71XX_GPIO_BASE,
		.end = AR71XX_GPIO_BASE + AR71XX_GPIO_SIZE - 1,
	},
	{
		.start	= ATH79_MISC_IRQ(2),
		.end	= ATH79_MISC_IRQ(2),
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device ath79_gpio_device = {
	.name		= "ath79-gpio",
	.id		= -1,
	.resource	= ath79_gpio_resources,
	.num_resources	= ARRAY_SIZE(ath79_gpio_resources),
	.dev = {
		.platform_data	= &ath79_gpio_pdata
	},
};

void __init ath79_gpio_init(void)
{
	if (soc_is_ar71xx()) {
		ath79_gpio_pdata.ngpios = AR71XX_GPIO_COUNT;
	} else if (soc_is_ar7240()) {
		ath79_gpio_pdata.ngpios = AR7240_GPIO_COUNT;
	} else if (soc_is_ar7241() || soc_is_ar7242()) {
		ath79_gpio_pdata.ngpios = AR7241_GPIO_COUNT;
	} else if (soc_is_ar913x()) {
		ath79_gpio_pdata.ngpios = AR913X_GPIO_COUNT;
	} else if (soc_is_ar933x()) {
		ath79_gpio_pdata.ngpios = AR933X_GPIO_COUNT;
	} else if (soc_is_ar934x()) {
		ath79_gpio_pdata.ngpios = AR934X_GPIO_COUNT;
		ath79_gpio_pdata.oe_inverted = 1;
	} else if (soc_is_qca955x()) {
		ath79_gpio_pdata.ngpios = QCA955X_GPIO_COUNT;
		ath79_gpio_pdata.oe_inverted = 1;
	} else {
		BUG();
	}

	platform_device_register(&ath79_gpio_device);
}
+57 −22
Original line number Diff line number Diff line
@@ -20,13 +20,15 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/gpio.h>
#include <linux/platform_data/gpio-ath79.h>
#include <linux/of_device.h>

#include <asm/mach-ath79/ar71xx_regs.h>
#include <asm/mach-ath79/ath79.h>
#include "common.h"

static void __iomem *ath79_gpio_base;
static unsigned long ath79_gpio_count;
static u32 ath79_gpio_count;
static DEFINE_SPINLOCK(ath79_gpio_lock);

static void __ath79_gpio_set_value(unsigned gpio, int value)
@@ -178,39 +180,72 @@ void ath79_gpio_function_disable(u32 mask)
	ath79_gpio_function_setup(0, mask);
}

void __init ath79_gpio_init(void)
static const struct of_device_id ath79_gpio_of_match[] = {
	{ .compatible = "qca,ar7100-gpio" },
	{ .compatible = "qca,ar9340-gpio" },
	{},
};

static int ath79_gpio_probe(struct platform_device *pdev)
{
	struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data;
	struct device_node *np = pdev->dev.of_node;
	struct resource *res;
	bool oe_inverted;
	int err;

	if (soc_is_ar71xx())
		ath79_gpio_count = AR71XX_GPIO_COUNT;
	else if (soc_is_ar7240())
		ath79_gpio_count = AR7240_GPIO_COUNT;
	else if (soc_is_ar7241() || soc_is_ar7242())
		ath79_gpio_count = AR7241_GPIO_COUNT;
	else if (soc_is_ar913x())
		ath79_gpio_count = AR913X_GPIO_COUNT;
	else if (soc_is_ar933x())
		ath79_gpio_count = AR933X_GPIO_COUNT;
	else if (soc_is_ar934x())
		ath79_gpio_count = AR934X_GPIO_COUNT;
	else if (soc_is_qca955x())
		ath79_gpio_count = QCA955X_GPIO_COUNT;
	else
		BUG();
	if (np) {
		err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
		if (err) {
			dev_err(&pdev->dev, "ngpios property is not valid\n");
			return err;
		}
		if (ath79_gpio_count >= 32) {
			dev_err(&pdev->dev, "ngpios must be less than 32\n");
			return -EINVAL;
		}
		oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio");
	} else if (pdata) {
		ath79_gpio_count = pdata->ngpios;
		oe_inverted = pdata->oe_inverted;
	} else {
		dev_err(&pdev->dev, "No DT node or platform data found\n");
		return -EINVAL;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	ath79_gpio_base = devm_ioremap_nocache(
		&pdev->dev, res->start, resource_size(res));
	if (!ath79_gpio_base)
		return -ENOMEM;

	ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
	ath79_gpio_chip.dev = &pdev->dev;
	ath79_gpio_chip.ngpio = ath79_gpio_count;
	if (soc_is_ar934x() || soc_is_qca955x()) {
	if (oe_inverted) {
		ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
		ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
	}

	err = gpiochip_add(&ath79_gpio_chip);
	if (err)
		panic("cannot add AR71xx GPIO chip, error=%d", err);
	if (err) {
		dev_err(&pdev->dev,
			"cannot add AR71xx GPIO chip, error=%d", err);
		return err;
	}

	return 0;
}

static struct platform_driver ath79_gpio_driver = {
	.driver = {
		.name = "ath79-gpio",
		.of_match_table	= ath79_gpio_of_match,
	},
	.probe = ath79_gpio_probe,
};

module_platform_driver(ath79_gpio_driver);

int gpio_get_value(unsigned gpio)
{
	if (gpio < ath79_gpio_count)
+19 −0
Original line number Diff line number Diff line
/*
 *  Atheros AR7XXX/AR9XXX GPIO controller platform data
 *
 * Copyright (C) 2015 Alban Bedel <albeu@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#ifndef __LINUX_PLATFORM_DATA_GPIO_ATH79_H
#define __LINUX_PLATFORM_DATA_GPIO_ATH79_H

struct ath79_gpio_platform_data {
	unsigned ngpios;
	bool oe_inverted;
};

#endif