blob: 032ceae6f8d12a37ea6e7438cbb7253555fd3197 [file] [log] [blame] [edit]
/* Control power to pn544
*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wakelock.h>
#include <plat/serial.h>
#include "mux.h"
#define GPIO_NFC_EN 173
#define GPIO_NFC_FW 172
#define GPIO_NFC_IRQ 17
#define PWR_OFF 0
#define PWR_ON 1
#define PWR_ON_FW 2
#define NFC_UART_NUM 4 /* omap_uart_wake() counts from 1 */
static unsigned int nfc_power;
static struct wake_lock nfc_wake_lock;
static void nfc_power_apply(void) {
switch (nfc_power) {
case PWR_OFF:
pr_info("%s OFF\n", __func__);
gpio_set_value(GPIO_NFC_FW, 0);
gpio_set_value(GPIO_NFC_EN, 0);
msleep(60);
break;
case PWR_ON:
pr_info("%s ON\n", __func__);
gpio_set_value(GPIO_NFC_FW, 0);
gpio_set_value(GPIO_NFC_EN, 1);
msleep(20);
break;
case PWR_ON_FW:
pr_info("%s ON (firmware download)\n", __func__);
gpio_set_value(GPIO_NFC_FW, 1);
gpio_set_value(GPIO_NFC_EN, 1);
msleep(20);
gpio_set_value(GPIO_NFC_EN, 0); /* fw mode requires reset */
msleep(60);
gpio_set_value(GPIO_NFC_EN, 1);
msleep(20);
break;
}
}
static ssize_t nfc_power_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", nfc_power);
}
static ssize_t nfc_power_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
unsigned int val;
rc = kstrtouint(buf, 0, &val);
if (rc < 0)
return rc;
if (val > PWR_ON_FW)
return -EINVAL;
nfc_power = val;
nfc_power_apply();
return count;
}
static DEVICE_ATTR(nfc_power, S_IWUSR | S_IRUGO, nfc_power_show,
nfc_power_store);
static irqreturn_t nfc_irq_isr(int irq, void *dev)
{
omap_uart_wake(NFC_UART_NUM);
/*
* take a 500ms wakelock, to give time for higher layers
* to either take their own wakelock or finish processing
*/
wake_lock_timeout(&nfc_wake_lock, msecs_to_jiffies(500));
return IRQ_HANDLED;
}
void __init omap4_tuna_nfc_init(void)
{
struct platform_device *pdev;
int irq;
gpio_request(GPIO_NFC_FW, "nfc_fw");
gpio_direction_output(GPIO_NFC_FW, 0);
omap_mux_init_gpio(GPIO_NFC_FW, OMAP_PIN_OUTPUT);
gpio_request(GPIO_NFC_EN, "nfc_en");
gpio_direction_output(GPIO_NFC_EN, 0);
omap_mux_init_gpio(GPIO_NFC_EN, OMAP_PIN_OUTPUT);
gpio_request(GPIO_NFC_IRQ, "nfc_irq");
gpio_direction_input(GPIO_NFC_IRQ);
omap_mux_init_gpio(GPIO_NFC_IRQ, OMAP_PIN_INPUT_PULLUP |
OMAP_PIN_OFF_WAKEUPENABLE);
wake_lock_init(&nfc_wake_lock, WAKE_LOCK_SUSPEND, "nfc");
irq = gpio_to_irq(GPIO_NFC_IRQ);
if (request_irq(irq, nfc_irq_isr, IRQF_TRIGGER_RISING, "nfc_irq",
NULL)) {
pr_err("%s: request_irq() failed\n", __func__);
return;
}
if (enable_irq_wake(irq)) {
pr_err("%s: irq_set_irq_wake() failed\n", __func__);
return;
}
nfc_power = PWR_OFF;
pdev = platform_device_register_simple("nfc-power", -1, NULL, 0);
if (IS_ERR(pdev)) {
pr_err("%s: platform_device_register_simple() failed\n", __func__);
return;
}
if (device_create_file(&pdev->dev, &dev_attr_nfc_power))
pr_err("%s: device_create_file() failed\n", __func__);
}