root/arch/mips/dec/platform.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *      DEC platform devices.
 *
 *      Copyright (c) 2014  Maciej W. Rozycki
 */

#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mc146818rtc.h>
#include <linux/platform_device.h>

#include <asm/bootinfo.h>

#include <asm/dec/interrupts.h>
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/kn01.h>
#include <asm/dec/kn02.h>
#include <asm/dec/system.h>

static struct resource dec_rtc_resources[] = {
        {
                .name = "rtc",
                .flags = IORESOURCE_MEM,
        },
};

static struct cmos_rtc_board_info dec_rtc_info = {
        .flags = CMOS_RTC_FLAGS_NOFREQ,
        .address_space = 64,
};

static struct platform_device dec_rtc_device = {
        .name = "rtc_cmos",
        .id = PLATFORM_DEVID_NONE,
        .dev.platform_data = &dec_rtc_info,
        .resource = dec_rtc_resources,
        .num_resources = ARRAY_SIZE(dec_rtc_resources),
};

static struct platform_device *dec_rtc_devices[] __initdata = {
        &dec_rtc_device,
};

static struct resource dec_dz_resources[] = {
        { .name = "dz", .flags = IORESOURCE_MEM, },
        { .name = "dz", .flags = IORESOURCE_IRQ, },
};

static struct platform_device dec_dz_device = {
        .name = "dz",
        .id = PLATFORM_DEVID_NONE,
        .resource = dec_dz_resources,
        .num_resources = ARRAY_SIZE(dec_dz_resources),
};

static struct platform_device *dec_dz_devices[] __initdata = {
        &dec_dz_device,
};

static struct resource dec_zs_resources[][2] = {
        {
                { .name = "scc0", .flags = IORESOURCE_MEM, },
                { .name = "scc0", .flags = IORESOURCE_IRQ, },
        },
        {
                { .name = "scc1", .flags = IORESOURCE_MEM, },
                { .name = "scc1", .flags = IORESOURCE_IRQ, },
        },
};

static struct platform_device dec_zs_device[] = {
        {
                .name = "zs",
                .id = 0,
                .resource = dec_zs_resources[0],
                .num_resources = ARRAY_SIZE(dec_zs_resources[0]),
        },
        {
                .name = "zs",
                .id = 1,
                .resource = dec_zs_resources[1],
                .num_resources = ARRAY_SIZE(dec_zs_resources[1]),
        },
};

static int __init dec_add_devices(void)
{
        struct platform_device *dec_zs_devices[ARRAY_SIZE(dec_zs_device)];
        int ret1, ret2, ret3;
        int num_dz, num_zs;
        int irq, i;

        dec_rtc_resources[0].start = RTC_PORT(0);
        dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1;

        i = 0;
        irq = dec_interrupt[DEC_IRQ_DZ11];
        if (IS_ENABLED(CONFIG_32BIT) && irq >= 0) {
                resource_size_t base;

                switch (mips_machtype) {
                case MACH_DS23100:
                case MACH_DS5100:
                        base = dec_kn_slot_base + KN01_DZ11;
                        break;
                default:
                        base = dec_kn_slot_base + KN02_DZ11;
                        break;
                }
                dec_dz_device.resource[0].start = base;
                dec_dz_device.resource[0].end = base + dec_kn_slot_size - 1;
                dec_dz_device.resource[1].start = irq;
                dec_dz_device.resource[1].end = irq;
                i++;
        }
        num_dz = i;

        i = 0;
        irq = dec_interrupt[DEC_IRQ_SCC0];
        if (irq >= 0) {
                resource_size_t base = dec_kn_slot_base + IOASIC_SCC0;

                dec_zs_device[i].resource[0].start = base;
                dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
                dec_zs_device[i].resource[1].start = irq;
                dec_zs_device[i].resource[1].end = irq;
                dec_zs_devices[i] = &dec_zs_device[i];
                i++;
        }
        irq = dec_interrupt[DEC_IRQ_SCC1];
        if (irq >= 0) {
                resource_size_t base = dec_kn_slot_base + IOASIC_SCC1;

                dec_zs_device[i].resource[0].start = base;
                dec_zs_device[i].resource[0].end = base + dec_kn_slot_size - 1;
                dec_zs_device[i].resource[1].start = irq;
                dec_zs_device[i].resource[1].end = irq;
                dec_zs_devices[i] = &dec_zs_device[i];
                i++;
        }
        num_zs = i;

        ret1 = platform_add_devices(dec_rtc_devices, 1);
        ret2 = IS_ENABLED(CONFIG_32BIT) ?
               platform_add_devices(dec_dz_devices, num_dz) : 0;
        ret3 = platform_add_devices(dec_zs_devices, num_zs);
        return ret1 ? ret1 : ret2 ? ret2 : ret3;
}

device_initcall(dec_add_devices);