-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 356398 b: refs/heads/master c: 5611fe4 h: refs/heads/master v: v3
- Loading branch information
Benjamin Collins
authored and
Benjamin Herrenschmidt
committed
Jan 29, 2013
1 parent
7f71edd
commit 415ebd1
Showing
4 changed files
with
186 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 34f364fef475f5d960b74bf074d65392ece50235 | ||
refs/heads/master: 5611fe48c545a22e62273428ed74c9bfae4a9406 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/* | ||
* Servergy CTS-1000 Setup | ||
* | ||
* Maintained by Ben Collins <ben.c@servergy.com> | ||
* | ||
* Copyright 2012 by Servergy, Inc. | ||
* | ||
* 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/platform_device.h> | ||
#include <linux/device.h> | ||
#include <linux/module.h> | ||
#include <linux/init.h> | ||
#include <linux/of_gpio.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/reboot.h> | ||
#include <linux/interrupt.h> | ||
|
||
#include <asm/machdep.h> | ||
|
||
static struct device_node *halt_node; | ||
|
||
static struct of_device_id child_match[] = { | ||
{ | ||
.compatible = "sgy,gpio-halt", | ||
}, | ||
{}, | ||
}; | ||
|
||
static void gpio_halt_wfn(struct work_struct *work) | ||
{ | ||
/* Likely wont return */ | ||
orderly_poweroff(true); | ||
} | ||
static DECLARE_WORK(gpio_halt_wq, gpio_halt_wfn); | ||
|
||
static void gpio_halt_cb(void) | ||
{ | ||
enum of_gpio_flags flags; | ||
int trigger, gpio; | ||
|
||
if (!halt_node) | ||
return; | ||
|
||
gpio = of_get_gpio_flags(halt_node, 0, &flags); | ||
|
||
if (!gpio_is_valid(gpio)) | ||
return; | ||
|
||
trigger = (flags == OF_GPIO_ACTIVE_LOW); | ||
|
||
printk(KERN_INFO "gpio-halt: triggering GPIO.\n"); | ||
|
||
/* Probably wont return */ | ||
gpio_set_value(gpio, trigger); | ||
} | ||
|
||
/* This IRQ means someone pressed the power button and it is waiting for us | ||
* to handle the shutdown/poweroff. */ | ||
static irqreturn_t gpio_halt_irq(int irq, void *__data) | ||
{ | ||
printk(KERN_INFO "gpio-halt: shutdown due to power button IRQ.\n"); | ||
schedule_work(&gpio_halt_wq); | ||
|
||
return IRQ_HANDLED; | ||
}; | ||
|
||
static int __devinit gpio_halt_probe(struct platform_device *pdev) | ||
{ | ||
enum of_gpio_flags flags; | ||
struct device_node *node = pdev->dev.of_node; | ||
int gpio, err, irq; | ||
int trigger; | ||
|
||
if (!node) | ||
return -ENODEV; | ||
|
||
/* If there's no matching child, this isn't really an error */ | ||
halt_node = of_find_matching_node(node, child_match); | ||
if (!halt_node) | ||
return 0; | ||
|
||
/* Technically we could just read the first one, but punish | ||
* DT writers for invalid form. */ | ||
if (of_gpio_count(halt_node) != 1) | ||
return -EINVAL; | ||
|
||
/* Get the gpio number relative to the dynamic base. */ | ||
gpio = of_get_gpio_flags(halt_node, 0, &flags); | ||
if (!gpio_is_valid(gpio)) | ||
return -EINVAL; | ||
|
||
err = gpio_request(gpio, "gpio-halt"); | ||
if (err) { | ||
printk(KERN_ERR "gpio-halt: error requesting GPIO %d.\n", | ||
gpio); | ||
halt_node = NULL; | ||
return err; | ||
} | ||
|
||
trigger = (flags == OF_GPIO_ACTIVE_LOW); | ||
|
||
gpio_direction_output(gpio, !trigger); | ||
|
||
/* Now get the IRQ which tells us when the power button is hit */ | ||
irq = irq_of_parse_and_map(halt_node, 0); | ||
err = request_irq(irq, gpio_halt_irq, IRQF_TRIGGER_RISING | | ||
IRQF_TRIGGER_FALLING, "gpio-halt", halt_node); | ||
if (err) { | ||
printk(KERN_ERR "gpio-halt: error requesting IRQ %d for " | ||
"GPIO %d.\n", irq, gpio); | ||
gpio_free(gpio); | ||
halt_node = NULL; | ||
return err; | ||
} | ||
|
||
/* Register our halt function */ | ||
ppc_md.halt = gpio_halt_cb; | ||
ppc_md.power_off = gpio_halt_cb; | ||
|
||
printk(KERN_INFO "gpio-halt: registered GPIO %d (%d trigger, %d" | ||
" irq).\n", gpio, trigger, irq); | ||
|
||
return 0; | ||
} | ||
|
||
static int __devexit gpio_halt_remove(struct platform_device *pdev) | ||
{ | ||
if (halt_node) { | ||
int gpio = of_get_gpio(halt_node, 0); | ||
int irq = irq_of_parse_and_map(halt_node, 0); | ||
|
||
free_irq(irq, halt_node); | ||
|
||
ppc_md.halt = NULL; | ||
ppc_md.power_off = NULL; | ||
|
||
gpio_free(gpio); | ||
|
||
halt_node = NULL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static struct of_device_id gpio_halt_match[] = { | ||
/* We match on the gpio bus itself and scan the children since they | ||
* wont be matched against us. We know the bus wont match until it | ||
* has been registered too. */ | ||
{ | ||
.compatible = "fsl,qoriq-gpio", | ||
}, | ||
{}, | ||
}; | ||
MODULE_DEVICE_TABLE(of, gpio_halt_match); | ||
|
||
static struct platform_driver gpio_halt_driver = { | ||
.driver = { | ||
.name = "gpio-halt", | ||
.owner = THIS_MODULE, | ||
.of_match_table = gpio_halt_match, | ||
}, | ||
.probe = gpio_halt_probe, | ||
.remove = __devexit_p(gpio_halt_remove), | ||
}; | ||
|
||
module_platform_driver(gpio_halt_driver); | ||
|
||
MODULE_DESCRIPTION("Driver to support GPIO triggered system halt for Servergy CTS-1000 Systems."); | ||
MODULE_VERSION("1.0"); | ||
MODULE_AUTHOR("Ben Collins <ben.c@servergy.com>"); | ||
MODULE_LICENSE("GPL"); |