devices.c 3.8 KB
Newer Older
1 2 3
/*
 *  CLPS711X common devices definitions
 *
4
 *  Author: Alexander Shiyan <shc_work@mail.ru>, 2013-2014
5 6 7 8 9 10 11
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

12 13
#include <linux/io.h>
#include <linux/of_fdt.h>
14
#include <linux/platform_device.h>
15
#include <linux/random.h>
16
#include <linux/sizes.h>
17 18 19 20
#include <linux/slab.h>
#include <linux/sys_soc.h>

#include <asm/system_info.h>
21 22 23

#include <mach/hardware.h>

24 25 26 27 28 29 30 31 32
static const struct resource clps711x_cpuidle_res __initconst =
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + HALT, SZ_128);

static void __init clps711x_add_cpuidle(void)
{
	platform_device_register_simple("clps711x-cpuidle", PLATFORM_DEVID_NONE,
					&clps711x_cpuidle_res, 1);
}

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
static const phys_addr_t clps711x_gpios[][2] __initconst = {
	{ PADR, PADDR },
	{ PBDR, PBDDR },
	{ PCDR, PCDDR },
	{ PDDR, PDDDR },
	{ PEDR, PEDDR },
};

static void __init clps711x_add_gpio(void)
{
	unsigned i;
	struct resource gpio_res[2];

	memset(gpio_res, 0, sizeof(gpio_res));

	gpio_res[0].flags = IORESOURCE_MEM;
	gpio_res[1].flags = IORESOURCE_MEM;

	for (i = 0; i < ARRAY_SIZE(clps711x_gpios); i++) {
		gpio_res[0].start = CLPS711X_PHYS_BASE + clps711x_gpios[i][0];
		gpio_res[0].end = gpio_res[0].start;
		gpio_res[1].start = CLPS711X_PHYS_BASE + clps711x_gpios[i][1];
		gpio_res[1].end = gpio_res[1].start;

		platform_device_register_simple("clps711x-gpio", i,
						gpio_res, ARRAY_SIZE(gpio_res));
	}
}

62 63 64 65 66 67 68 69 70 71 72 73 74 75
const struct resource clps711x_syscon_res[] __initconst = {
	/* SYSCON1, SYSFLG1 */
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON1, SZ_128),
	/* SYSCON2, SYSFLG2 */
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON2, SZ_128),
	/* SYSCON3 */
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + SYSCON3, SZ_64),
};

static void __init clps711x_add_syscon(void)
{
	unsigned i;

	for (i = 0; i < ARRAY_SIZE(clps711x_syscon_res); i++)
76
		platform_device_register_simple("syscon", i + 1,
77 78 79
						&clps711x_syscon_res[i], 1);
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static const struct resource clps711x_uart1_res[] __initconst = {
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR1, SZ_128),
	DEFINE_RES_IRQ(IRQ_UTXINT1),
	DEFINE_RES_IRQ(IRQ_URXINT1),
};

static const struct resource clps711x_uart2_res[] __initconst = {
	DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR2, SZ_128),
	DEFINE_RES_IRQ(IRQ_UTXINT2),
	DEFINE_RES_IRQ(IRQ_URXINT2),
};

static void __init clps711x_add_uart(void)
{
	platform_device_register_simple("clps711x-uart", 0, clps711x_uart1_res,
					ARRAY_SIZE(clps711x_uart1_res));
	platform_device_register_simple("clps711x-uart", 1, clps711x_uart2_res,
					ARRAY_SIZE(clps711x_uart2_res));
};

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
static void __init clps711x_soc_init(void)
{
	struct soc_device_attribute *soc_dev_attr;
	struct soc_device *soc_dev;
	void __iomem *base;
	u32 id[5];

	base = ioremap(CLPS711X_PHYS_BASE, SZ_32K);
	if (!base)
		return;

	id[0] = readl(base + UNIQID);
	id[1] = readl(base + RANDID0);
	id[2] = readl(base + RANDID1);
	id[3] = readl(base + RANDID2);
	id[4] = readl(base + RANDID3);
	system_rev = SYSFLG1_VERID(readl(base + SYSFLG1));

	add_device_randomness(id, sizeof(id));

	system_serial_low = id[0];

	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
	if (!soc_dev_attr)
		goto out_unmap;

	soc_dev_attr->machine = of_flat_dt_get_machine_name();
	soc_dev_attr->family = "Cirrus Logic CLPS711X";
	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u", system_rev);
	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%08x", id[0]);

	soc_dev = soc_device_register(soc_dev_attr);
	if (IS_ERR(soc_dev)) {
		kfree(soc_dev_attr->revision);
		kfree(soc_dev_attr->soc_id);
		kfree(soc_dev_attr);
	}

out_unmap:
	iounmap(base);
}

142 143
void __init clps711x_devices_init(void)
{
144
	clps711x_add_cpuidle();
145
	clps711x_add_gpio();
146
	clps711x_add_syscon();
147
	clps711x_add_uart();
148
	clps711x_soc_init();
149
}