psw.c 3.2 KB
Newer Older
K
kogiidena 已提交
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
/*
 * arch/sh/boards/landisk/psw.c
 *
 * push switch support for LANDISK and USL-5P
 *
 * Copyright (C) 2006-2007  Paul Mundt
 * Copyright (C) 2007  kogiidena
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/io.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/landisk/iodata_landisk.h>
#include <asm/push-switch.h>

static irqreturn_t psw_irq_handler(int irq, void *arg)
{
	struct platform_device *pdev = arg;
	struct push_switch *psw = platform_get_drvdata(pdev);
	struct push_switch_platform_info *psw_info = pdev->dev.platform_data;
	unsigned int sw_value;
	int ret = 0;

	sw_value = (0x0ff & (~ctrl_inb(PA_STATUS)));

	/* Nothing to do if there's no state change */
	if (psw->state) {
		ret = 1;
		goto out;
	}

	/* Figure out who raised it */
	if (sw_value & (1 << psw_info->bit)) {
		psw->state = 1;
		mod_timer(&psw->debounce, jiffies + 50);
		ret = 1;
	}

out:
	/* Clear the switch IRQs */
	ctrl_outb(0x00, PA_PWRINT_CLR);

	return IRQ_RETVAL(ret);
}

static struct resource psw_power_resources[] = {
	[0] = {
		.start = IRQ_POWER,
		.flags = IORESOURCE_IRQ,
       },
};

static struct resource psw_usl5p_resources[] = {
	[0] = {
		.start = IRQ_BUTTON,
		.flags = IORESOURCE_IRQ,
	},
};

static struct push_switch_platform_info psw_power_platform_data = {
	.name		= "psw_power",
	.bit		= 4,
	.irq_flags	= IRQF_SHARED,
	.irq_handler	= psw_irq_handler,
};

static struct push_switch_platform_info psw1_platform_data = {
	.name		= "psw1",
	.bit		= 0,
	.irq_flags	= IRQF_SHARED,
	.irq_handler	= psw_irq_handler,
};

static struct push_switch_platform_info psw2_platform_data = {
	.name		= "psw2",
	.bit		= 2,
	.irq_flags	= IRQF_SHARED,
	.irq_handler	= psw_irq_handler,
};

static struct push_switch_platform_info psw3_platform_data = {
	.name		= "psw3",
	.bit		= 1,
	.irq_flags	= IRQF_SHARED,
	.irq_handler	= psw_irq_handler,
};

static struct platform_device psw_power_switch_device = {
	.name		= "push-switch",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(psw_power_resources),
	.resource	= psw_power_resources,
	.dev		= {
		.platform_data = &psw_power_platform_data,
	},
};

static struct platform_device psw1_switch_device = {
	.name		= "push-switch",
	.id		= 1,
	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
	.resource	= psw_usl5p_resources,
	.dev		= {
		.platform_data = &psw1_platform_data,
	},
};

static struct platform_device psw2_switch_device = {
	.name		= "push-switch",
	.id		= 2,
	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
	.resource	= psw_usl5p_resources,
	.dev		= {
		.platform_data = &psw2_platform_data,
	},
};

static struct platform_device psw3_switch_device = {
	.name		= "push-switch",
	.id		= 3,
	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
	.resource	= psw_usl5p_resources,
	.dev = {
		.platform_data = &psw3_platform_data,
	},
};

static struct platform_device *psw_devices[] = {
	&psw_power_switch_device,
	&psw1_switch_device,
	&psw2_switch_device,
	&psw3_switch_device,
};

static int __init psw_init(void)
{
	return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices));
}
module_init(psw_init);