Commit c8cce6279f5c126cbf6b6054f1ea0148bfc19511

Authored by Hebbar Gururaja
Committed by Satyanarayana Sandhya
1 parent 158e06653b

ARM: OMAP2+: AM33xx: PM: Add support to wakeup via GPIO method for standby

Wakeup from standby mode is supported via GPIO method where peripherals
can be configured as gpios while entering standby and wakeup happens
through gpio interrupt.

This patch provides an method to handle the same through a debugfs
approach.

User should know the IO pads to be configured and the trigger value to
be written to them. The PAD offset & gpio configuration depends mainly
on the wake-up source selected.

Inside <debugfs-mount-dir>/omap_mux/board/ (Directory where these
features are available)

	standby_gpio_pad_conf

standby_gpio_pad_conf
Expected input: pinmux_name=<value1>,<trigger>
	Pin-mux name that is to be setup as gpio during standby
	suspend with gpio interrupt trigger mode as per <trigger> field
	with value <value1>.
	Pin-mux name should be in "mode0_name.mode7_function_name"
	format. Internally the pin-mux offset is calculated from the
	pin-mux names. Invalid pin-mux names and values are ignored.
	Remember,
		- No spaces anywhere in the input.
		- <value1> field is a must
		- <trigger> field is a must and must be one of "rising",
		  "falling"

Example:
echo uart0_rxd.gpio1_10=0x27,rising > standby_gpio_pad_conf
	sets up uart0_rxd.gpio1_10 for gpio mode with interrupt trigger
	as rising and pin-mux value as 0x27 when entering standby mode.

During standby, If "standby_gpio_pad_conf" is configured, then the
respective pin-mux value is saved, the gpio pin-mux mode is selected
for the pin. Relevant gpio settings & interrupts are configured.
During resume, the original values saved are restored back.

User should make sure that the mux mode exists for the selected pin-mux
and the trigger is proper.

When here a duplicate header include (linux/io.h> is removed

Signed-off-by: Hebbar Gururaja <gururaja.hebbar@ti.com>

Showing 3 changed files with 315 additions and 1 deletions Side-by-side Diff

arch/arm/mach-omap2/mux33xx.c
... ... @@ -20,8 +20,11 @@
20 20 #include <linux/slab.h>
21 21 #include <linux/seq_file.h>
22 22 #include <linux/uaccess.h>
23   -#include <linux/io.h>
  23 +#include <linux/gpio.h>
  24 +#include <linux/interrupt.h>
  25 +#include <linux/suspend.h>
24 26  
  27 +#include "cm33xx.h"
25 28 #include "control.h"
26 29 #include "mux.h"
27 30  
... ... @@ -473,6 +476,17 @@
473 476 static u32 susp_io_pad_conf_enabled;
474 477 static struct susp_io_pad_conf pad_array[MAX_IO_PADCONF];
475 478  
  479 +struct standby_gpio_pad_struct {
  480 + u32 enabled;
  481 + u32 gpio_request_success;
  482 + u32 pin_val;
  483 + u32 trigger;
  484 + u32 gpio_pin;
  485 + u32 curr_pin_mux;
  486 +};
  487 +
  488 +static struct standby_gpio_pad_struct standby_gpio_array[MAX_IO_PADCONF];
  489 +
476 490 /*
477 491 * Expected input: 1/0
478 492 * Example: "echo 1 > enable_suspend_io_pad_conf" enables IO PAD Config
... ... @@ -653,6 +667,210 @@
653 667 .release = single_release,
654 668 };
655 669  
  670 +static int standby_gpio_status_show(struct seq_file *s, void *unused)
  671 +{
  672 + struct omap_mux *mux_arr = &am33xx_muxmodes[0];
  673 +
  674 + int i;
  675 +
  676 + for (i = 0; i < MAX_IO_PADCONF;) {
  677 + int off, j, addr_match = 0;
  678 + char *trigger;
  679 +
  680 + if (standby_gpio_array[i].enabled) {
  681 + switch (standby_gpio_array[i].trigger) {
  682 + case IRQF_TRIGGER_RISING:
  683 + trigger = "rising";
  684 + break;
  685 +
  686 + case IRQF_TRIGGER_FALLING:
  687 + trigger = "falling";
  688 + break;
  689 +
  690 + case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
  691 + /* fall through */
  692 + default:
  693 + trigger = "falling_rising";
  694 + break;
  695 + }
  696 +
  697 + seq_printf(s, "%s.%s (0x%08x = 0x%02x), trigger = %s\n",
  698 + mux_arr->muxnames[0],
  699 + mux_arr->muxnames[OMAP_MUX_MODE7],
  700 + (unsigned int)(AM33XX_CONTROL_PADCONF_MUX_PBASE
  701 + + mux_arr->reg_offset),
  702 + standby_gpio_array[i].pin_val,
  703 + trigger);
  704 +
  705 +
  706 + }
  707 +
  708 + /*
  709 + * AM335x pin-mux register offset sequence is broken, meaning
  710 + * there is no pin-mux setting at some offset and at some
  711 + * offsets, the modes are not supposed to be changed. Because
  712 + * of this, the "am33xx_muxmodes" array above will not have any
  713 + * values at these indexes. Hence the standby_gpio_array &
  714 + * am33xx_muxmodes array will be out of sync at these index.
  715 + * Handle missing pin-mux entries accordingly by using a special
  716 + * array that indicate these offsets.
  717 + */
  718 +
  719 + i++;
  720 + off = ((i * 4) + 0x800);
  721 + for (j = 0; j < ARRAY_SIZE(am335x_pin_mux_addr_to_skip); j++) {
  722 + if (off == am335x_pin_mux_addr_to_skip[j]) {
  723 + addr_match = 1;
  724 + break;
  725 + }
  726 + }
  727 + if (addr_match == 0)
  728 + mux_arr++;
  729 + }
  730 +
  731 + return 0;
  732 +}
  733 +
  734 +/*
  735 + * Expected input: pinmux_name=<value1>,<trigger>
  736 + * pinmux_name = Pin-mux name that is to be setup as gpio during standby
  737 + * suspend with gpio interrupt trigger mode as per <trigger> field
  738 + * with value <value1>.
  739 + * Pin-mux name should be in "mode0_name.mode7_function_name"
  740 + * format. Internally the pin-mux offset is calculated from the
  741 + * pin-mux names. Invalid pin-mux names and values are ignored.
  742 + * Remember,
  743 + * - No spaces anywhere in the input.
  744 + * - <value1> field is a must
  745 + * - <trigger> field is a must and must be one of "rising",
  746 + * "falling"
  747 + *
  748 + * Example:
  749 + * echo uart0_rxd.gpio1_10=0x27,rising > standby_gpio_pad_conf
  750 + * sets up uart0_rxd.gpio1_10 for gpio mode with interrupt trigger
  751 + * as rising and pin-mux value as 0x27 when entering standby mode.
  752 + */
  753 +static ssize_t standby_gpio_pad_write(struct file *file,
  754 + const char __user *user_buf,
  755 + size_t count, loff_t *ppos)
  756 +{
  757 + u32 trigger;
  758 + char *export_string, *token, *name;
  759 +
  760 + export_string = kzalloc(count + 1, GFP_KERNEL);
  761 + if (!export_string)
  762 + return -ENOMEM;
  763 +
  764 + if (copy_from_user(export_string, user_buf, count)) {
  765 + kfree(export_string);
  766 + return -EFAULT;
  767 + }
  768 +
  769 + export_string[count-1] = '\0'; /* force null terminator */
  770 + token = export_string;
  771 + name = strsep(&token, "=");
  772 + if (name) {
  773 + struct omap_mux_partition *partition = NULL;
  774 + struct omap_mux *mux = NULL;
  775 + int mux_index, mux_mode, gpio_bank, gpio_pin, res, pin_val;
  776 + char *gpio_name;
  777 +
  778 + mux_mode = omap_mux_get_by_name(name, &partition, &mux);
  779 + if (mux_mode < 0) {
  780 + pr_err("%s: Invalid mux name (%s). Ignoring the"
  781 + " value\n", __func__, name);
  782 + goto err_out;
  783 + }
  784 +
  785 + name = strsep(&token, ",");
  786 + if (!name) {
  787 + pr_err("%s: Invalid value (%s). Ignoring\n",
  788 + __func__, token);
  789 + goto err_out;
  790 + }
  791 +
  792 + res = kstrtouint(name, 0, &pin_val);
  793 + if (res < 0) {
  794 + pr_err("%s: Invalid pin mux value (%s). Ignoring\n",
  795 + __func__, token);
  796 + goto err_out;
  797 + }
  798 +
  799 + if (token && !strncmp("rising", token, 6)) {
  800 + trigger = IRQF_TRIGGER_RISING;
  801 + } else if (token && !strncmp("falling", token, 7)) {
  802 + trigger = IRQF_TRIGGER_FALLING;
  803 + } else {
  804 + pr_err("%s: Invalid trigger (%s). Defaulting to"
  805 + " falling_rising\n", __func__, token);
  806 + trigger = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
  807 + }
  808 +
  809 + /* confirm whether a gpio pin exists here */
  810 + gpio_name = mux->muxnames[OMAP_MUX_MODE7];
  811 +
  812 + if (!gpio_name) {
  813 + pr_err("%s: Invalid mux name (%s)\n", __func__, name);
  814 + goto err_out;
  815 + } else if (strncmp(gpio_name, "gpio", 4)) {
  816 + pr_err("%s: Invalid mux name found (%s)\n",
  817 + __func__, gpio_name);
  818 + goto err_out;
  819 + }
  820 +
  821 + /*
  822 + * parse the string name and get the gpio bank & pin number.
  823 + * gpio_name will be in the format of "gpioX_Y" where
  824 + * X = bank
  825 + * Y = pin number
  826 + */
  827 + gpio_bank = *(gpio_name + 4) - '0';
  828 +
  829 + gpio_name += 6;
  830 + res = kstrtoint(gpio_name, 10, &gpio_pin);
  831 + if (res < 0) {
  832 + pr_err("%s: Invalid gpio pin number (%s). Ignoring\n",
  833 + __func__, gpio_name);
  834 + goto err_out;
  835 + }
  836 +
  837 + mux_index = (mux->reg_offset -
  838 + AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET) / 4;
  839 +
  840 + if (mux_index > MAX_IO_PADCONF) {
  841 + pr_err("%s: Invalid index (0x%x). Ignoring\n",
  842 + __func__, mux_index);
  843 + goto err_out;
  844 + }
  845 +
  846 + standby_gpio_array[mux_index].enabled = true;
  847 + standby_gpio_array[mux_index].pin_val = pin_val;
  848 + standby_gpio_array[mux_index].trigger = trigger;
  849 + standby_gpio_array[mux_index].gpio_pin =
  850 + ((gpio_bank * 32) + gpio_pin);
  851 + } else {
  852 + pr_err("%s: Invalid mux name (%s). Ignoring the entry\n",
  853 + __func__, export_string);
  854 + }
  855 +
  856 +err_out:
  857 + *ppos += count;
  858 + kfree(export_string);
  859 + return count;
  860 +}
  861 +
  862 +static int standby_gpio_pad_open(struct inode *inode, struct file *file)
  863 +{
  864 + return single_open(file, standby_gpio_status_show, inode->i_private);
  865 +}
  866 +
  867 +static const struct file_operations standby_gpio_pad_conf_fops = {
  868 + .open = standby_gpio_pad_open,
  869 + .read = seq_read,
  870 + .write = standby_gpio_pad_write,
  871 + .release = single_release,
  872 +};
  873 +
656 874 void am33xx_mux_dbg_create_entry(struct dentry *mux_dbg_dir)
657 875 {
658 876 struct dentry *mux_dbg_suspend_io_conf_dir;
... ... @@ -680,6 +898,10 @@
680 898 mux_dbg_suspend_io_conf_dir,
681 899 &susp_io_pad_conf_enabled,
682 900 &susp_io_pad_fops);
  901 + (void)debugfs_create_file("standby_gpio_pad_conf", S_IRUGO | S_IWUSR,
  902 + mux_dbg_dir,
  903 + &susp_io_pad_conf_enabled,
  904 + &standby_gpio_pad_conf_fops);
683 905 }
684 906  
685 907 void am33xx_setup_pinmux_on_suspend(void)
... ... @@ -730,6 +952,92 @@
730 952 } else {
731 953 for (i = 0; i < ARRAY_SIZE(am33xx_lp_padconf); i++, temp++)
732 954 writel(temp->val, AM33XX_CTRL_REGADDR(temp->offset));
  955 + }
  956 +}
  957 +
  958 +/*
  959 + * Dummy GPIO interrupt Handler
  960 + */
  961 +static irqreturn_t gpio_irq(int irq, void *dev_id)
  962 +{
  963 + return IRQ_HANDLED;
  964 +}
  965 +
  966 +void am33xx_standby_setup(unsigned int state)
  967 +{
  968 + u32 reg_off, i;
  969 +
  970 + if (state != PM_SUSPEND_STANDBY)
  971 + return;
  972 +
  973 + writel(0x2, AM33XX_CM_PER_GPIO1_CLKCTRL);
  974 + writel(0x2, AM33XX_CM_PER_GPIO2_CLKCTRL);
  975 + writel(0x2, AM33XX_CM_PER_GPIO3_CLKCTRL);
  976 +
  977 + reg_off = AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET;
  978 + for (i = 0; i < MAX_IO_PADCONF; reg_off += 4, i++) {
  979 + if (standby_gpio_array[i].enabled) {
  980 + int ret, reg_val, irq;
  981 + u32 gpio_pin = standby_gpio_array[i].gpio_pin;
  982 +
  983 + reg_val = readl(AM33XX_CTRL_REGADDR(reg_off));
  984 + standby_gpio_array[i].curr_pin_mux = reg_val;
  985 + reg_val = standby_gpio_array[i].pin_val;
  986 + writel(reg_val, AM33XX_CTRL_REGADDR(reg_off));
  987 +
  988 + ret = gpio_request(gpio_pin, "pm_standby");
  989 + if (ret) {
  990 + pr_err("%s: Error in gpio request (%d)\n",
  991 + __func__, ret);
  992 + continue;
  993 + }
  994 + irq = gpio_to_irq(gpio_pin);
  995 + if (irq < 0) {
  996 + gpio_free(gpio_pin);
  997 + pr_err("%s: gpio_to_irq failed (%d)\n",
  998 + __func__, irq);
  999 + continue;
  1000 + }
  1001 + ret = request_irq(irq, gpio_irq,
  1002 + standby_gpio_array[i].trigger,
  1003 + "pm_standby", NULL);
  1004 + if (ret) {
  1005 + gpio_free(gpio_pin);
  1006 + pr_err("%s: interrupt request failed (%d)\n",
  1007 + __func__, ret);
  1008 + continue;
  1009 + }
  1010 +
  1011 + standby_gpio_array[i].gpio_request_success = true;
  1012 + }
  1013 + }
  1014 +
  1015 +}
  1016 +
  1017 +void am33xx_standby_release(unsigned int state)
  1018 +{
  1019 + u32 reg_off, i;
  1020 +
  1021 + if (state != PM_SUSPEND_STANDBY)
  1022 + return;
  1023 +
  1024 + reg_off = AM33XX_CONTROL_PADCONF_GPMC_AD0_OFFSET;
  1025 + for (i = 0; i < MAX_IO_PADCONF; reg_off += 4, i++) {
  1026 + u32 gpio_pin = standby_gpio_array[i].gpio_pin;
  1027 +
  1028 + if (standby_gpio_array[i].enabled) {
  1029 + writel(standby_gpio_array[i].curr_pin_mux,
  1030 + AM33XX_CTRL_REGADDR(reg_off));
  1031 +
  1032 + if (standby_gpio_array[i].gpio_request_success ==
  1033 + true) {
  1034 + int irq;
  1035 +
  1036 + irq = gpio_to_irq(gpio_pin);
  1037 + gpio_free(gpio_pin);
  1038 + free_irq(irq, 0);
  1039 + }
  1040 + }
733 1041 }
734 1042 }
735 1043  
arch/arm/mach-omap2/mux33xx.h
... ... @@ -248,6 +248,10 @@
248 248 struct dentry;
249 249 void am33xx_mux_dbg_create_entry(struct dentry *mux_dbg_dir);
250 250 void am33xx_setup_pinmux_on_suspend(void);
  251 +
  252 +void am33xx_standby_setup(unsigned int state);
  253 +void am33xx_standby_release(unsigned int state);
  254 +
251 255 #endif
252 256  
253 257 #endif
arch/arm/mach-omap2/pm33xx.c
... ... @@ -80,12 +80,14 @@
80 80  
81 81 am335x_save_padconf();
82 82 am33xx_setup_pinmux_on_suspend();
  83 + am33xx_standby_setup(suspend_state);
83 84  
84 85 return ret;
85 86 }
86 87  
87 88 static void am33xx_pm_finish(void)
88 89 {
  90 + am33xx_standby_release(suspend_state);
89 91 am335x_restore_padconf();
90 92 }
91 93