/* * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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, see . */ #include #include #include #include #include #include #include #include #include "gpio-names.h" #include "wakeups.h" extern struct tegra_wake_info *tegra_wake_event_data; extern unsigned int tegra_wake_event_data_size; /* * FIXME: unable to pass rising and falling * flags from usb driver hence using polarity field * from wake table to set wake_mask_any * for selected usb wake sources - VBUS and ID */ static int update_wake_mask(unsigned int index, int flow_type, struct wake_mask_types *wake_msk) { int trigger_val; /* * set wake function calls with flow_type as -1 * set wake type function calls update_wake_mask with * the wake polarity */ if (flow_type == -1) { pr_debug("Wake%d flow_type=%d\n", index, flow_type); /* use argument wake_mask_hi to return mask */ wake_msk->wake_mask_hi |= (1ULL << index); } else { trigger_val = (flow_type & IRQF_TRIGGER_MASK); if ((tegra_wake_event_data[index].polarity == POLARITY_EDGE_ANY) || (trigger_val == (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) { pr_debug("Wake%d flow_type=ANY\n", index); wake_msk->wake_mask_any |= (1ULL << index); } else if ((trigger_val == IRQF_TRIGGER_HIGH) || (trigger_val == IRQF_TRIGGER_RISING)) { pr_debug("Wake%d flow_type=HI\n", index); wake_msk->wake_mask_hi |= (1ULL << index); } else if ((trigger_val == IRQF_TRIGGER_LOW) || (trigger_val == IRQF_TRIGGER_FALLING)) { pr_debug("Wake%d flow_type=LO\n", index); wake_msk->wake_mask_lo |= (1ULL << index); } else { pr_err("Error: Wake%d UNKNOWN flow_type=%d\n", index, flow_type); return -EINVAL; } } return 0; } int tegra_irq_to_wake(unsigned int irq, int flow_type, struct wake_mask_types *wake_msk) { int i; int err; wake_msk->wake_mask_hi = 0ULL; wake_msk->wake_mask_lo = 0ULL; wake_msk->wake_mask_any = 0ULL; /* * check for irq based on tegra_wake_event_data table */ for (i = 0; i < tegra_wake_event_data_size; i++) { if (tegra_wake_event_data[i].irq == irq) { err = update_wake_mask(i, flow_type, wake_msk); if (err) return err; continue; } } if (wake_msk->wake_mask_hi || wake_msk->wake_mask_lo || wake_msk->wake_mask_any) { pr_debug("Enabling wake sources for irq=%d, mask hi=%#llx, lo=%#llx, any=%#llx, flow_type=%d\n", irq, wake_msk->wake_mask_hi, wake_msk->wake_mask_lo, wake_msk->wake_mask_any, flow_type); return 0; } return -EINVAL; } int tegra_wake_to_irq(int wake) { if (wake < 0) return -EINVAL; if (wake >= tegra_wake_event_data_size) return -EINVAL; return tegra_wake_event_data[wake].irq; } int tegra_disable_wake_source(int wake) { if (wake >= tegra_wake_event_data_size) return -EINVAL; tegra_wake_event_data[wake].irq = -EINVAL; return 0; }