in qcom/pinctrl-spmi-mpp.c [646:785]
static int pmic_mpp_populate(struct pmic_mpp_state *state,
struct pmic_mpp_pad *pad)
{
int type, subtype, val, dir;
unsigned int sel;
type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE);
if (type < 0)
return type;
if (type != PMIC_MPP_TYPE) {
dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
type, pad->base);
return -ENODEV;
}
subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE);
if (subtype < 0)
return subtype;
switch (subtype) {
case PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT:
case PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
case PMIC_MPP_SUBTYPE_4CH_NO_SINK:
case PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK:
case PMIC_MPP_SUBTYPE_4CH_FULL_FUNC:
pad->num_sources = 4;
break;
case PMIC_MPP_SUBTYPE_8CH_FULL_FUNC:
pad->num_sources = 8;
break;
default:
dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n",
subtype, pad->base);
return -ENODEV;
}
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL);
if (val < 0)
return val;
pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK;
dir = val >> PMIC_MPP_REG_MODE_DIR_SHIFT;
dir &= PMIC_MPP_REG_MODE_DIR_MASK;
switch (dir) {
case PMIC_MPP_MODE_DIGITAL_INPUT:
pad->input_enabled = true;
pad->output_enabled = false;
pad->function = PMIC_MPP_DIGITAL;
break;
case PMIC_MPP_MODE_DIGITAL_OUTPUT:
pad->input_enabled = false;
pad->output_enabled = true;
pad->function = PMIC_MPP_DIGITAL;
break;
case PMIC_MPP_MODE_DIGITAL_BIDIR:
pad->input_enabled = true;
pad->output_enabled = true;
pad->function = PMIC_MPP_DIGITAL;
break;
case PMIC_MPP_MODE_ANALOG_BIDIR:
pad->input_enabled = true;
pad->output_enabled = true;
pad->function = PMIC_MPP_ANALOG;
break;
case PMIC_MPP_MODE_ANALOG_INPUT:
pad->input_enabled = true;
pad->output_enabled = false;
pad->function = PMIC_MPP_ANALOG;
break;
case PMIC_MPP_MODE_ANALOG_OUTPUT:
pad->input_enabled = false;
pad->output_enabled = true;
pad->function = PMIC_MPP_ANALOG;
break;
case PMIC_MPP_MODE_CURRENT_SINK:
pad->input_enabled = false;
pad->output_enabled = true;
pad->function = PMIC_MPP_SINK;
break;
default:
dev_err(state->dev, "unknown MPP direction\n");
return -ENODEV;
}
sel = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
sel &= PMIC_MPP_REG_MODE_FUNCTION_MASK;
if (sel >= PMIC_MPP_SELECTOR_DTEST_FIRST)
pad->dtest = sel + 1;
else if (sel == PMIC_MPP_SELECTOR_PAIRED)
pad->paired = true;
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL);
if (val < 0)
return val;
pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT;
pad->power_source &= PMIC_MPP_REG_VIN_MASK;
if (subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT &&
subtype != PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK) {
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL);
if (val < 0)
return val;
pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT;
pad->pullup &= PMIC_MPP_REG_PULL_MASK;
pad->has_pullup = true;
}
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL);
if (val < 0)
return val;
pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT;
pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK;
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL);
if (val < 0)
return val;
pad->drive_strength = val;
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL);
if (val < 0)
return val;
pad->aout_level = val;
val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL);
if (val < 0)
return val;
pad->is_enabled = !!val;
return 0;
}