Esempio n. 1
0
File: core.c Progetto: 020gzh/linux
int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
{
	const struct pinmux_range *range;
	int pos = 0;

	switch (pinmux_type) {
	case PINMUX_TYPE_GPIO:
	case PINMUX_TYPE_FUNCTION:
		range = NULL;
		break;

	case PINMUX_TYPE_OUTPUT:
		range = &pfc->info->output;
		break;

	case PINMUX_TYPE_INPUT:
		range = &pfc->info->input;
		break;

	default:
		return -EINVAL;
	}

	/* Iterate over all the configuration fields we need to update. */
	while (1) {
		const struct pinmux_cfg_reg *cr;
		unsigned int field;
		u16 enum_id;
		u32 value;
		int in_range;
		int ret;

		pos = sh_pfc_mark_to_enum(pfc, mark, pos, &enum_id);
		if (pos < 0)
			return pos;

		if (!enum_id)
			break;

		/* Check if the configuration field selects a function. If it
		 * doesn't, skip the field if it's not applicable to the
		 * requested pinmux type.
		 */
		in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->function);
		if (!in_range) {
			if (pinmux_type == PINMUX_TYPE_FUNCTION) {
				/* Functions are allowed to modify all
				 * fields.
				 */
				in_range = 1;
			} else if (pinmux_type != PINMUX_TYPE_GPIO) {
				/* Input/output types can only modify fields
				 * that correspond to their respective ranges.
				 */
				in_range = sh_pfc_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;
			}
			/* GPIOs are only allowed to modify function fields. */
		}

		if (!in_range)
			continue;

		ret = sh_pfc_get_config_reg(pfc, enum_id, &cr, &field, &value);
		if (ret < 0)
			return ret;

		sh_pfc_write_config_reg(pfc, cr, field, value);
	}

	return 0;
}
Esempio n. 2
0
int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
{
    const struct pinmux_cfg_reg *cr = NULL;
    pinmux_enum_t enum_id;
    const struct pinmux_range *range;
    int in_range, pos, field, value;
    int ret;

    switch (pinmux_type) {

    case PINMUX_TYPE_FUNCTION:
        range = NULL;
        break;

    case PINMUX_TYPE_OUTPUT:
        range = &pfc->info->output;
        break;

    case PINMUX_TYPE_INPUT:
        range = &pfc->info->input;
        break;

    case PINMUX_TYPE_INPUT_PULLUP:
        range = &pfc->info->input_pu;
        break;

    case PINMUX_TYPE_INPUT_PULLDOWN:
        range = &pfc->info->input_pd;
        break;

    default:
        return -EINVAL;
    }

    pos = 0;
    enum_id = 0;
    field = 0;
    value = 0;
    while (1) {
        pos = sh_pfc_mark_to_enum(pfc, mark, pos, &enum_id);
        if (pos < 0)
            return pos;

        if (!enum_id)
            break;

        /* first check if this is a function enum */
        in_range = sh_pfc_enum_in_range(enum_id, &pfc->info->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 = sh_pfc_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;

        ret = sh_pfc_get_config_reg(pfc, enum_id, &cr, &field, &value);
        if (ret < 0)
            return ret;

        sh_pfc_write_config_reg(pfc, cr, field, value);
    }

    return 0;
}