static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, int pos, pinmux_enum_t *enum_idp) { pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; pinmux_enum_t *data = gpioc->gpio_data; int k; if (!enum_in_range(enum_id, &gpioc->data)) { if (!enum_in_range(enum_id, &gpioc->mark)) { pr_err("non data/mark enum_id for gpio %d\n", gpio); return -1; } } if (pos) { *enum_idp = data[pos + 1]; return pos + 1; } for (k = 0; k < gpioc->gpio_data_size; k++) { if (data[k] == enum_id) { *enum_idp = data[k + 1]; return k + 1; } } pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio); return -1; }
static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) { struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; struct pinmux_data_reg *data_reg; int k, n; if (!enum_in_range(gpiop->enum_id, &gpioc->data)) return -1; k = 0; while (1) { data_reg = gpioc->data_regs + k; if (!data_reg->reg_width) break; for (n = 0; n < data_reg->reg_width; n++) { if (data_reg->enum_ids[n] == gpiop->enum_id) { gpiop->flags &= ~PINMUX_FLAG_DREG; gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); gpiop->flags &= ~PINMUX_FLAG_DBIT; gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); return 0; } } k++; } BUG(); return -1; }
static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, struct pinmux_data_reg **drp, int *bitp) { pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; struct pinmux_data_reg *data_reg; int k, n; if (!enum_in_range(enum_id, &gpioc->data)) return -1; k = 0; while (1) { data_reg = gpioc->data_regs + k; if (!data_reg->reg_width) break; for (n = 0; n < data_reg->reg_width; n++) { if (data_reg->enum_ids[n] == enum_id) { *drp = data_reg; *bitp = n; return 0; } } k++; } return -1; }
static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, struct pinmux_data_reg **drp, int *bitp) { struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; int k, n; if (!enum_in_range(gpiop->enum_id, &gpioc->data)) return -1; k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; *drp = gpioc->data_regs + k; *bitp = n; return 0; }
static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, int pinmux_type, int cfg_mode) { struct pinmux_cfg_reg *cr = NULL; pinmux_enum_t enum_id; struct pinmux_range *range; int in_range, pos, index; unsigned long *cntp; switch (pinmux_type) { case PINMUX_TYPE_FUNCTION: range = NULL; break; case PINMUX_TYPE_OUTPUT: range = &gpioc->output; break; case PINMUX_TYPE_INPUT: range = &gpioc->input; break; case PINMUX_TYPE_INPUT_PULLUP: range = &gpioc->input_pu; break; case PINMUX_TYPE_INPUT_PULLDOWN: range = &gpioc->input_pd; break; default: goto out_err; } pos = 0; enum_id = 0; index = 0; while (1) { pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); if (pos <= 0) goto out_err; if (!enum_id) break; in_range = enum_in_range(enum_id, &gpioc->function); if (!in_range && range) { in_range = enum_in_range(enum_id, range); if (in_range && enum_id == range->force) continue; } if (!in_range) continue; if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) goto out_err; switch (cfg_mode) { case GPIO_CFG_DRYRUN: if (!*cntp || !check_config_reg(gpioc, cr, index)) continue; break; case GPIO_CFG_REQ: write_config_reg(gpioc, cr, index); *cntp = *cntp + 1; break; case GPIO_CFG_FREE: *cntp = *cntp - 1; break; } } return 0; out_err: return -1; }
static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, int pinmux_type, int cfg_mode) { struct pinmux_cfg_reg *cr = NULL; pinmux_enum_t enum_id; struct pinmux_range *range; int in_range, pos, field, value; unsigned long *cntp; switch (pinmux_type) { case PINMUX_TYPE_FUNCTION: range = NULL; break; case PINMUX_TYPE_OUTPUT: range = &gpioc->output; break; case PINMUX_TYPE_INPUT: range = &gpioc->input; break; case PINMUX_TYPE_INPUT_PULLUP: range = &gpioc->input_pu; break; case PINMUX_TYPE_INPUT_PULLDOWN: range = &gpioc->input_pd; break; default: goto out_err; } pos = 0; enum_id = 0; field = 0; value = 0; while (1) { pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); if (pos <= 0) goto out_err; if (!enum_id) break; /* first check if this is a function enum */ in_range = enum_in_range(enum_id, &gpioc->function); if (!in_range) { /* not a function enum */ if (range) { /* * other range exists, so this pin is * a regular GPIO pin that now is being * bound to a specific direction. * * for this case we only allow function enums * and the enums that match the other range. */ in_range = enum_in_range(enum_id, range); /* * special case pass through for fixed * input-only or output-only pins without * function enum register association. */ if (in_range && enum_id == range->force) continue; } else { /* * no other range exists, so this pin * must then be of the function type. * * allow function type pins to select * any combination of function/in/out * in their MARK lists. */ in_range = 1; } } if (!in_range) continue; if (get_config_reg(gpioc, enum_id, &cr, &field, &value, &cntp) != 0) goto out_err; switch (cfg_mode) { case GPIO_CFG_DRYRUN: if (!*cntp || (read_config_reg(gpioc, cr, field) != value)) continue; break; case GPIO_CFG_REQ: write_config_reg(gpioc, cr, field, value); *cntp = *cntp + 1; break; case GPIO_CFG_FREE: *cntp = *cntp - 1; break; } } return 0; out_err: return -1; }