162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2012 John Crispin <john@phrozen.org>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/err.h>
862306a36Sopenharmony_ci#include <linux/export.h>
962306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1062306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <lantiq_soc.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic unsigned int *cp1_base;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciunsigned int *ltq_get_cp1_base(void)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	if (!cp1_base)
2162306a36Sopenharmony_ci		panic("no cp1 base was set\n");
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	return cp1_base;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ciEXPORT_SYMBOL(ltq_get_cp1_base);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int vmmc_probe(struct platform_device *pdev)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci#define CP1_SIZE       (1 << 20)
3062306a36Sopenharmony_ci	struct gpio_desc *gpio;
3162306a36Sopenharmony_ci	int gpio_count;
3262306a36Sopenharmony_ci	dma_addr_t dma;
3362306a36Sopenharmony_ci	int error;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	cp1_base =
3662306a36Sopenharmony_ci		(void *) CPHYSADDR(dma_alloc_coherent(&pdev->dev, CP1_SIZE,
3762306a36Sopenharmony_ci						    &dma, GFP_KERNEL));
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	gpio_count = gpiod_count(&pdev->dev, NULL);
4062306a36Sopenharmony_ci	while (gpio_count > 0) {
4162306a36Sopenharmony_ci		gpio = devm_gpiod_get_index(&pdev->dev,
4262306a36Sopenharmony_ci					    NULL, --gpio_count, GPIOD_OUT_HIGH);
4362306a36Sopenharmony_ci		error = PTR_ERR_OR_ZERO(gpio);
4462306a36Sopenharmony_ci		if (error) {
4562306a36Sopenharmony_ci			dev_err(&pdev->dev,
4662306a36Sopenharmony_ci				"failed to request GPIO idx %d: %d\n",
4762306a36Sopenharmony_ci				gpio_count, error);
4862306a36Sopenharmony_ci			continue;
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		gpiod_set_consumer_name(gpio, "vmmc-relay");
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	dev_info(&pdev->dev, "reserved %dMB at 0x%p", CP1_SIZE >> 20, cp1_base);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic const struct of_device_id vmmc_match[] = {
6062306a36Sopenharmony_ci	{ .compatible = "lantiq,vmmc-xway" },
6162306a36Sopenharmony_ci	{},
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic struct platform_driver vmmc_driver = {
6562306a36Sopenharmony_ci	.probe = vmmc_probe,
6662306a36Sopenharmony_ci	.driver = {
6762306a36Sopenharmony_ci		.name = "lantiq,vmmc",
6862306a36Sopenharmony_ci		.of_match_table = vmmc_match,
6962306a36Sopenharmony_ci	},
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_cibuiltin_platform_driver(vmmc_driver);
72