]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - arch/arm/mach-imx/3ds_debugboard.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / arch / arm / mach-imx / 3ds_debugboard.c
CommitLineData
fcaf2036 1// SPDX-License-Identifier: GPL-2.0-or-later
fa94f8dc
JW
2/*
3 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
4 * Copyright (C) 2010 Jason Wang <jason77.wang@gmail.com>
fa94f8dc
JW
5 */
6
7#include <linux/interrupt.h>
8#include <linux/irq.h>
ec782880 9#include <linux/irqdomain.h>
fa94f8dc
JW
10#include <linux/io.h>
11#include <linux/platform_device.h>
12#include <linux/gpio.h>
ec782880 13#include <linux/module.h>
fa94f8dc 14#include <linux/smsc911x.h>
33499df8
SH
15#include <linux/regulator/machine.h>
16#include <linux/regulator/fixed.h>
07294a7e 17#include "3ds_debugboard.h"
50f2de61 18#include "hardware.h"
fa94f8dc
JW
19
20/* LAN9217 ethernet base address */
21#define LAN9217_BASE_ADDR(n) (n + 0x0)
22/* External UART */
23#define UARTA_BASE_ADDR(n) (n + 0x8000)
24#define UARTB_BASE_ADDR(n) (n + 0x10000)
25
26#define BOARD_IO_ADDR(n) (n + 0x20000)
27/* LED switchs */
28#define LED_SWITCH_REG 0x00
29/* buttons */
30#define SWITCH_BUTTONS_REG 0x08
31/* status, interrupt */
32#define INTR_STATUS_REG 0x10
33#define INTR_MASK_REG 0x38
34#define INTR_RESET_REG 0x20
35/* magic word for debug CPLD */
36#define MAGIC_NUMBER1_REG 0x40
37#define MAGIC_NUMBER2_REG 0x48
38/* CPLD code version */
39#define CPLD_CODE_VER_REG 0x50
40/* magic word for debug CPLD */
41#define MAGIC_NUMBER3_REG 0x58
42/* module reset register*/
43#define MODULE_RESET_REG 0x60
44/* CPU ID and Personality ID */
45#define MCU_BOARD_ID_REG 0x68
46
fa94f8dc
JW
47#define MXC_MAX_EXP_IO_LINES 16
48
49/* interrupts like external uart , external ethernet etc*/
ec782880
SG
50#define EXPIO_INT_ENET 0
51#define EXPIO_INT_XUART_A 1
52#define EXPIO_INT_XUART_B 2
53#define EXPIO_INT_BUTTON_A 3
54#define EXPIO_INT_BUTTON_B 4
fa94f8dc
JW
55
56static void __iomem *brd_io;
ec782880 57static struct irq_domain *domain;
fa94f8dc
JW
58
59static struct resource smsc911x_resources[] = {
60 {
61 .flags = IORESOURCE_MEM,
62 } , {
fa94f8dc
JW
63 .flags = IORESOURCE_IRQ,
64 },
65};
66
67static struct smsc911x_platform_config smsc911x_config = {
68 .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
69 .flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY,
70};
71
72static struct platform_device smsc_lan9217_device = {
73 .name = "smsc911x",
f0df8754 74 .id = -1,
fa94f8dc
JW
75 .dev = {
76 .platform_data = &smsc911x_config,
77 },
78 .num_resources = ARRAY_SIZE(smsc911x_resources),
79 .resource = smsc911x_resources,
80};
81
bd0b9ac4 82static void mxc_expio_irq_handler(struct irq_desc *desc)
fa94f8dc
JW
83{
84 u32 imr_val;
85 u32 int_valid;
86 u32 expio_irq;
87
4d93579f
LB
88 /* irq = gpio irq number */
89 desc->irq_data.chip->irq_mask(&desc->irq_data);
fa94f8dc 90
c553138f
JB
91 imr_val = imx_readw(brd_io + INTR_MASK_REG);
92 int_valid = imx_readw(brd_io + INTR_STATUS_REG) & ~imr_val;
fa94f8dc 93
ec782880 94 expio_irq = 0;
fa94f8dc 95 for (; int_valid != 0; int_valid >>= 1, expio_irq++) {
fa94f8dc
JW
96 if ((int_valid & 1) == 0)
97 continue;
ec782880 98 generic_handle_irq(irq_find_mapping(domain, expio_irq));
fa94f8dc
JW
99 }
100
4d93579f
LB
101 desc->irq_data.chip->irq_ack(&desc->irq_data);
102 desc->irq_data.chip->irq_unmask(&desc->irq_data);
fa94f8dc
JW
103}
104
105/*
106 * Disable an expio pin's interrupt by setting the bit in the imr.
107 * Irq is an expio virtual irq number
108 */
4d93579f 109static void expio_mask_irq(struct irq_data *d)
fa94f8dc
JW
110{
111 u16 reg;
ec782880 112 u32 expio = d->hwirq;
fa94f8dc 113
c553138f 114 reg = imx_readw(brd_io + INTR_MASK_REG);
fa94f8dc 115 reg |= (1 << expio);
c553138f 116 imx_writew(reg, brd_io + INTR_MASK_REG);
fa94f8dc
JW
117}
118
4d93579f 119static void expio_ack_irq(struct irq_data *d)
fa94f8dc 120{
ec782880 121 u32 expio = d->hwirq;
fa94f8dc 122
c553138f
JB
123 imx_writew(1 << expio, brd_io + INTR_RESET_REG);
124 imx_writew(0, brd_io + INTR_RESET_REG);
4d93579f 125 expio_mask_irq(d);
fa94f8dc
JW
126}
127
4d93579f 128static void expio_unmask_irq(struct irq_data *d)
fa94f8dc
JW
129{
130 u16 reg;
ec782880 131 u32 expio = d->hwirq;
fa94f8dc 132
c553138f 133 reg = imx_readw(brd_io + INTR_MASK_REG);
fa94f8dc 134 reg &= ~(1 << expio);
c553138f 135 imx_writew(reg, brd_io + INTR_MASK_REG);
fa94f8dc
JW
136}
137
138static struct irq_chip expio_irq_chip = {
4d93579f
LB
139 .irq_ack = expio_ack_irq,
140 .irq_mask = expio_mask_irq,
141 .irq_unmask = expio_unmask_irq,
fa94f8dc
JW
142};
143
33499df8
SH
144static struct regulator_consumer_supply dummy_supplies[] = {
145 REGULATOR_SUPPLY("vdd33a", "smsc911x"),
146 REGULATOR_SUPPLY("vddvario", "smsc911x"),
147};
148
ed4a7fb0 149int __init mxc_expio_init(u32 base, u32 intr_gpio)
fa94f8dc 150{
ed4a7fb0 151 u32 p_irq = gpio_to_irq(intr_gpio);
ec782880 152 int irq_base;
fa94f8dc
JW
153 int i;
154
155 brd_io = ioremap(BOARD_IO_ADDR(base), SZ_4K);
156 if (brd_io == NULL)
157 return -ENOMEM;
158
c553138f
JB
159 if ((imx_readw(brd_io + MAGIC_NUMBER1_REG) != 0xAAAA) ||
160 (imx_readw(brd_io + MAGIC_NUMBER2_REG) != 0x5555) ||
161 (imx_readw(brd_io + MAGIC_NUMBER3_REG) != 0xCAFE)) {
fa94f8dc
JW
162 pr_info("3-Stack Debug board not detected\n");
163 iounmap(brd_io);
164 brd_io = NULL;
165 return -ENODEV;
166 }
167
168 pr_info("3-Stack Debug board detected, rev = 0x%04X\n",
169 readw(brd_io + CPLD_CODE_VER_REG));
170
171 /*
172 * Configure INT line as GPIO input
173 */
ed4a7fb0
SG
174 gpio_request(intr_gpio, "expio_pirq");
175 gpio_direction_input(intr_gpio);
fa94f8dc
JW
176
177 /* disable the interrupt and clear the status */
c553138f
JB
178 imx_writew(0, brd_io + INTR_MASK_REG);
179 imx_writew(0xFFFF, brd_io + INTR_RESET_REG);
180 imx_writew(0, brd_io + INTR_RESET_REG);
181 imx_writew(0x1F, brd_io + INTR_MASK_REG);
ec782880
SG
182
183 irq_base = irq_alloc_descs(-1, 0, MXC_MAX_EXP_IO_LINES, numa_node_id());
184 WARN_ON(irq_base < 0);
185
186 domain = irq_domain_add_legacy(NULL, MXC_MAX_EXP_IO_LINES, irq_base, 0,
187 &irq_domain_simple_ops, NULL);
188 WARN_ON(!domain);
189
190 for (i = irq_base; i < irq_base + MXC_MAX_EXP_IO_LINES; i++) {
f38c02f3 191 irq_set_chip_and_handler(i, &expio_irq_chip, handle_level_irq);
e8d36d5d 192 irq_clear_status_flags(i, IRQ_NOREQUEST);
fa94f8dc 193 }
6845664a
TG
194 irq_set_irq_type(p_irq, IRQF_TRIGGER_LOW);
195 irq_set_chained_handler(p_irq, mxc_expio_irq_handler);
fa94f8dc
JW
196
197 /* Register Lan device on the debugboard */
33499df8
SH
198 regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
199
fa94f8dc
JW
200 smsc911x_resources[0].start = LAN9217_BASE_ADDR(base);
201 smsc911x_resources[0].end = LAN9217_BASE_ADDR(base) + 0x100 - 1;
ec782880
SG
202 smsc911x_resources[1].start = irq_find_mapping(domain, EXPIO_INT_ENET);
203 smsc911x_resources[1].end = irq_find_mapping(domain, EXPIO_INT_ENET);
fa94f8dc
JW
204 platform_device_register(&smsc_lan9217_device);
205
206 return 0;
207}