/*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ #include #include #include #include #include "boardparms.h" #include "bcm_gpio.h" #include "bcm_led.h" #include "bcm_map_part.h" #include "bcm_pinmux.h" #include "mach/avm_gpio.h" #include "pushbutton.h" extern spinlock_t bcm_gpio_spinlock; static void brcm_pinctrl_print(unsigned int gpio_pin); static unsigned int bcm_get_pin_diag(unsigned int pin_num); static int brcm_gpio_button_index(unsigned int gpio_pin) { void *iter = NULL; unsigned short bp_index, bp_gpio, bp_ext_irq; while (BpGetButtonInfo(&iter, &bp_index, &bp_gpio, &bp_ext_irq, NULL, NULL, NULL) == BP_SUCCESS) { if ((gpio_pin & BP_GPIO_NUM_MASK) == (bp_gpio & BP_GPIO_NUM_MASK)) return bp_index; } return -1; } /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ int brcm_gpio_init(void) { return GPIO_OK; } /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ int brcm_gpio_ctrl(unsigned int gpio_pin, enum _hw_gpio_function pin_mode, enum _hw_gpio_direction pin_dir) { unsigned long flags; int result = GPIO_FAIL; spin_lock_irqsave(&bcm_gpio_spinlock, flags); if (pin_mode >= 0 && pin_mode < FUNCTION_PIN_NOCHANGE) { bcm_set_pinmux(gpio_pin, pin_mode); BpSetupGpioOptled(gpio_pin, pin_mode); } bcm_gpio_set_dir(gpio_pin, (unsigned int)pin_dir); result = (bcm_gpio_get_dir(gpio_pin) == (unsigned int)pin_dir) ? GPIO_OK : GPIO_FAIL; spin_unlock_irqrestore(&bcm_gpio_spinlock, flags); return result; } EXPORT_SYMBOL(brcm_gpio_ctrl); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ typedef int (*buttonCallback_t)(unsigned int); static buttonCallback_t buttonCallback[PB_BUTTON_MAX]; void pbNotifyHook(unsigned long timeInMs, void *param) { int index = (int)param; int ret; unsigned short idx, gpio, extIrq; pr_debug("[%s] index %d\n", __func__, index); ret = BpGetButtonInfoByIdx(index, &idx, &gpio, &extIrq, NULL, NULL, NULL); if (ret != BP_SUCCESS) return; if (buttonCallback[index] != NULL) (buttonCallback[index])(1 << gpio); } int brcm_button_request_callback(unsigned int mask, enum _hw_gpio_polarity mode, enum _hw_gpio_sensitivity edge, int (*handle_func)(unsigned int)) { unsigned int gpio = ilog2(mask); PB_BUTTON_ID index = (PB_BUTTON_ID)brcm_gpio_button_index(gpio); if (hweight_long((unsigned long)mask) != 1) { pr_err("[%s] MASK MUST HAVE ONE BIT SET! \n", __func__); return -1; } pr_info("[%s] gpio=%x, index=%d mode=%d, edge=%d, func_p=%p\n", __func__, gpio, index, mode, edge, handle_func); if (edge == 0) { pr_err("[%s] LEVEL SENSIVITY NOT SUPPORTED! GPIO: %x\n", __func__, gpio); return -1; } if (registerPushButtonPressNotifyHook(index, pbNotifyHook, (void *)index)) { pr_err("[%s] PRESS HOOK REGISTRATION FAILED! GPIO: %x\n", __func__, gpio); return -1; } if (edge > 1) { if (registerPushButtonReleaseNotifyHook((PB_BUTTON_ID)index, pbNotifyHook, 100UL, (void *)index)) { pr_err("[%s] RELEASE HOOK REGISTRATION FAILED! GPIO: %x\n", __func__, gpio); return -1; } } buttonCallback[index] = handle_func; return index; } EXPORT_SYMBOL(brcm_button_request_callback); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ void brcm_button_disable_callback(int index) { if (index == -1) return; (void)deregisterPushButtonPressNotifyHook((PB_BUTTON_ID)index, pbNotifyHook); (void)deregisterPushButtonReleaseNotifyHook((PB_BUTTON_ID)index, pbNotifyHook, 100UL); buttonCallback[index] = NULL; } EXPORT_SYMBOL(brcm_button_disable_callback); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ int brcm_gpio_out_bit(unsigned int gpio_pin, int value) { unsigned long flags; int result = GPIO_FAIL; spin_lock_irqsave(&bcm_gpio_spinlock, flags); if ((bcm_get_pin_diag(gpio_pin) & 0x7) != GPIO_PIN) { bcm_led_driver_set_dim(gpio_pin, value); } else { bcm_gpio_set_data(gpio_pin, (unsigned int)value); result = (bcm_gpio_get_data(gpio_pin) == (unsigned int)value) ? GPIO_OK : GPIO_FAIL; } spin_unlock_irqrestore(&bcm_gpio_spinlock, flags); return result; } EXPORT_SYMBOL(brcm_gpio_out_bit); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ int brcm_gpio_out_bit_no_sched(unsigned int gpio_pin, int value) { return (brcm_gpio_out_bit(gpio_pin, value)); } EXPORT_SYMBOL(brcm_gpio_out_bit_no_sched); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ int brcm_gpio_in_bit(unsigned int gpio_pin) { unsigned long flags; int result = GPIO_FAIL; spin_lock_irqsave(&bcm_gpio_spinlock, flags); result = (int)bcm_gpio_get_data(gpio_pin); spin_unlock_irqrestore(&bcm_gpio_spinlock, flags); return result; } EXPORT_SYMBOL(brcm_gpio_in_bit); /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ void brcm_gpio_set_bitmask(uint64_t mask, uint64_t value) { unsigned long flags; spin_lock_irqsave(&bcm_gpio_spinlock, flags); bcm_gpio_set_bitmask(mask, value); spin_unlock_irqrestore(&bcm_gpio_spinlock, flags); return; } EXPORT_SYMBOL(brcm_gpio_set_bitmask); /*----------------------------------------------------------------------------*\ * ret: negval -> not found/no range/no match \*----------------------------------------------------------------------------*/ static int generic_gpio_param_parse(char *string, char *match, int maxval, char *matchstrg1, char *matchstrg2) { char *p = string; int ret = -1; if ((p = strstr(string, match))) { p += strlen(match); while (*p == ' ' || *p == '\t') p++; if (matchstrg1 && strncmp(p, matchstrg1, strlen(matchstrg1)) == 0) { ret = 0; } else if (matchstrg2 && strncmp(p, matchstrg2, strlen(matchstrg2)) == 0) { ret = 1; } else if (*p) { sscanf(p, "%d", &ret); if (ret > maxval) { ret = -1; } } } return ret; } /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static int brcm_gpio_set(char *string, void *priv __maybe_unused) { int gpio, dir, set, mux; gpio = generic_gpio_param_parse(string, "gpio", GPIO_NUM_MAX - 1, NULL, NULL); dir = generic_gpio_param_parse(string, "dir=", 0, "in", "out"); set = generic_gpio_param_parse(string, "set=", 255, NULL, NULL); mux = generic_gpio_param_parse(string, "mux=", FUNCTION_PINMUX7, NULL, NULL); if ((gpio < 0) || (strstr(string, "help"))) { printk(KERN_ERR "use: gpio dir= set=<0..255> mux=<0..7>\n"); return 0; } if (dir >= 0 || mux >= 0) { brcm_gpio_ctrl(gpio, mux, dir); } if (set >= 0) { brcm_gpio_out_bit(gpio, set); } brcm_pinctrl_print(gpio); return 0; } #define READ_SELECT_CMD 0x23 /* see 63178-PR100 pg. 2185 */ static unsigned int bcm_get_pin_diag(unsigned int pin_num) { GPIO->TestPortBlockDataMSB = 0; GPIO->TestPortBlockDataLSB = pin_num; GPIO->TestPortCmd = READ_SELECT_CMD; return GPIO->DiagReadBack; } /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static void brcm_gpio_list(struct seq_file *seq, void *priv) { unsigned int gpio_pin, gpio_start = 0, gpio_end = GPIO_NUM_MAX - 1, val; if (priv) { gpio_start = (unsigned int)priv; gpio_end = gpio_start; if (gpio_start >= GPIO_NUM_MAX - 1) { return; } } for (gpio_pin = gpio_start; gpio_pin <= gpio_end; gpio_pin++) { unsigned int dir = bcm_gpio_get_dir(gpio_pin); unsigned int diag = bcm_get_pin_diag(gpio_pin); val = bcm_gpio_get_data(gpio_pin); seq_printf(seq, "gpio%02u %s pinmux=%x%s val=%x diag=%08x\n", gpio_pin, dir ? "OUT" : "IN ", diag & 0x7, (diag & 0x7) == GPIO_PIN ? "(GPIO)" : "", val, diag); } } /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static void brcm_pinctrl_print(unsigned int gpio_pin) { char txtbuf[256]; struct seq_file s; memset(&s, 0, sizeof(s)); txtbuf[0] = 0; s.buf = txtbuf; s.size = sizeof(txtbuf); brcm_gpio_list(&s, (void *)gpio_pin); printk(KERN_ERR "%s", txtbuf); } static struct proc_dir_entry *gpioprocdir; /*----------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------*/ static int __init avm_gpioproc_init(void) { #define PROC_GPIODIR "avm/gpio" gpioprocdir = proc_mkdir(PROC_GPIODIR, NULL); if (gpioprocdir == NULL) { return 0; } add_simple_proc_file("avm/gpio/list", NULL, brcm_gpio_list, NULL); add_simple_proc_file("avm/gpio/set", brcm_gpio_set, NULL, NULL); return 0; } late_initcall(avm_gpioproc_init);