162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Intel Merrifield watchdog platform device library file
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright 2014 Intel Corporation
662306a36Sopenharmony_ci * Author: David Cohen <david.a.cohen@linux.intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/platform_data/intel-mid_wdt.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
1562306a36Sopenharmony_ci#include <asm/intel-family.h>
1662306a36Sopenharmony_ci#include <asm/intel-mid.h>
1762306a36Sopenharmony_ci#include <asm/io_apic.h>
1862306a36Sopenharmony_ci#include <asm/hw_irq.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define TANGIER_EXT_TIMER0_MSI 12
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic struct platform_device wdt_dev = {
2362306a36Sopenharmony_ci	.name = "intel_mid_wdt",
2462306a36Sopenharmony_ci	.id = -1,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int tangier_probe(struct platform_device *pdev)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct irq_alloc_info info;
3062306a36Sopenharmony_ci	struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
3162306a36Sopenharmony_ci	int gsi = TANGIER_EXT_TIMER0_MSI;
3262306a36Sopenharmony_ci	int irq;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (!pdata)
3562306a36Sopenharmony_ci		return -EINVAL;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* IOAPIC builds identity mapping between GSI and IRQ on MID */
3862306a36Sopenharmony_ci	ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0);
3962306a36Sopenharmony_ci	irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
4062306a36Sopenharmony_ci	if (irq < 0) {
4162306a36Sopenharmony_ci		dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n", gsi);
4262306a36Sopenharmony_ci		return irq;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	pdata->irq = irq;
4662306a36Sopenharmony_ci	return 0;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct intel_mid_wdt_pdata tangier_pdata = {
5062306a36Sopenharmony_ci	.probe = tangier_probe,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const struct x86_cpu_id intel_mid_cpu_ids[] = {
5462306a36Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &tangier_pdata),
5562306a36Sopenharmony_ci	{}
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int __init register_mid_wdt(void)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	const struct x86_cpu_id *id;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	id = x86_match_cpu(intel_mid_cpu_ids);
6362306a36Sopenharmony_ci	if (!id)
6462306a36Sopenharmony_ci		return -ENODEV;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	wdt_dev.dev.platform_data = (struct intel_mid_wdt_pdata *)id->driver_data;
6762306a36Sopenharmony_ci	return platform_device_register(&wdt_dev);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ciarch_initcall(register_mid_wdt);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void __exit unregister_mid_wdt(void)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	platform_device_unregister(&wdt_dev);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci__exitcall(unregister_mid_wdt);
76