brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 00c3829 Raw
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, &reg, &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