summaryrefslogtreecommitdiffstats
path: root/kernel/arch/arm/mach-clps711x/devices.c
blob: 77a9617c216d50d8c5746fd5429d066c7f1d74ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
142
143
144
145
146
147
148
149
/*
 *  CLPS711X common devices definitions
 *
 *  Author: Alexander Shiyan <shc_work@mail.ru>, 2013-2014
 *
 * 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.
 */

#include <linux/io.h>
#include <linux/of_fdt.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>

#include <asm/system_info.h>

#include <mach/hardware.h>

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);
}

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));
	}
}

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++)
		platform_device_register_simple("syscon", i + 1,
						&clps711x_syscon_res[i], 1);
}

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));
};

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);
}

void __init clps711x_devices_init(void)
{
	clps711x_add_cpuidle();
	clps711x_add_gpio();
	clps711x_add_syscon();
	clps711x_add_uart();
	clps711x_soc_init();
}