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