^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Second generation of pinmux driver for Amlogic Meson-AXG SoC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2017 Baylibre SAS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Jerome Brunet <jbrunet@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2017 Amlogic, Inc. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Xingyu Chen <xingyu.chen@amlogic.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * SPDX-License-Identifier: (GPL-2.0+ or MIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * This new generation of pinctrl IP is mainly adopted by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Meson-AXG SoC and later series, which use 4-width continuous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * register bit to select the function for each pin.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * The value 0 is always selecting the GPIO mode, while other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * values (start from 1) for selecting the function mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/pinctrl/pinctrl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/pinctrl/pinmux.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "pinctrl-meson.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "pinctrl-meson-axg-pmx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int meson_axg_pmx_get_bank(struct meson_pinctrl *pc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int pin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct meson_pmx_bank **bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct meson_axg_pmx_data *pmx = pc->data->pmx_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) for (i = 0; i < pmx->num_pmx_banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (pin >= pmx->pmx_banks[i].first &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) pin <= pmx->pmx_banks[i].last) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *bank = &pmx->pmx_banks[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int meson_pmx_calc_reg_and_offset(struct meson_pmx_bank *bank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned int pin, unsigned int *reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned int *offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) shift = pin - bank->first;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *reg = bank->reg + (bank->offset + (shift << 2)) / 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *offset = (bank->offset + (shift << 2)) % 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static int meson_axg_pmx_update_function(struct meson_pinctrl *pc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned int pin, unsigned int func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct meson_pmx_bank *bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ret = meson_axg_pmx_get_bank(pc, pin, &bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) meson_pmx_calc_reg_and_offset(bank, pin, ®, &offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ret = regmap_update_bits(pc->reg_mux, reg << 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) 0xf << offset, (func & 0xf) << offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int meson_axg_pmx_set_mux(struct pinctrl_dev *pcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned int func_num, unsigned int group_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct meson_pmx_func *func = &pc->data->funcs[func_num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct meson_pmx_group *group = &pc->data->groups[group_num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct meson_pmx_axg_data *pmx_data =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) (struct meson_pmx_axg_data *)group->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) dev_dbg(pc->dev, "enable function %s, group %s\n", func->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) group->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) for (i = 0; i < group->num_pins; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = meson_axg_pmx_update_function(pc, group->pins[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) pmx_data->func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static int meson_axg_pmx_request_gpio(struct pinctrl_dev *pcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct pinctrl_gpio_range *range, unsigned int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return meson_axg_pmx_update_function(pc, offset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) const struct pinmux_ops meson_axg_pmx_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .set_mux = meson_axg_pmx_set_mux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .get_functions_count = meson_pmx_get_funcs_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .get_function_name = meson_pmx_get_func_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .get_function_groups = meson_pmx_get_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .gpio_request_enable = meson_axg_pmx_request_gpio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) EXPORT_SYMBOL_GPL(meson_axg_pmx_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) MODULE_LICENSE("Dual BSD/GPL");