Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 273267
b: refs/heads/master
c: 1615204
h: refs/heads/master
i:
  273265: ef0d8c6
  273263: 44fbafd
v: v3
  • Loading branch information
James Nuss authored and Linus Torvalds committed Nov 2, 2011
1 parent 17e792f commit cb3f132
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 437c53418616973071fd2d7c87497780944d8fdb
refs/heads/master: 161520451dfacd0eb79d501933f47d3fb7464938
9 changes: 9 additions & 0 deletions trunk/drivers/pps/clients/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,13 @@ config PPS_CLIENT_PARPORT
If you say yes here you get support for a PPS source connected
with the interrupt pin of your parallel port.

config PPS_CLIENT_GPIO
tristate "PPS client using GPIO"
depends on PPS
help
If you say yes here you get support for a PPS source using
GPIO. To be useful you must also register a platform device
specifying the GPIO pin and other options, usually in your board
setup.

endif
1 change: 1 addition & 0 deletions trunk/drivers/pps/clients/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o

ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
227 changes: 227 additions & 0 deletions trunk/drivers/pps/clients/pps-gpio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
* pps-gpio.c -- PPS client driver using GPIO
*
*
* Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define PPS_GPIO_NAME "pps-gpio"
#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pps_kernel.h>
#include <linux/pps-gpio.h>
#include <linux/gpio.h>
#include <linux/list.h>

/* Info for each registered platform device */
struct pps_gpio_device_data {
int irq; /* IRQ used as PPS source */
struct pps_device *pps; /* PPS source device */
struct pps_source_info info; /* PPS source information */
const struct pps_gpio_platform_data *pdata;
};

/*
* Report the PPS event
*/

static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
{
const struct pps_gpio_device_data *info;
struct pps_event_time ts;
int rising_edge;

/* Get the time stamp first */
pps_get_ts(&ts);

info = data;

rising_edge = gpio_get_value(info->pdata->gpio_pin);
if ((rising_edge && !info->pdata->assert_falling_edge) ||
(!rising_edge && info->pdata->assert_falling_edge))
pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
else if (info->pdata->capture_clear &&
((rising_edge && info->pdata->assert_falling_edge) ||
(!rising_edge && !info->pdata->assert_falling_edge)))
pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);

return IRQ_HANDLED;
}

static int pps_gpio_setup(struct platform_device *pdev)
{
int ret;
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;

ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
if (ret) {
pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
return -EINVAL;
}

ret = gpio_direction_input(pdata->gpio_pin);
if (ret) {
pr_warning("failed to set pin direction\n");
gpio_free(pdata->gpio_pin);
return -EINVAL;
}

return 0;
}

static unsigned long
get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
{
unsigned long flags = pdata->assert_falling_edge ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;

if (pdata->capture_clear) {
flags |= ((flags & IRQF_TRIGGER_RISING) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
}

return flags;
}

static int pps_gpio_probe(struct platform_device *pdev)
{
struct pps_gpio_device_data *data;
int irq;
int ret;
int err;
int pps_default_params;
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;


/* GPIO setup */
ret = pps_gpio_setup(pdev);
if (ret)
return -EINVAL;

/* IRQ setup */
irq = gpio_to_irq(pdata->gpio_pin);
if (irq < 0) {
pr_err("failed to map GPIO to IRQ: %d\n", irq);
err = -EINVAL;
goto return_error;
}

/* allocate space for device info */
data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
if (data == NULL) {
err = -ENOMEM;
goto return_error;
}

/* initialize PPS specific parts of the bookkeeping data structure. */
data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
if (pdata->capture_clear)
data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
PPS_ECHOCLEAR;
data->info.owner = THIS_MODULE;
snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
pdev->name, pdev->id);

/* register PPS source */
pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
if (pdata->capture_clear)
pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
data->pps = pps_register_source(&data->info, pps_default_params);
if (data->pps == NULL) {
kfree(data);
pr_err("failed to register IRQ %d as PPS source\n", irq);
err = -EINVAL;
goto return_error;
}

data->irq = irq;
data->pdata = pdata;

/* register IRQ interrupt handler */
ret = request_irq(irq, pps_gpio_irq_handler,
get_irqf_trigger_flags(pdata), data->info.name, data);
if (ret) {
pps_unregister_source(data->pps);
kfree(data);
pr_err("failed to acquire IRQ %d\n", irq);
err = -EINVAL;
goto return_error;
}

platform_set_drvdata(pdev, data);
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);

return 0;

return_error:
gpio_free(pdata->gpio_pin);
return err;
}

static int pps_gpio_remove(struct platform_device *pdev)
{
struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
const struct pps_gpio_platform_data *pdata = data->pdata;

platform_set_drvdata(pdev, NULL);
free_irq(data->irq, data);
gpio_free(pdata->gpio_pin);
pps_unregister_source(data->pps);
pr_info("removed IRQ %d as PPS source\n", data->irq);
kfree(data);
return 0;
}

static struct platform_driver pps_gpio_driver = {
.probe = pps_gpio_probe,
.remove = __devexit_p(pps_gpio_remove),
.driver = {
.name = PPS_GPIO_NAME,
.owner = THIS_MODULE
},
};

static int __init pps_gpio_init(void)
{
int ret = platform_driver_register(&pps_gpio_driver);
if (ret < 0)
pr_err("failed to register platform driver\n");
return ret;
}

static void __exit pps_gpio_exit(void)
{
platform_driver_unregister(&pps_gpio_driver);
pr_debug("unregistered platform driver\n");
}

module_init(pps_gpio_init);
module_exit(pps_gpio_exit);

MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
MODULE_DESCRIPTION("Use GPIO pin as PPS source");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
32 changes: 32 additions & 0 deletions trunk/include/linux/pps-gpio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* pps-gpio.h -- PPS client for GPIOs
*
*
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef _PPS_GPIO_H
#define _PPS_GPIO_H

struct pps_gpio_platform_data {
bool assert_falling_edge;
bool capture_clear;
unsigned int gpio_pin;
const char *gpio_label;
};

#endif

0 comments on commit cb3f132

Please sign in to comment.