18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-footbridge/ebsa285.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * EBSA285 machine fixup
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/init.h>
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/leds.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/hardware/dec21285.h>
148c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <asm/mach/arch.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "common.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* LEDs */
218c2ecf20Sopenharmony_ci#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
228c2ecf20Sopenharmony_ci#define XBUS_AMBER_L	BIT(0)
238c2ecf20Sopenharmony_ci#define XBUS_GREEN_L	BIT(1)
248c2ecf20Sopenharmony_ci#define XBUS_RED_L	BIT(2)
258c2ecf20Sopenharmony_ci#define XBUS_TOGGLE	BIT(7)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct ebsa285_led {
288c2ecf20Sopenharmony_ci	struct led_classdev     cdev;
298c2ecf20Sopenharmony_ci	u8                      mask;
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * The triggers lines up below will only be used if the
348c2ecf20Sopenharmony_ci * LED triggers are compiled in.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic const struct {
378c2ecf20Sopenharmony_ci	const char *name;
388c2ecf20Sopenharmony_ci	const char *trigger;
398c2ecf20Sopenharmony_ci} ebsa285_leds[] = {
408c2ecf20Sopenharmony_ci	{ "ebsa285:amber", "cpu0", },
418c2ecf20Sopenharmony_ci	{ "ebsa285:green", "heartbeat", },
428c2ecf20Sopenharmony_ci	{ "ebsa285:red",},
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic unsigned char hw_led_state;
468c2ecf20Sopenharmony_cistatic void __iomem *xbus;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void ebsa285_led_set(struct led_classdev *cdev,
498c2ecf20Sopenharmony_ci		enum led_brightness b)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct ebsa285_led *led = container_of(cdev,
528c2ecf20Sopenharmony_ci			struct ebsa285_led, cdev);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (b == LED_OFF)
558c2ecf20Sopenharmony_ci		hw_led_state |= led->mask;
568c2ecf20Sopenharmony_ci	else
578c2ecf20Sopenharmony_ci		hw_led_state &= ~led->mask;
588c2ecf20Sopenharmony_ci	writeb(hw_led_state, xbus);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct ebsa285_led *led = container_of(cdev,
648c2ecf20Sopenharmony_ci			struct ebsa285_led, cdev);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return hw_led_state & led->mask ? LED_OFF : LED_FULL;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int __init ebsa285_leds_init(void)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int i;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (!machine_is_ebsa285())
748c2ecf20Sopenharmony_ci		return -ENODEV;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	xbus = ioremap(XBUS_CS2, SZ_4K);
778c2ecf20Sopenharmony_ci	if (!xbus)
788c2ecf20Sopenharmony_ci		return -ENOMEM;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* 3 LEDS all off */
818c2ecf20Sopenharmony_ci	hw_led_state = XBUS_AMBER_L | XBUS_GREEN_L | XBUS_RED_L;
828c2ecf20Sopenharmony_ci	writeb(hw_led_state, xbus);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) {
858c2ecf20Sopenharmony_ci		struct ebsa285_led *led;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		led = kzalloc(sizeof(*led), GFP_KERNEL);
888c2ecf20Sopenharmony_ci		if (!led)
898c2ecf20Sopenharmony_ci			break;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		led->cdev.name = ebsa285_leds[i].name;
928c2ecf20Sopenharmony_ci		led->cdev.brightness_set = ebsa285_led_set;
938c2ecf20Sopenharmony_ci		led->cdev.brightness_get = ebsa285_led_get;
948c2ecf20Sopenharmony_ci		led->cdev.default_trigger = ebsa285_leds[i].trigger;
958c2ecf20Sopenharmony_ci		led->mask = BIT(i);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		if (led_classdev_register(NULL, &led->cdev) < 0) {
988c2ecf20Sopenharmony_ci			kfree(led);
998c2ecf20Sopenharmony_ci			break;
1008c2ecf20Sopenharmony_ci		}
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/*
1078c2ecf20Sopenharmony_ci * Since we may have triggers on any subsystem, defer registration
1088c2ecf20Sopenharmony_ci * until after subsystem_init.
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_cifs_initcall(ebsa285_leds_init);
1118c2ecf20Sopenharmony_ci#endif
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciMACHINE_START(EBSA285, "EBSA285")
1148c2ecf20Sopenharmony_ci	/* Maintainer: Russell King */
1158c2ecf20Sopenharmony_ci	.atag_offset	= 0x100,
1168c2ecf20Sopenharmony_ci	.video_start	= 0x000a0000,
1178c2ecf20Sopenharmony_ci	.video_end	= 0x000bffff,
1188c2ecf20Sopenharmony_ci	.map_io		= footbridge_map_io,
1198c2ecf20Sopenharmony_ci	.init_early	= footbridge_sched_clock,
1208c2ecf20Sopenharmony_ci	.init_irq	= footbridge_init_irq,
1218c2ecf20Sopenharmony_ci	.init_time	= footbridge_timer_init,
1228c2ecf20Sopenharmony_ci	.restart	= footbridge_restart,
1238c2ecf20Sopenharmony_ciMACHINE_END
1248c2ecf20Sopenharmony_ci
125