Lines Matching +full:mpp1 +full:- +full:state

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
10 #include <linux/pinctrl/pinconf-generic.h>
18 #include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
21 #include "../pinctrl-utils.h"
26 * Pull Up Values - it indicates whether a pull-up should be
104 * struct pmic_mpp_pad - keep current MPP settings
106 * @is_enabled: Set to false when MPP should be put in high Z state.
112 * @num_sources: Number of power-sources supported by this MPP.
113 * @power_source: Current power-source used.
148 {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0},
149 {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0},
164 "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8",
175 static int pmic_mpp_read(struct pmic_mpp_state *state, in pmic_mpp_read() argument
181 ret = regmap_read(state->map, pad->base + addr, &val); in pmic_mpp_read()
183 dev_err(state->dev, "read 0x%x failed\n", addr); in pmic_mpp_read()
190 static int pmic_mpp_write(struct pmic_mpp_state *state, in pmic_mpp_write() argument
196 ret = regmap_write(state->map, pad->base + addr, val); in pmic_mpp_write()
198 dev_err(state->dev, "write 0x%x failed\n", addr); in pmic_mpp_write()
206 return pctldev->desc->npins; in pmic_mpp_get_groups_count()
212 return pctldev->desc->pins[pin].name; in pmic_mpp_get_group_name()
219 *pins = &pctldev->desc->pins[pin].number; in pmic_mpp_get_group_pins()
249 *num_qgroups = pctldev->desc->npins; in pmic_mpp_get_function_groups()
253 static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, in pmic_mpp_write_mode_ctl() argument
261 switch (pad->function) { in pmic_mpp_write_mode_ctl()
263 if (pad->input_enabled && pad->output_enabled) in pmic_mpp_write_mode_ctl()
265 else if (pad->input_enabled) in pmic_mpp_write_mode_ctl()
271 if (pad->input_enabled && pad->output_enabled) in pmic_mpp_write_mode_ctl()
273 else if (pad->input_enabled) in pmic_mpp_write_mode_ctl()
284 if (pad->dtest) in pmic_mpp_write_mode_ctl()
285 sel = PMIC_MPP_SELECTOR_DTEST_FIRST + pad->dtest - 1; in pmic_mpp_write_mode_ctl()
286 else if (pad->paired) in pmic_mpp_write_mode_ctl()
291 en = !!pad->out_value; in pmic_mpp_write_mode_ctl()
297 return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); in pmic_mpp_write_mode_ctl()
303 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); in pmic_mpp_set_mux() local
308 pad = pctldev->desc->pins[pin].drv_data; in pmic_mpp_set_mux()
310 pad->function = function; in pmic_mpp_set_mux()
312 ret = pmic_mpp_write_mode_ctl(state, pad); in pmic_mpp_set_mux()
316 val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; in pmic_mpp_set_mux()
318 return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); in pmic_mpp_set_mux()
335 pad = pctldev->desc->pins[pin].drv_data; in pmic_mpp_config_get()
339 if (pad->pullup != PMIC_MPP_PULL_UP_OPEN) in pmic_mpp_config_get()
340 return -EINVAL; in pmic_mpp_config_get()
344 switch (pad->pullup) { in pmic_mpp_config_get()
355 return -EINVAL; in pmic_mpp_config_get()
359 if (pad->is_enabled) in pmic_mpp_config_get()
360 return -EINVAL; in pmic_mpp_config_get()
364 arg = pad->power_source; in pmic_mpp_config_get()
367 if (!pad->input_enabled) in pmic_mpp_config_get()
368 return -EINVAL; in pmic_mpp_config_get()
372 arg = pad->out_value; in pmic_mpp_config_get()
375 arg = pad->dtest; in pmic_mpp_config_get()
378 arg = pad->amux_input; in pmic_mpp_config_get()
381 if (!pad->paired) in pmic_mpp_config_get()
382 return -EINVAL; in pmic_mpp_config_get()
386 arg = pad->drive_strength; in pmic_mpp_config_get()
389 arg = pad->aout_level; in pmic_mpp_config_get()
392 return -EINVAL; in pmic_mpp_config_get()
403 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); in pmic_mpp_config_set() local
409 pad = pctldev->desc->pins[pin].drv_data; in pmic_mpp_config_set()
412 pad->is_enabled = true; in pmic_mpp_config_set()
420 pad->pullup = PMIC_MPP_PULL_UP_OPEN; in pmic_mpp_config_set()
425 pad->pullup = PMIC_MPP_PULL_UP_0P6KOHM; in pmic_mpp_config_set()
428 pad->pullup = PMIC_MPP_PULL_UP_10KOHM; in pmic_mpp_config_set()
431 pad->pullup = PMIC_MPP_PULL_UP_30KOHM; in pmic_mpp_config_set()
434 return -EINVAL; in pmic_mpp_config_set()
438 pad->is_enabled = false; in pmic_mpp_config_set()
441 if (arg >= pad->num_sources) in pmic_mpp_config_set()
442 return -EINVAL; in pmic_mpp_config_set()
443 pad->power_source = arg; in pmic_mpp_config_set()
446 pad->input_enabled = arg ? true : false; in pmic_mpp_config_set()
449 pad->output_enabled = true; in pmic_mpp_config_set()
450 pad->out_value = arg; in pmic_mpp_config_set()
453 pad->dtest = arg; in pmic_mpp_config_set()
456 pad->drive_strength = arg; in pmic_mpp_config_set()
460 return -EINVAL; in pmic_mpp_config_set()
461 pad->amux_input = arg; in pmic_mpp_config_set()
464 pad->aout_level = arg; in pmic_mpp_config_set()
467 pad->paired = !!arg; in pmic_mpp_config_set()
470 return -EINVAL; in pmic_mpp_config_set()
474 val = pad->power_source << PMIC_MPP_REG_VIN_SHIFT; in pmic_mpp_config_set()
476 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_VIN_CTL, val); in pmic_mpp_config_set()
480 if (pad->has_pullup) { in pmic_mpp_config_set()
481 val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT; in pmic_mpp_config_set()
483 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, in pmic_mpp_config_set()
489 val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK; in pmic_mpp_config_set()
491 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AIN_CTL, val); in pmic_mpp_config_set()
495 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AOUT_CTL, pad->aout_level); in pmic_mpp_config_set()
499 ret = pmic_mpp_write_mode_ctl(state, pad); in pmic_mpp_config_set()
503 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_SINK_CTL, pad->drive_strength); in pmic_mpp_config_set()
507 val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; in pmic_mpp_config_set()
509 return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); in pmic_mpp_config_set()
515 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); in pmic_mpp_config_dbg_show() local
523 pad = pctldev->desc->pins[pin].drv_data; in pmic_mpp_config_dbg_show()
525 seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); in pmic_mpp_config_dbg_show()
527 if (!pad->is_enabled) { in pmic_mpp_config_dbg_show()
528 seq_puts(s, " ---"); in pmic_mpp_config_dbg_show()
531 if (pad->input_enabled) { in pmic_mpp_config_dbg_show()
532 ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); in pmic_mpp_config_dbg_show()
537 pad->out_value = ret; in pmic_mpp_config_dbg_show()
540 seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); in pmic_mpp_config_dbg_show()
541 seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); in pmic_mpp_config_dbg_show()
542 seq_printf(s, " vin-%d", pad->power_source); in pmic_mpp_config_dbg_show()
543 seq_printf(s, " %d", pad->aout_level); in pmic_mpp_config_dbg_show()
544 if (pad->has_pullup) in pmic_mpp_config_dbg_show()
545 seq_printf(s, " %-8s", biases[pad->pullup]); in pmic_mpp_config_dbg_show()
546 seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); in pmic_mpp_config_dbg_show()
547 if (pad->dtest) in pmic_mpp_config_dbg_show()
548 seq_printf(s, " dtest%d", pad->dtest); in pmic_mpp_config_dbg_show()
549 if (pad->paired) in pmic_mpp_config_dbg_show()
563 struct pmic_mpp_state *state = gpiochip_get_data(chip); in pmic_mpp_direction_input() local
568 return pmic_mpp_config_set(state->ctrl, pin, &config, 1); in pmic_mpp_direction_input()
574 struct pmic_mpp_state *state = gpiochip_get_data(chip); in pmic_mpp_direction_output() local
579 return pmic_mpp_config_set(state->ctrl, pin, &config, 1); in pmic_mpp_direction_output()
584 struct pmic_mpp_state *state = gpiochip_get_data(chip); in pmic_mpp_get() local
588 pad = state->ctrl->desc->pins[pin].drv_data; in pmic_mpp_get()
590 if (pad->input_enabled) { in pmic_mpp_get()
591 ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS); in pmic_mpp_get()
595 pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; in pmic_mpp_get()
598 return !!pad->out_value; in pmic_mpp_get()
603 struct pmic_mpp_state *state = gpiochip_get_data(chip); in pmic_mpp_set() local
608 pmic_mpp_config_set(state->ctrl, pin, &config, 1); in pmic_mpp_set()
615 if (chip->of_gpio_n_cells < 2) in pmic_mpp_of_xlate()
616 return -EINVAL; in pmic_mpp_of_xlate()
619 *flags = gpio_desc->args[1]; in pmic_mpp_of_xlate()
621 return gpio_desc->args[0] - PMIC_MPP_PHYSICAL_OFFSET; in pmic_mpp_of_xlate()
626 struct pmic_mpp_state *state = gpiochip_get_data(chip); in pmic_mpp_dbg_show() local
629 for (i = 0; i < chip->ngpio; i++) { in pmic_mpp_dbg_show()
630 pmic_mpp_config_dbg_show(state->ctrl, s, i); in pmic_mpp_dbg_show()
646 static int pmic_mpp_populate(struct pmic_mpp_state *state, in pmic_mpp_populate() argument
652 type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE); in pmic_mpp_populate()
657 dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n", in pmic_mpp_populate()
658 type, pad->base); in pmic_mpp_populate()
659 return -ENODEV; in pmic_mpp_populate()
662 subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE); in pmic_mpp_populate()
672 pad->num_sources = 4; in pmic_mpp_populate()
675 pad->num_sources = 8; in pmic_mpp_populate()
678 dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n", in pmic_mpp_populate()
679 subtype, pad->base); in pmic_mpp_populate()
680 return -ENODEV; in pmic_mpp_populate()
683 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL); in pmic_mpp_populate()
687 pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK; in pmic_mpp_populate()
694 pad->input_enabled = true; in pmic_mpp_populate()
695 pad->output_enabled = false; in pmic_mpp_populate()
696 pad->function = PMIC_MPP_DIGITAL; in pmic_mpp_populate()
699 pad->input_enabled = false; in pmic_mpp_populate()
700 pad->output_enabled = true; in pmic_mpp_populate()
701 pad->function = PMIC_MPP_DIGITAL; in pmic_mpp_populate()
704 pad->input_enabled = true; in pmic_mpp_populate()
705 pad->output_enabled = true; in pmic_mpp_populate()
706 pad->function = PMIC_MPP_DIGITAL; in pmic_mpp_populate()
709 pad->input_enabled = true; in pmic_mpp_populate()
710 pad->output_enabled = true; in pmic_mpp_populate()
711 pad->function = PMIC_MPP_ANALOG; in pmic_mpp_populate()
714 pad->input_enabled = true; in pmic_mpp_populate()
715 pad->output_enabled = false; in pmic_mpp_populate()
716 pad->function = PMIC_MPP_ANALOG; in pmic_mpp_populate()
719 pad->input_enabled = false; in pmic_mpp_populate()
720 pad->output_enabled = true; in pmic_mpp_populate()
721 pad->function = PMIC_MPP_ANALOG; in pmic_mpp_populate()
724 pad->input_enabled = false; in pmic_mpp_populate()
725 pad->output_enabled = true; in pmic_mpp_populate()
726 pad->function = PMIC_MPP_SINK; in pmic_mpp_populate()
729 dev_err(state->dev, "unknown MPP direction\n"); in pmic_mpp_populate()
730 return -ENODEV; in pmic_mpp_populate()
737 pad->dtest = sel + 1; in pmic_mpp_populate()
739 pad->paired = true; in pmic_mpp_populate()
741 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL); in pmic_mpp_populate()
745 pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT; in pmic_mpp_populate()
746 pad->power_source &= PMIC_MPP_REG_VIN_MASK; in pmic_mpp_populate()
750 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL); in pmic_mpp_populate()
754 pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT; in pmic_mpp_populate()
755 pad->pullup &= PMIC_MPP_REG_PULL_MASK; in pmic_mpp_populate()
756 pad->has_pullup = true; in pmic_mpp_populate()
759 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL); in pmic_mpp_populate()
763 pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; in pmic_mpp_populate()
764 pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; in pmic_mpp_populate()
766 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL); in pmic_mpp_populate()
770 pad->drive_strength = val; in pmic_mpp_populate()
772 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL); in pmic_mpp_populate()
776 pad->aout_level = val; in pmic_mpp_populate()
778 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); in pmic_mpp_populate()
782 pad->is_enabled = !!val; in pmic_mpp_populate()
792 struct pmic_mpp_state *state = container_of(domain->host_data, in pmic_mpp_domain_translate() local
796 if (fwspec->param_count != 2 || in pmic_mpp_domain_translate()
797 fwspec->param[0] < 1 || fwspec->param[0] > state->chip.ngpio) in pmic_mpp_domain_translate()
798 return -EINVAL; in pmic_mpp_domain_translate()
800 *hwirq = fwspec->param[0] - PMIC_MPP_PHYSICAL_OFFSET; in pmic_mpp_domain_translate()
801 *type = fwspec->param[1]; in pmic_mpp_domain_translate()
828 struct device *dev = &pdev->dev; in pmic_mpp_probe()
832 struct pmic_mpp_state *state; in pmic_mpp_probe() local
837 ret = of_property_read_u32(dev->of_node, "reg", &reg); in pmic_mpp_probe()
843 npins = (uintptr_t) device_get_match_data(&pdev->dev); in pmic_mpp_probe()
847 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); in pmic_mpp_probe()
848 if (!state) in pmic_mpp_probe()
849 return -ENOMEM; in pmic_mpp_probe()
851 platform_set_drvdata(pdev, state); in pmic_mpp_probe()
853 state->dev = &pdev->dev; in pmic_mpp_probe()
854 state->map = dev_get_regmap(dev->parent, NULL); in pmic_mpp_probe()
858 return -ENOMEM; in pmic_mpp_probe()
862 return -ENOMEM; in pmic_mpp_probe()
866 return -ENOMEM; in pmic_mpp_probe()
868 pctrldesc->pctlops = &pmic_mpp_pinctrl_ops; in pmic_mpp_probe()
869 pctrldesc->pmxops = &pmic_mpp_pinmux_ops; in pmic_mpp_probe()
870 pctrldesc->confops = &pmic_mpp_pinconf_ops; in pmic_mpp_probe()
871 pctrldesc->owner = THIS_MODULE; in pmic_mpp_probe()
872 pctrldesc->name = dev_name(dev); in pmic_mpp_probe()
873 pctrldesc->pins = pindesc; in pmic_mpp_probe()
874 pctrldesc->npins = npins; in pmic_mpp_probe()
876 pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings); in pmic_mpp_probe()
877 pctrldesc->custom_params = pmic_mpp_bindings; in pmic_mpp_probe()
879 pctrldesc->custom_conf_items = pmic_conf_items; in pmic_mpp_probe()
884 pindesc->drv_data = pad; in pmic_mpp_probe()
885 pindesc->number = i; in pmic_mpp_probe()
886 pindesc->name = pmic_mpp_groups[i]; in pmic_mpp_probe()
888 pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE; in pmic_mpp_probe()
890 ret = pmic_mpp_populate(state, pad); in pmic_mpp_probe()
895 state->chip = pmic_mpp_gpio_template; in pmic_mpp_probe()
896 state->chip.parent = dev; in pmic_mpp_probe()
897 state->chip.base = -1; in pmic_mpp_probe()
898 state->chip.ngpio = npins; in pmic_mpp_probe()
899 state->chip.label = dev_name(dev); in pmic_mpp_probe()
900 state->chip.of_gpio_n_cells = 2; in pmic_mpp_probe()
901 state->chip.can_sleep = false; in pmic_mpp_probe()
903 state->ctrl = devm_pinctrl_register(dev, pctrldesc, state); in pmic_mpp_probe()
904 if (IS_ERR(state->ctrl)) in pmic_mpp_probe()
905 return PTR_ERR(state->ctrl); in pmic_mpp_probe()
907 parent_node = of_irq_find_parent(state->dev->of_node); in pmic_mpp_probe()
909 return -ENXIO; in pmic_mpp_probe()
914 return -ENXIO; in pmic_mpp_probe()
916 state->irq.name = "spmi-mpp", in pmic_mpp_probe()
917 state->irq.irq_ack = irq_chip_ack_parent, in pmic_mpp_probe()
918 state->irq.irq_mask = irq_chip_mask_parent, in pmic_mpp_probe()
919 state->irq.irq_unmask = irq_chip_unmask_parent, in pmic_mpp_probe()
920 state->irq.irq_set_type = irq_chip_set_type_parent, in pmic_mpp_probe()
921 state->irq.irq_set_wake = irq_chip_set_wake_parent, in pmic_mpp_probe()
922 state->irq.flags = IRQCHIP_MASK_ON_SUSPEND, in pmic_mpp_probe()
924 girq = &state->chip.irq; in pmic_mpp_probe()
925 girq->chip = &state->irq; in pmic_mpp_probe()
926 girq->default_type = IRQ_TYPE_NONE; in pmic_mpp_probe()
927 girq->handler = handle_level_irq; in pmic_mpp_probe()
928 girq->fwnode = of_node_to_fwnode(state->dev->of_node); in pmic_mpp_probe()
929 girq->parent_domain = parent_domain; in pmic_mpp_probe()
930 girq->child_to_parent_hwirq = pmic_mpp_child_to_parent_hwirq; in pmic_mpp_probe()
931 girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell; in pmic_mpp_probe()
932 girq->child_offset_to_irq = pmic_mpp_child_offset_to_irq; in pmic_mpp_probe()
933 girq->child_irq_domain_ops.translate = pmic_mpp_domain_translate; in pmic_mpp_probe()
935 ret = gpiochip_add_data(&state->chip, state); in pmic_mpp_probe()
937 dev_err(state->dev, "can't add gpio chip\n"); in pmic_mpp_probe()
941 ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); in pmic_mpp_probe()
950 gpiochip_remove(&state->chip); in pmic_mpp_probe()
956 struct pmic_mpp_state *state = platform_get_drvdata(pdev); in pmic_mpp_remove() local
958 gpiochip_remove(&state->chip); in pmic_mpp_remove()
963 { .compatible = "qcom,pm8019-mpp", .data = (void *) 6 },
964 { .compatible = "qcom,pm8226-mpp", .data = (void *) 8 },
965 { .compatible = "qcom,pm8841-mpp", .data = (void *) 4 },
966 { .compatible = "qcom,pm8916-mpp", .data = (void *) 4 },
967 { .compatible = "qcom,pm8941-mpp", .data = (void *) 8 },
968 { .compatible = "qcom,pm8950-mpp", .data = (void *) 4 },
969 { .compatible = "qcom,pmi8950-mpp", .data = (void *) 4 },
970 { .compatible = "qcom,pm8994-mpp", .data = (void *) 8 },
971 { .compatible = "qcom,pma8084-mpp", .data = (void *) 8 },
972 { .compatible = "qcom,pmi8994-mpp", .data = (void *) 4 },
980 .name = "qcom-spmi-mpp",
989 MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
991 MODULE_ALIAS("platform:qcom-spmi-mpp");