1*c0f84760SKrzysztof Kozlowski // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
20fabe43fSXingyu Chen /*
30fabe43fSXingyu Chen * Second generation of pinmux driver for Amlogic Meson-AXG SoC.
40fabe43fSXingyu Chen *
50fabe43fSXingyu Chen * Copyright (c) 2017 Baylibre SAS.
60fabe43fSXingyu Chen * Author: Jerome Brunet <jbrunet@baylibre.com>
70fabe43fSXingyu Chen *
80fabe43fSXingyu Chen * Copyright (c) 2017 Amlogic, Inc. All rights reserved.
90fabe43fSXingyu Chen * Author: Xingyu Chen <xingyu.chen@amlogic.com>
100fabe43fSXingyu Chen */
110fabe43fSXingyu Chen
120fabe43fSXingyu Chen /*
130fabe43fSXingyu Chen * This new generation of pinctrl IP is mainly adopted by the
140fabe43fSXingyu Chen * Meson-AXG SoC and later series, which use 4-width continuous
150fabe43fSXingyu Chen * register bit to select the function for each pin.
160fabe43fSXingyu Chen *
170fabe43fSXingyu Chen * The value 0 is always selecting the GPIO mode, while other
180fabe43fSXingyu Chen * values (start from 1) for selecting the function mode.
190fabe43fSXingyu Chen */
200fabe43fSXingyu Chen #include <linux/device.h>
210fabe43fSXingyu Chen #include <linux/regmap.h>
220fabe43fSXingyu Chen #include <linux/pinctrl/pinctrl.h>
230fabe43fSXingyu Chen #include <linux/pinctrl/pinmux.h>
240fabe43fSXingyu Chen
250fabe43fSXingyu Chen #include "pinctrl-meson.h"
260fabe43fSXingyu Chen #include "pinctrl-meson-axg-pmx.h"
270fabe43fSXingyu Chen
meson_axg_pmx_get_bank(struct meson_pinctrl * pc,unsigned int pin,struct meson_pmx_bank ** bank)280fabe43fSXingyu Chen static int meson_axg_pmx_get_bank(struct meson_pinctrl *pc,
290fabe43fSXingyu Chen unsigned int pin,
300fabe43fSXingyu Chen struct meson_pmx_bank **bank)
310fabe43fSXingyu Chen {
320fabe43fSXingyu Chen int i;
330fabe43fSXingyu Chen struct meson_axg_pmx_data *pmx = pc->data->pmx_data;
340fabe43fSXingyu Chen
350fabe43fSXingyu Chen for (i = 0; i < pmx->num_pmx_banks; i++)
360fabe43fSXingyu Chen if (pin >= pmx->pmx_banks[i].first &&
370fabe43fSXingyu Chen pin <= pmx->pmx_banks[i].last) {
380fabe43fSXingyu Chen *bank = &pmx->pmx_banks[i];
390fabe43fSXingyu Chen return 0;
400fabe43fSXingyu Chen }
410fabe43fSXingyu Chen
420fabe43fSXingyu Chen return -EINVAL;
430fabe43fSXingyu Chen }
440fabe43fSXingyu Chen
meson_pmx_calc_reg_and_offset(struct meson_pmx_bank * bank,unsigned int pin,unsigned int * reg,unsigned int * offset)450fabe43fSXingyu Chen static int meson_pmx_calc_reg_and_offset(struct meson_pmx_bank *bank,
460fabe43fSXingyu Chen unsigned int pin, unsigned int *reg,
470fabe43fSXingyu Chen unsigned int *offset)
480fabe43fSXingyu Chen {
490fabe43fSXingyu Chen int shift;
500fabe43fSXingyu Chen
510fabe43fSXingyu Chen shift = pin - bank->first;
520fabe43fSXingyu Chen
530fabe43fSXingyu Chen *reg = bank->reg + (bank->offset + (shift << 2)) / 32;
540fabe43fSXingyu Chen *offset = (bank->offset + (shift << 2)) % 32;
550fabe43fSXingyu Chen
560fabe43fSXingyu Chen return 0;
570fabe43fSXingyu Chen }
580fabe43fSXingyu Chen
meson_axg_pmx_update_function(struct meson_pinctrl * pc,unsigned int pin,unsigned int func)590fabe43fSXingyu Chen static int meson_axg_pmx_update_function(struct meson_pinctrl *pc,
600fabe43fSXingyu Chen unsigned int pin, unsigned int func)
610fabe43fSXingyu Chen {
620fabe43fSXingyu Chen int ret;
630fabe43fSXingyu Chen int reg;
640fabe43fSXingyu Chen int offset;
650fabe43fSXingyu Chen struct meson_pmx_bank *bank;
660fabe43fSXingyu Chen
670fabe43fSXingyu Chen ret = meson_axg_pmx_get_bank(pc, pin, &bank);
680fabe43fSXingyu Chen if (ret)
690fabe43fSXingyu Chen return ret;
700fabe43fSXingyu Chen
710fabe43fSXingyu Chen meson_pmx_calc_reg_and_offset(bank, pin, ®, &offset);
720fabe43fSXingyu Chen
730fabe43fSXingyu Chen ret = regmap_update_bits(pc->reg_mux, reg << 2,
740fabe43fSXingyu Chen 0xf << offset, (func & 0xf) << offset);
750fabe43fSXingyu Chen
760fabe43fSXingyu Chen return ret;
770fabe43fSXingyu Chen }
780fabe43fSXingyu Chen
meson_axg_pmx_set_mux(struct pinctrl_dev * pcdev,unsigned int func_num,unsigned int group_num)790fabe43fSXingyu Chen static int meson_axg_pmx_set_mux(struct pinctrl_dev *pcdev,
800fabe43fSXingyu Chen unsigned int func_num, unsigned int group_num)
810fabe43fSXingyu Chen {
820fabe43fSXingyu Chen int i;
830fabe43fSXingyu Chen int ret;
840fabe43fSXingyu Chen struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
850fabe43fSXingyu Chen struct meson_pmx_func *func = &pc->data->funcs[func_num];
860fabe43fSXingyu Chen struct meson_pmx_group *group = &pc->data->groups[group_num];
870fabe43fSXingyu Chen struct meson_pmx_axg_data *pmx_data =
880fabe43fSXingyu Chen (struct meson_pmx_axg_data *)group->data;
890fabe43fSXingyu Chen
900fabe43fSXingyu Chen dev_dbg(pc->dev, "enable function %s, group %s\n", func->name,
910fabe43fSXingyu Chen group->name);
920fabe43fSXingyu Chen
930fabe43fSXingyu Chen for (i = 0; i < group->num_pins; i++) {
940fabe43fSXingyu Chen ret = meson_axg_pmx_update_function(pc, group->pins[i],
950fabe43fSXingyu Chen pmx_data->func);
960fabe43fSXingyu Chen if (ret)
970fabe43fSXingyu Chen return ret;
980fabe43fSXingyu Chen }
990fabe43fSXingyu Chen
1000fabe43fSXingyu Chen return 0;
1010fabe43fSXingyu Chen }
1020fabe43fSXingyu Chen
meson_axg_pmx_request_gpio(struct pinctrl_dev * pcdev,struct pinctrl_gpio_range * range,unsigned int offset)1030fabe43fSXingyu Chen static int meson_axg_pmx_request_gpio(struct pinctrl_dev *pcdev,
1040fabe43fSXingyu Chen struct pinctrl_gpio_range *range, unsigned int offset)
1050fabe43fSXingyu Chen {
1060fabe43fSXingyu Chen struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
1070fabe43fSXingyu Chen
1080fabe43fSXingyu Chen return meson_axg_pmx_update_function(pc, offset, 0);
1090fabe43fSXingyu Chen }
1100fabe43fSXingyu Chen
1110fabe43fSXingyu Chen const struct pinmux_ops meson_axg_pmx_ops = {
1120fabe43fSXingyu Chen .set_mux = meson_axg_pmx_set_mux,
1130fabe43fSXingyu Chen .get_functions_count = meson_pmx_get_funcs_count,
1140fabe43fSXingyu Chen .get_function_name = meson_pmx_get_func_name,
1150fabe43fSXingyu Chen .get_function_groups = meson_pmx_get_groups,
1160fabe43fSXingyu Chen .gpio_request_enable = meson_axg_pmx_request_gpio,
1170fabe43fSXingyu Chen };
1189c65441eSKevin Hilman EXPORT_SYMBOL_GPL(meson_axg_pmx_ops);
1199c65441eSKevin Hilman
1209c65441eSKevin Hilman MODULE_LICENSE("Dual BSD/GPL");
121