18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Atmel (Multi-port DDR-)SDRAM Controller driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2014 Atmel
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/err.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistruct at91_ramc_caps {
188c2ecf20Sopenharmony_ci	bool has_ddrck;
198c2ecf20Sopenharmony_ci	bool has_mpddr_clk;
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic const struct at91_ramc_caps at91rm9200_caps = { };
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic const struct at91_ramc_caps at91sam9g45_caps = {
258c2ecf20Sopenharmony_ci	.has_ddrck = 1,
268c2ecf20Sopenharmony_ci	.has_mpddr_clk = 0,
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const struct at91_ramc_caps sama5d3_caps = {
308c2ecf20Sopenharmony_ci	.has_ddrck = 1,
318c2ecf20Sopenharmony_ci	.has_mpddr_clk = 1,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_ramc_of_match[] = {
358c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at91rm9200-sdramc", .data = &at91rm9200_caps, },
368c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at91sam9260-sdramc", .data = &at91rm9200_caps, },
378c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at91sam9g45-ddramc", .data = &at91sam9g45_caps, },
388c2ecf20Sopenharmony_ci	{ .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, },
398c2ecf20Sopenharmony_ci	{},
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int atmel_ramc_probe(struct platform_device *pdev)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	const struct at91_ramc_caps *caps;
458c2ecf20Sopenharmony_ci	struct clk *clk;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	caps = of_device_get_match_data(&pdev->dev);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (caps->has_ddrck) {
508c2ecf20Sopenharmony_ci		clk = devm_clk_get_enabled(&pdev->dev, "ddrck");
518c2ecf20Sopenharmony_ci		if (IS_ERR(clk))
528c2ecf20Sopenharmony_ci			return PTR_ERR(clk);
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (caps->has_mpddr_clk) {
568c2ecf20Sopenharmony_ci		clk = devm_clk_get_enabled(&pdev->dev, "mpddr");
578c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
588c2ecf20Sopenharmony_ci			pr_err("AT91 RAMC: couldn't get mpddr clock\n");
598c2ecf20Sopenharmony_ci			return PTR_ERR(clk);
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return 0;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic struct platform_driver atmel_ramc_driver = {
678c2ecf20Sopenharmony_ci	.probe		= atmel_ramc_probe,
688c2ecf20Sopenharmony_ci	.driver		= {
698c2ecf20Sopenharmony_ci		.name	= "atmel-ramc",
708c2ecf20Sopenharmony_ci		.of_match_table = atmel_ramc_of_match,
718c2ecf20Sopenharmony_ci	},
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cibuiltin_platform_driver(atmel_ramc_driver);
75