| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * PEF2256 also known as FALC56 driver | |
| * | |
| * Copyright 2023 CS GROUP France | |
| * | |
| * Author: Herve Codina <herve.codina@bootlin.com> | |
| */ | |
| #include <linux/bitfield.h> | |
| #include <linux/framer/pef2256.h> | |
| #include <linux/module.h> | |
| #include <linux/of.h> | |
| #include <linux/pinctrl/pinctrl.h> | |
| #include <linux/pinctrl/pinconf-generic.h> | |
| #include <linux/pinctrl/pinmux.h> | |
| #include <linux/platform_device.h> | |
| #include <linux/regmap.h> | |
| #include <linux/slab.h> | |
| /* Port Configuration 1..4 */ | |
| #define PEF2256_PC1 0x80 | |
| #define PEF2256_PC2 0x81 | |
| #define PEF2256_PC3 0x82 | |
| #define PEF2256_PC4 0x83 | |
| #define PEF2256_12_PC_RPC_MASK GENMASK(6, 4) | |
| #define PEF2256_12_PC_RPC_SYPR FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x0) | |
| #define PEF2256_12_PC_RPC_RFM FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x1) | |
| #define PEF2256_12_PC_RPC_RFMB FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x2) | |
| #define PEF2256_12_PC_RPC_RSIGM FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x3) | |
| #define PEF2256_12_PC_RPC_RSIG FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x4) | |
| #define PEF2256_12_PC_RPC_DLR FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x5) | |
| #define PEF2256_12_PC_RPC_FREEZE FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x6) | |
| #define PEF2256_12_PC_RPC_RFSP FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x7) | |
| #define PEF2256_12_PC_XPC_MASK GENMASK(4, 0) | |
| #define PEF2256_12_PC_XPC_SYPX FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x0) | |
| #define PEF2256_12_PC_XPC_XFMS FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x1) | |
| #define PEF2256_12_PC_XPC_XSIG FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x2) | |
| #define PEF2256_12_PC_XPC_TCLK FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x3) | |
| #define PEF2256_12_PC_XPC_XMFB FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x4) | |
| #define PEF2256_12_PC_XPC_XSIGM FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x5) | |
| #define PEF2256_12_PC_XPC_DLX FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x6) | |
| #define PEF2256_12_PC_XPC_XCLK FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x7) | |
| #define PEF2256_12_PC_XPC_XLT FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x8) | |
| #define PEF2256_2X_PC_RPC_MASK GENMASK(7, 4) | |
| #define PEF2256_2X_PC_RPC_SYPR FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x0) | |
| #define PEF2256_2X_PC_RPC_RFM FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x1) | |
| #define PEF2256_2X_PC_RPC_RFMB FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x2) | |
| #define PEF2256_2X_PC_RPC_RSIGM FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x3) | |
| #define PEF2256_2X_PC_RPC_RSIG FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x4) | |
| #define PEF2256_2X_PC_RPC_DLR FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x5) | |
| #define PEF2256_2X_PC_RPC_FREEZE FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x6) | |
| #define PEF2256_2X_PC_RPC_RFSP FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x7) | |
| #define PEF2256_2X_PC_RPC_GPI FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x9) | |
| #define PEF2256_2X_PC_RPC_GPOH FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xa) | |
| #define PEF2256_2X_PC_RPC_GPOL FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xb) | |
| #define PEF2256_2X_PC_RPC_LOS FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xc) | |
| #define PEF2256_2X_PC_XPC_MASK GENMASK(3, 0) | |
| #define PEF2256_2X_PC_XPC_SYPX FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x0) | |
| #define PEF2256_2X_PC_XPC_XFMS FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x1) | |
| #define PEF2256_2X_PC_XPC_XSIG FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x2) | |
| #define PEF2256_2X_PC_XPC_TCLK FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x3) | |
| #define PEF2256_2X_PC_XPC_XMFB FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x4) | |
| #define PEF2256_2X_PC_XPC_XSIGM FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x5) | |
| #define PEF2256_2X_PC_XPC_DLX FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x6) | |
| #define PEF2256_2X_PC_XPC_XCLK FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x7) | |
| #define PEF2256_2X_PC_XPC_XLT FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x8) | |
| #define PEF2256_2X_PC_XPC_GPI FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x9) | |
| #define PEF2256_2X_PC_XPC_GPOH FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0xa) | |
| #define PEF2256_2X_PC_XPC_GPOL FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0xb) | |
| struct pef2256_pinreg_desc { | |
| int offset; | |
| u8 mask; | |
| }; | |
| struct pef2256_function_desc { | |
| const char *name; | |
| const char * const*groups; | |
| unsigned int ngroups; | |
| u8 func_val; | |
| }; | |
| struct pef2256_pinctrl { | |
| struct device *dev; | |
| struct regmap *regmap; | |
| enum pef2256_version version; | |
| struct pinctrl_desc pctrl_desc; | |
| const struct pef2256_function_desc *functions; | |
| unsigned int nfunctions; | |
| }; | |
| static int pef2256_get_groups_count(struct pinctrl_dev *pctldev) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| /* We map 1 group <-> 1 pin */ | |
| return pef2256->pctrl_desc.npins; | |
| } | |
| static const char *pef2256_get_group_name(struct pinctrl_dev *pctldev, | |
| unsigned int selector) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| /* We map 1 group <-> 1 pin */ | |
| return pef2256->pctrl_desc.pins[selector].name; | |
| } | |
| static int pef2256_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, | |
| const unsigned int **pins, | |
| unsigned int *num_pins) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| /* We map 1 group <-> 1 pin */ | |
| *pins = &pef2256->pctrl_desc.pins[selector].number; | |
| *num_pins = 1; | |
| return 0; | |
| } | |
| static const struct pinctrl_ops pef2256_pctlops = { | |
| .get_groups_count = pef2256_get_groups_count, | |
| .get_group_name = pef2256_get_group_name, | |
| .get_group_pins = pef2256_get_group_pins, | |
| .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | |
| .dt_free_map = pinconf_generic_dt_free_map, | |
| }; | |
| static int pef2256_get_functions_count(struct pinctrl_dev *pctldev) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| return pef2256->nfunctions; | |
| } | |
| static const char *pef2256_get_function_name(struct pinctrl_dev *pctldev, | |
| unsigned int selector) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| return pef2256->functions[selector].name; | |
| } | |
| static int pef2256_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, | |
| const char * const **groups, | |
| unsigned * const num_groups) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| *groups = pef2256->functions[selector].groups; | |
| *num_groups = pef2256->functions[selector].ngroups; | |
| return 0; | |
| } | |
| static int pef2256_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, | |
| unsigned int group_selector) | |
| { | |
| struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); | |
| const struct pef2256_pinreg_desc *pinreg_desc; | |
| u8 func_val; | |
| /* We map 1 group <-> 1 pin */ | |
| pinreg_desc = pef2256->pctrl_desc.pins[group_selector].drv_data; | |
| func_val = pef2256->functions[func_selector].func_val; | |
| return regmap_update_bits(pef2256->regmap, pinreg_desc->offset, | |
| pinreg_desc->mask, func_val); | |
| } | |
| static const struct pinmux_ops pef2256_pmxops = { | |
| .get_functions_count = pef2256_get_functions_count, | |
| .get_function_name = pef2256_get_function_name, | |
| .get_function_groups = pef2256_get_function_groups, | |
| .set_mux = pef2256_set_mux, | |
| }; | |
| #define PEF2256_PINCTRL_PIN(_number, _name, _offset, _mask) { \ | |
| .number = _number, \ | |
| .name = _name, \ | |
| .drv_data = &(struct pef2256_pinreg_desc) { \ | |
| .offset = _offset, \ | |
| .mask = _mask, \ | |
| }, \ | |
| } | |
| static const struct pinctrl_pin_desc pef2256_v12_pins[] = { | |
| PEF2256_PINCTRL_PIN(0, "RPA", PEF2256_PC1, PEF2256_12_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(1, "RPB", PEF2256_PC2, PEF2256_12_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(2, "RPC", PEF2256_PC3, PEF2256_12_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(3, "RPD", PEF2256_PC4, PEF2256_12_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(4, "XPA", PEF2256_PC1, PEF2256_12_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(5, "XPB", PEF2256_PC2, PEF2256_12_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(6, "XPC", PEF2256_PC3, PEF2256_12_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(7, "XPD", PEF2256_PC4, PEF2256_12_PC_XPC_MASK), | |
| }; | |
| static const struct pinctrl_pin_desc pef2256_v2x_pins[] = { | |
| PEF2256_PINCTRL_PIN(0, "RPA", PEF2256_PC1, PEF2256_2X_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(1, "RPB", PEF2256_PC2, PEF2256_2X_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(2, "RPC", PEF2256_PC3, PEF2256_2X_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(3, "RPD", PEF2256_PC4, PEF2256_2X_PC_RPC_MASK), | |
| PEF2256_PINCTRL_PIN(4, "XPA", PEF2256_PC1, PEF2256_2X_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(5, "XPB", PEF2256_PC2, PEF2256_2X_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(6, "XPC", PEF2256_PC3, PEF2256_2X_PC_XPC_MASK), | |
| PEF2256_PINCTRL_PIN(7, "XPD", PEF2256_PC4, PEF2256_2X_PC_XPC_MASK), | |
| }; | |
| static const char *const pef2256_rp_groups[] = { "RPA", "RPB", "RPC", "RPD" }; | |
| static const char *const pef2256_xp_groups[] = { "XPA", "XPB", "XPC", "XPD" }; | |
| static const char *const pef2256_all_groups[] = { "RPA", "RPB", "RPC", "RPD", | |
| "XPA", "XPB", "XPC", "XPD" }; | |
| #define PEF2256_FUNCTION(_name, _func_val, _groups) { \ | |
| .name = _name, \ | |
| .groups = _groups, \ | |
| .ngroups = ARRAY_SIZE(_groups), \ | |
| .func_val = _func_val, \ | |
| } | |
| static const struct pef2256_function_desc pef2256_v2x_functions[] = { | |
| PEF2256_FUNCTION("SYPR", PEF2256_2X_PC_RPC_SYPR, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFM", PEF2256_2X_PC_RPC_RFM, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFMB", PEF2256_2X_PC_RPC_RFMB, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RSIGM", PEF2256_2X_PC_RPC_RSIGM, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RSIG", PEF2256_2X_PC_RPC_RSIG, pef2256_rp_groups), | |
| PEF2256_FUNCTION("DLR", PEF2256_2X_PC_RPC_DLR, pef2256_rp_groups), | |
| PEF2256_FUNCTION("FREEZE", PEF2256_2X_PC_RPC_FREEZE, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFSP", PEF2256_2X_PC_RPC_RFSP, pef2256_rp_groups), | |
| PEF2256_FUNCTION("LOS", PEF2256_2X_PC_RPC_LOS, pef2256_rp_groups), | |
| PEF2256_FUNCTION("SYPX", PEF2256_2X_PC_XPC_SYPX, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XFMS", PEF2256_2X_PC_XPC_XFMS, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XSIG", PEF2256_2X_PC_XPC_XSIG, pef2256_xp_groups), | |
| PEF2256_FUNCTION("TCLK", PEF2256_2X_PC_XPC_TCLK, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XMFB", PEF2256_2X_PC_XPC_XMFB, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XSIGM", PEF2256_2X_PC_XPC_XSIGM, pef2256_xp_groups), | |
| PEF2256_FUNCTION("DLX", PEF2256_2X_PC_XPC_DLX, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XCLK", PEF2256_2X_PC_XPC_XCLK, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XLT", PEF2256_2X_PC_XPC_XLT, pef2256_xp_groups), | |
| PEF2256_FUNCTION("GPI", PEF2256_2X_PC_RPC_GPI | PEF2256_2X_PC_XPC_GPI, | |
| pef2256_all_groups), | |
| PEF2256_FUNCTION("GPOH", PEF2256_2X_PC_RPC_GPOH | PEF2256_2X_PC_XPC_GPOH, | |
| pef2256_all_groups), | |
| PEF2256_FUNCTION("GPOL", PEF2256_2X_PC_RPC_GPOL | PEF2256_2X_PC_XPC_GPOL, | |
| pef2256_all_groups), | |
| }; | |
| static const struct pef2256_function_desc pef2256_v12_functions[] = { | |
| PEF2256_FUNCTION("SYPR", PEF2256_12_PC_RPC_SYPR, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFM", PEF2256_12_PC_RPC_RFM, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFMB", PEF2256_12_PC_RPC_RFMB, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RSIGM", PEF2256_12_PC_RPC_RSIGM, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RSIG", PEF2256_12_PC_RPC_RSIG, pef2256_rp_groups), | |
| PEF2256_FUNCTION("DLR", PEF2256_12_PC_RPC_DLR, pef2256_rp_groups), | |
| PEF2256_FUNCTION("FREEZE", PEF2256_12_PC_RPC_FREEZE, pef2256_rp_groups), | |
| PEF2256_FUNCTION("RFSP", PEF2256_12_PC_RPC_RFSP, pef2256_rp_groups), | |
| PEF2256_FUNCTION("SYPX", PEF2256_12_PC_XPC_SYPX, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XFMS", PEF2256_12_PC_XPC_XFMS, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XSIG", PEF2256_12_PC_XPC_XSIG, pef2256_xp_groups), | |
| PEF2256_FUNCTION("TCLK", PEF2256_12_PC_XPC_TCLK, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XMFB", PEF2256_12_PC_XPC_XMFB, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XSIGM", PEF2256_12_PC_XPC_XSIGM, pef2256_xp_groups), | |
| PEF2256_FUNCTION("DLX", PEF2256_12_PC_XPC_DLX, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XCLK", PEF2256_12_PC_XPC_XCLK, pef2256_xp_groups), | |
| PEF2256_FUNCTION("XLT", PEF2256_12_PC_XPC_XLT, pef2256_xp_groups), | |
| }; | |
| static int pef2256_register_pinctrl(struct pef2256_pinctrl *pef2256) | |
| { | |
| struct pinctrl_dev *pctrl; | |
| pef2256->pctrl_desc.name = dev_name(pef2256->dev); | |
| pef2256->pctrl_desc.owner = THIS_MODULE; | |
| pef2256->pctrl_desc.pctlops = &pef2256_pctlops; | |
| pef2256->pctrl_desc.pmxops = &pef2256_pmxops; | |
| if (pef2256->version == PEF2256_VERSION_1_2) { | |
| pef2256->pctrl_desc.pins = pef2256_v12_pins; | |
| pef2256->pctrl_desc.npins = ARRAY_SIZE(pef2256_v12_pins); | |
| pef2256->functions = pef2256_v12_functions; | |
| pef2256->nfunctions = ARRAY_SIZE(pef2256_v12_functions); | |
| } else { | |
| pef2256->pctrl_desc.pins = pef2256_v2x_pins; | |
| pef2256->pctrl_desc.npins = ARRAY_SIZE(pef2256_v2x_pins); | |
| pef2256->functions = pef2256_v2x_functions; | |
| pef2256->nfunctions = ARRAY_SIZE(pef2256_v2x_functions); | |
| } | |
| pctrl = devm_pinctrl_register(pef2256->dev, &pef2256->pctrl_desc, pef2256); | |
| if (IS_ERR(pctrl)) | |
| return dev_err_probe(pef2256->dev, PTR_ERR(pctrl), | |
| "pinctrl driver registration failed\n"); | |
| return 0; | |
| } | |
| static void pef2256_reset_pinmux(struct pef2256_pinctrl *pef2256) | |
| { | |
| u8 val; | |
| /* | |
| * Reset values cannot be used. | |
| * They define the SYPR/SYPX pin mux for all the RPx and XPx pins and | |
| * Only one pin can be muxed to SYPR and one pin can be muxed to SYPX. | |
| * Choose here an other reset value. | |
| */ | |
| if (pef2256->version == PEF2256_VERSION_1_2) | |
| val = PEF2256_12_PC_XPC_XCLK | PEF2256_12_PC_RPC_RFSP; | |
| else | |
| val = PEF2256_2X_PC_XPC_GPI | PEF2256_2X_PC_RPC_GPI; | |
| regmap_write(pef2256->regmap, PEF2256_PC1, val); | |
| regmap_write(pef2256->regmap, PEF2256_PC2, val); | |
| regmap_write(pef2256->regmap, PEF2256_PC3, val); | |
| regmap_write(pef2256->regmap, PEF2256_PC4, val); | |
| } | |
| static int pef2256_pinctrl_probe(struct platform_device *pdev) | |
| { | |
| struct pef2256_pinctrl *pef2256_pinctrl; | |
| struct pef2256 *pef2256; | |
| int ret; | |
| pef2256_pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pef2256_pinctrl), GFP_KERNEL); | |
| if (!pef2256_pinctrl) | |
| return -ENOMEM; | |
| device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); | |
| pef2256 = dev_get_drvdata(pdev->dev.parent); | |
| pef2256_pinctrl->dev = &pdev->dev; | |
| pef2256_pinctrl->regmap = pef2256_get_regmap(pef2256); | |
| pef2256_pinctrl->version = pef2256_get_version(pef2256); | |
| platform_set_drvdata(pdev, pef2256_pinctrl); | |
| pef2256_reset_pinmux(pef2256_pinctrl); | |
| ret = pef2256_register_pinctrl(pef2256_pinctrl); | |
| if (ret) | |
| return ret; | |
| return 0; | |
| } | |
| static struct platform_driver pef2256_pinctrl_driver = { | |
| .driver = { | |
| .name = "lantiq-pef2256-pinctrl", | |
| }, | |
| .probe = pef2256_pinctrl_probe, | |
| }; | |
| module_platform_driver(pef2256_pinctrl_driver); | |
| MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); | |
| MODULE_DESCRIPTION("PEF2256 pin controller driver"); | |
| MODULE_LICENSE("GPL"); |