cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pinctrl-bcm4908.c (17803B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> */
      3
      4#include <linux/err.h>
      5#include <linux/io.h>
      6#include <linux/mod_devicetable.h>
      7#include <linux/module.h>
      8#include <linux/pinctrl/pinconf-generic.h>
      9#include <linux/pinctrl/pinctrl.h>
     10#include <linux/pinctrl/pinmux.h>
     11#include <linux/platform_device.h>
     12#include <linux/slab.h>
     13#include <linux/string_helpers.h>
     14
     15#include "../core.h"
     16#include "../pinmux.h"
     17
     18#define BCM4908_NUM_PINS			86
     19
     20#define BCM4908_TEST_PORT_BLOCK_EN_LSB			0x00
     21#define BCM4908_TEST_PORT_BLOCK_DATA_MSB		0x04
     22#define BCM4908_TEST_PORT_BLOCK_DATA_LSB		0x08
     23#define  BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT	12
     24#define BCM4908_TEST_PORT_COMMAND			0x0c
     25#define  BCM4908_TEST_PORT_CMD_LOAD_MUX_REG		0x00000021
     26
     27struct bcm4908_pinctrl {
     28	struct device *dev;
     29	void __iomem *base;
     30	struct mutex mutex;
     31	struct pinctrl_dev *pctldev;
     32	struct pinctrl_desc pctldesc;
     33};
     34
     35/*
     36 * Groups
     37 */
     38
     39struct bcm4908_pinctrl_pin_setup {
     40	unsigned int number;
     41	unsigned int function;
     42};
     43
     44static const struct bcm4908_pinctrl_pin_setup led_0_pins_a[] = {
     45	{ 0, 3 },
     46};
     47
     48static const struct bcm4908_pinctrl_pin_setup led_1_pins_a[] = {
     49	{ 1, 3 },
     50};
     51
     52static const struct bcm4908_pinctrl_pin_setup led_2_pins_a[] = {
     53	{ 2, 3 },
     54};
     55
     56static const struct bcm4908_pinctrl_pin_setup led_3_pins_a[] = {
     57	{ 3, 3 },
     58};
     59
     60static const struct bcm4908_pinctrl_pin_setup led_4_pins_a[] = {
     61	{ 4, 3 },
     62};
     63
     64static const struct bcm4908_pinctrl_pin_setup led_5_pins_a[] = {
     65	{ 5, 3 },
     66};
     67
     68static const struct bcm4908_pinctrl_pin_setup led_6_pins_a[] = {
     69	{ 6, 3 },
     70};
     71
     72static const struct bcm4908_pinctrl_pin_setup led_7_pins_a[] = {
     73	{ 7, 3 },
     74};
     75
     76static const struct bcm4908_pinctrl_pin_setup led_8_pins_a[] = {
     77	{ 8, 3 },
     78};
     79
     80static const struct bcm4908_pinctrl_pin_setup led_9_pins_a[] = {
     81	{ 9, 3 },
     82};
     83
     84static const struct bcm4908_pinctrl_pin_setup led_10_pins_a[] = {
     85	{ 10, 3 },
     86};
     87
     88static const struct bcm4908_pinctrl_pin_setup led_11_pins_a[] = {
     89	{ 11, 3 },
     90};
     91
     92static const struct bcm4908_pinctrl_pin_setup led_12_pins_a[] = {
     93	{ 12, 3 },
     94};
     95
     96static const struct bcm4908_pinctrl_pin_setup led_13_pins_a[] = {
     97	{ 13, 3 },
     98};
     99
    100static const struct bcm4908_pinctrl_pin_setup led_14_pins_a[] = {
    101	{ 14, 3 },
    102};
    103
    104static const struct bcm4908_pinctrl_pin_setup led_15_pins_a[] = {
    105	{ 15, 3 },
    106};
    107
    108static const struct bcm4908_pinctrl_pin_setup led_16_pins_a[] = {
    109	{ 16, 3 },
    110};
    111
    112static const struct bcm4908_pinctrl_pin_setup led_17_pins_a[] = {
    113	{ 17, 3 },
    114};
    115
    116static const struct bcm4908_pinctrl_pin_setup led_18_pins_a[] = {
    117	{ 18, 3 },
    118};
    119
    120static const struct bcm4908_pinctrl_pin_setup led_19_pins_a[] = {
    121	{ 19, 3 },
    122};
    123
    124static const struct bcm4908_pinctrl_pin_setup led_20_pins_a[] = {
    125	{ 20, 3 },
    126};
    127
    128static const struct bcm4908_pinctrl_pin_setup led_21_pins_a[] = {
    129	{ 21, 3 },
    130};
    131
    132static const struct bcm4908_pinctrl_pin_setup led_22_pins_a[] = {
    133	{ 22, 3 },
    134};
    135
    136static const struct bcm4908_pinctrl_pin_setup led_23_pins_a[] = {
    137	{ 23, 3 },
    138};
    139
    140static const struct bcm4908_pinctrl_pin_setup led_24_pins_a[] = {
    141	{ 24, 3 },
    142};
    143
    144static const struct bcm4908_pinctrl_pin_setup led_25_pins_a[] = {
    145	{ 25, 3 },
    146};
    147
    148static const struct bcm4908_pinctrl_pin_setup led_26_pins_a[] = {
    149	{ 26, 3 },
    150};
    151
    152static const struct bcm4908_pinctrl_pin_setup led_27_pins_a[] = {
    153	{ 27, 3 },
    154};
    155
    156static const struct bcm4908_pinctrl_pin_setup led_28_pins_a[] = {
    157	{ 28, 3 },
    158};
    159
    160static const struct bcm4908_pinctrl_pin_setup led_29_pins_a[] = {
    161	{ 29, 3 },
    162};
    163
    164static const struct bcm4908_pinctrl_pin_setup led_30_pins_a[] = {
    165	{ 30, 3 },
    166};
    167
    168static const struct bcm4908_pinctrl_pin_setup led_31_pins_a[] = {
    169	{ 31, 3 },
    170};
    171
    172static const struct bcm4908_pinctrl_pin_setup led_10_pins_b[] = {
    173	{ 8, 2 },
    174};
    175
    176static const struct bcm4908_pinctrl_pin_setup led_11_pins_b[] = {
    177	{ 9, 2 },
    178};
    179
    180static const struct bcm4908_pinctrl_pin_setup led_12_pins_b[] = {
    181	{ 0, 2 },
    182};
    183
    184static const struct bcm4908_pinctrl_pin_setup led_13_pins_b[] = {
    185	{ 1, 2 },
    186};
    187
    188static const struct bcm4908_pinctrl_pin_setup led_31_pins_b[] = {
    189	{ 30, 2 },
    190};
    191
    192static const struct bcm4908_pinctrl_pin_setup hs_uart_pins[] = {
    193	{ 10, 0 },	/* CTS */
    194	{ 11, 0 },	/* RTS */
    195	{ 12, 0 },	/* RXD */
    196	{ 13, 0 },	/* TXD */
    197};
    198
    199static const struct bcm4908_pinctrl_pin_setup i2c_pins_a[] = {
    200	{ 18, 0 },	/* SDA */
    201	{ 19, 0 },	/* SCL */
    202};
    203
    204static const struct bcm4908_pinctrl_pin_setup i2c_pins_b[] = {
    205	{ 22, 0 },	/* SDA */
    206	{ 23, 0 },	/* SCL */
    207};
    208
    209static const struct bcm4908_pinctrl_pin_setup i2s_pins[] = {
    210	{ 27, 0 },	/* MCLK */
    211	{ 28, 0 },	/* LRCK */
    212	{ 29, 0 },	/* SDATA */
    213	{ 30, 0 },	/* SCLK */
    214};
    215
    216static const struct bcm4908_pinctrl_pin_setup nand_ctrl_pins[] = {
    217	{ 32, 0 },
    218	{ 33, 0 },
    219	{ 34, 0 },
    220	{ 43, 0 },
    221	{ 44, 0 },
    222	{ 45, 0 },
    223	{ 56, 1 },
    224};
    225
    226static const struct bcm4908_pinctrl_pin_setup nand_data_pins[] = {
    227	{ 35, 0 },
    228	{ 36, 0 },
    229	{ 37, 0 },
    230	{ 38, 0 },
    231	{ 39, 0 },
    232	{ 40, 0 },
    233	{ 41, 0 },
    234	{ 42, 0 },
    235};
    236
    237static const struct bcm4908_pinctrl_pin_setup emmc_ctrl_pins[] = {
    238	{ 46, 0 },
    239	{ 47, 0 },
    240};
    241
    242static const struct bcm4908_pinctrl_pin_setup usb0_pwr_pins[] = {
    243	{ 63, 0 },
    244	{ 64, 0 },
    245};
    246
    247static const struct bcm4908_pinctrl_pin_setup usb1_pwr_pins[] = {
    248	{ 66, 0 },
    249	{ 67, 0 },
    250};
    251
    252struct bcm4908_pinctrl_grp {
    253	const char *name;
    254	const struct bcm4908_pinctrl_pin_setup *pins;
    255	const unsigned int num_pins;
    256};
    257
    258static const struct bcm4908_pinctrl_grp bcm4908_pinctrl_grps[] = {
    259	{ "led_0_grp_a", led_0_pins_a, ARRAY_SIZE(led_0_pins_a) },
    260	{ "led_1_grp_a", led_1_pins_a, ARRAY_SIZE(led_1_pins_a) },
    261	{ "led_2_grp_a", led_2_pins_a, ARRAY_SIZE(led_2_pins_a) },
    262	{ "led_3_grp_a", led_3_pins_a, ARRAY_SIZE(led_3_pins_a) },
    263	{ "led_4_grp_a", led_4_pins_a, ARRAY_SIZE(led_4_pins_a) },
    264	{ "led_5_grp_a", led_5_pins_a, ARRAY_SIZE(led_5_pins_a) },
    265	{ "led_6_grp_a", led_6_pins_a, ARRAY_SIZE(led_6_pins_a) },
    266	{ "led_7_grp_a", led_7_pins_a, ARRAY_SIZE(led_7_pins_a) },
    267	{ "led_8_grp_a", led_8_pins_a, ARRAY_SIZE(led_8_pins_a) },
    268	{ "led_9_grp_a", led_9_pins_a, ARRAY_SIZE(led_9_pins_a) },
    269	{ "led_10_grp_a", led_10_pins_a, ARRAY_SIZE(led_10_pins_a) },
    270	{ "led_11_grp_a", led_11_pins_a, ARRAY_SIZE(led_11_pins_a) },
    271	{ "led_12_grp_a", led_12_pins_a, ARRAY_SIZE(led_12_pins_a) },
    272	{ "led_13_grp_a", led_13_pins_a, ARRAY_SIZE(led_13_pins_a) },
    273	{ "led_14_grp_a", led_14_pins_a, ARRAY_SIZE(led_14_pins_a) },
    274	{ "led_15_grp_a", led_15_pins_a, ARRAY_SIZE(led_15_pins_a) },
    275	{ "led_16_grp_a", led_16_pins_a, ARRAY_SIZE(led_16_pins_a) },
    276	{ "led_17_grp_a", led_17_pins_a, ARRAY_SIZE(led_17_pins_a) },
    277	{ "led_18_grp_a", led_18_pins_a, ARRAY_SIZE(led_18_pins_a) },
    278	{ "led_19_grp_a", led_19_pins_a, ARRAY_SIZE(led_19_pins_a) },
    279	{ "led_20_grp_a", led_20_pins_a, ARRAY_SIZE(led_20_pins_a) },
    280	{ "led_21_grp_a", led_21_pins_a, ARRAY_SIZE(led_21_pins_a) },
    281	{ "led_22_grp_a", led_22_pins_a, ARRAY_SIZE(led_22_pins_a) },
    282	{ "led_23_grp_a", led_23_pins_a, ARRAY_SIZE(led_23_pins_a) },
    283	{ "led_24_grp_a", led_24_pins_a, ARRAY_SIZE(led_24_pins_a) },
    284	{ "led_25_grp_a", led_25_pins_a, ARRAY_SIZE(led_25_pins_a) },
    285	{ "led_26_grp_a", led_26_pins_a, ARRAY_SIZE(led_26_pins_a) },
    286	{ "led_27_grp_a", led_27_pins_a, ARRAY_SIZE(led_27_pins_a) },
    287	{ "led_28_grp_a", led_28_pins_a, ARRAY_SIZE(led_28_pins_a) },
    288	{ "led_29_grp_a", led_29_pins_a, ARRAY_SIZE(led_29_pins_a) },
    289	{ "led_30_grp_a", led_30_pins_a, ARRAY_SIZE(led_30_pins_a) },
    290	{ "led_31_grp_a", led_31_pins_a, ARRAY_SIZE(led_31_pins_a) },
    291	{ "led_10_grp_b", led_10_pins_b, ARRAY_SIZE(led_10_pins_b) },
    292	{ "led_11_grp_b", led_11_pins_b, ARRAY_SIZE(led_11_pins_b) },
    293	{ "led_12_grp_b", led_12_pins_b, ARRAY_SIZE(led_12_pins_b) },
    294	{ "led_13_grp_b", led_13_pins_b, ARRAY_SIZE(led_13_pins_b) },
    295	{ "led_31_grp_b", led_31_pins_b, ARRAY_SIZE(led_31_pins_b) },
    296	{ "hs_uart_grp", hs_uart_pins, ARRAY_SIZE(hs_uart_pins) },
    297	{ "i2c_grp_a", i2c_pins_a, ARRAY_SIZE(i2c_pins_a) },
    298	{ "i2c_grp_b", i2c_pins_b, ARRAY_SIZE(i2c_pins_b) },
    299	{ "i2s_grp", i2s_pins, ARRAY_SIZE(i2s_pins) },
    300	{ "nand_ctrl_grp", nand_ctrl_pins, ARRAY_SIZE(nand_ctrl_pins) },
    301	{ "nand_data_grp", nand_data_pins, ARRAY_SIZE(nand_data_pins) },
    302	{ "emmc_ctrl_grp", emmc_ctrl_pins, ARRAY_SIZE(emmc_ctrl_pins) },
    303	{ "usb0_pwr_grp", usb0_pwr_pins, ARRAY_SIZE(usb0_pwr_pins) },
    304	{ "usb1_pwr_grp", usb1_pwr_pins, ARRAY_SIZE(usb1_pwr_pins) },
    305};
    306
    307/*
    308 * Functions
    309 */
    310
    311struct bcm4908_pinctrl_function {
    312	const char *name;
    313	const char * const *groups;
    314	const unsigned int num_groups;
    315};
    316
    317static const char * const led_0_groups[] = { "led_0_grp_a" };
    318static const char * const led_1_groups[] = { "led_1_grp_a" };
    319static const char * const led_2_groups[] = { "led_2_grp_a" };
    320static const char * const led_3_groups[] = { "led_3_grp_a" };
    321static const char * const led_4_groups[] = { "led_4_grp_a" };
    322static const char * const led_5_groups[] = { "led_5_grp_a" };
    323static const char * const led_6_groups[] = { "led_6_grp_a" };
    324static const char * const led_7_groups[] = { "led_7_grp_a" };
    325static const char * const led_8_groups[] = { "led_8_grp_a" };
    326static const char * const led_9_groups[] = { "led_9_grp_a" };
    327static const char * const led_10_groups[] = { "led_10_grp_a", "led_10_grp_b" };
    328static const char * const led_11_groups[] = { "led_11_grp_a", "led_11_grp_b" };
    329static const char * const led_12_groups[] = { "led_12_grp_a", "led_12_grp_b" };
    330static const char * const led_13_groups[] = { "led_13_grp_a", "led_13_grp_b" };
    331static const char * const led_14_groups[] = { "led_14_grp_a" };
    332static const char * const led_15_groups[] = { "led_15_grp_a" };
    333static const char * const led_16_groups[] = { "led_16_grp_a" };
    334static const char * const led_17_groups[] = { "led_17_grp_a" };
    335static const char * const led_18_groups[] = { "led_18_grp_a" };
    336static const char * const led_19_groups[] = { "led_19_grp_a" };
    337static const char * const led_20_groups[] = { "led_20_grp_a" };
    338static const char * const led_21_groups[] = { "led_21_grp_a" };
    339static const char * const led_22_groups[] = { "led_22_grp_a" };
    340static const char * const led_23_groups[] = { "led_23_grp_a" };
    341static const char * const led_24_groups[] = { "led_24_grp_a" };
    342static const char * const led_25_groups[] = { "led_25_grp_a" };
    343static const char * const led_26_groups[] = { "led_26_grp_a" };
    344static const char * const led_27_groups[] = { "led_27_grp_a" };
    345static const char * const led_28_groups[] = { "led_28_grp_a" };
    346static const char * const led_29_groups[] = { "led_29_grp_a" };
    347static const char * const led_30_groups[] = { "led_30_grp_a" };
    348static const char * const led_31_groups[] = { "led_31_grp_a", "led_31_grp_b" };
    349static const char * const hs_uart_groups[] = { "hs_uart_grp" };
    350static const char * const i2c_groups[] = { "i2c_grp_a", "i2c_grp_b" };
    351static const char * const i2s_groups[] = { "i2s_grp" };
    352static const char * const nand_ctrl_groups[] = { "nand_ctrl_grp" };
    353static const char * const nand_data_groups[] = { "nand_data_grp" };
    354static const char * const emmc_ctrl_groups[] = { "emmc_ctrl_grp" };
    355static const char * const usb0_pwr_groups[] = { "usb0_pwr_grp" };
    356static const char * const usb1_pwr_groups[] = { "usb1_pwr_grp" };
    357
    358static const struct bcm4908_pinctrl_function bcm4908_pinctrl_functions[] = {
    359	{ "led_0", led_0_groups, ARRAY_SIZE(led_0_groups) },
    360	{ "led_1", led_1_groups, ARRAY_SIZE(led_1_groups) },
    361	{ "led_2", led_2_groups, ARRAY_SIZE(led_2_groups) },
    362	{ "led_3", led_3_groups, ARRAY_SIZE(led_3_groups) },
    363	{ "led_4", led_4_groups, ARRAY_SIZE(led_4_groups) },
    364	{ "led_5", led_5_groups, ARRAY_SIZE(led_5_groups) },
    365	{ "led_6", led_6_groups, ARRAY_SIZE(led_6_groups) },
    366	{ "led_7", led_7_groups, ARRAY_SIZE(led_7_groups) },
    367	{ "led_8", led_8_groups, ARRAY_SIZE(led_8_groups) },
    368	{ "led_9", led_9_groups, ARRAY_SIZE(led_9_groups) },
    369	{ "led_10", led_10_groups, ARRAY_SIZE(led_10_groups) },
    370	{ "led_11", led_11_groups, ARRAY_SIZE(led_11_groups) },
    371	{ "led_12", led_12_groups, ARRAY_SIZE(led_12_groups) },
    372	{ "led_13", led_13_groups, ARRAY_SIZE(led_13_groups) },
    373	{ "led_14", led_14_groups, ARRAY_SIZE(led_14_groups) },
    374	{ "led_15", led_15_groups, ARRAY_SIZE(led_15_groups) },
    375	{ "led_16", led_16_groups, ARRAY_SIZE(led_16_groups) },
    376	{ "led_17", led_17_groups, ARRAY_SIZE(led_17_groups) },
    377	{ "led_18", led_18_groups, ARRAY_SIZE(led_18_groups) },
    378	{ "led_19", led_19_groups, ARRAY_SIZE(led_19_groups) },
    379	{ "led_20", led_20_groups, ARRAY_SIZE(led_20_groups) },
    380	{ "led_21", led_21_groups, ARRAY_SIZE(led_21_groups) },
    381	{ "led_22", led_22_groups, ARRAY_SIZE(led_22_groups) },
    382	{ "led_23", led_23_groups, ARRAY_SIZE(led_23_groups) },
    383	{ "led_24", led_24_groups, ARRAY_SIZE(led_24_groups) },
    384	{ "led_25", led_25_groups, ARRAY_SIZE(led_25_groups) },
    385	{ "led_26", led_26_groups, ARRAY_SIZE(led_26_groups) },
    386	{ "led_27", led_27_groups, ARRAY_SIZE(led_27_groups) },
    387	{ "led_28", led_28_groups, ARRAY_SIZE(led_28_groups) },
    388	{ "led_29", led_29_groups, ARRAY_SIZE(led_29_groups) },
    389	{ "led_30", led_30_groups, ARRAY_SIZE(led_30_groups) },
    390	{ "led_31", led_31_groups, ARRAY_SIZE(led_31_groups) },
    391	{ "hs_uart", hs_uart_groups, ARRAY_SIZE(hs_uart_groups) },
    392	{ "i2c", i2c_groups, ARRAY_SIZE(i2c_groups) },
    393	{ "i2s", i2s_groups, ARRAY_SIZE(i2s_groups) },
    394	{ "nand_ctrl", nand_ctrl_groups, ARRAY_SIZE(nand_ctrl_groups) },
    395	{ "nand_data", nand_data_groups, ARRAY_SIZE(nand_data_groups) },
    396	{ "emmc_ctrl", emmc_ctrl_groups, ARRAY_SIZE(emmc_ctrl_groups) },
    397	{ "usb0_pwr", usb0_pwr_groups, ARRAY_SIZE(usb0_pwr_groups) },
    398	{ "usb1_pwr", usb1_pwr_groups, ARRAY_SIZE(usb1_pwr_groups) },
    399};
    400
    401/*
    402 * Groups code
    403 */
    404
    405static const struct pinctrl_ops bcm4908_pinctrl_ops = {
    406	.get_groups_count = pinctrl_generic_get_group_count,
    407	.get_group_name = pinctrl_generic_get_group_name,
    408	.get_group_pins = pinctrl_generic_get_group_pins,
    409	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
    410	.dt_free_map = pinconf_generic_dt_free_map,
    411};
    412
    413/*
    414 * Functions code
    415 */
    416
    417static int bcm4908_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
    418			      unsigned int func_selector,
    419			      unsigned int group_selector)
    420{
    421	struct bcm4908_pinctrl *bcm4908_pinctrl = pinctrl_dev_get_drvdata(pctrl_dev);
    422	const struct bcm4908_pinctrl_grp *group;
    423	struct group_desc *group_desc;
    424	int i;
    425
    426	group_desc = pinctrl_generic_get_group(pctrl_dev, group_selector);
    427	if (!group_desc)
    428		return -EINVAL;
    429	group = group_desc->data;
    430
    431	mutex_lock(&bcm4908_pinctrl->mutex);
    432	for (i = 0; i < group->num_pins; i++) {
    433		u32 lsb = 0;
    434
    435		lsb |= group->pins[i].number;
    436		lsb |= group->pins[i].function << BCM4908_TEST_PORT_LSB_PINMUX_DATA_SHIFT;
    437
    438		writel(0x0, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_MSB);
    439		writel(lsb, bcm4908_pinctrl->base + BCM4908_TEST_PORT_BLOCK_DATA_LSB);
    440		writel(BCM4908_TEST_PORT_CMD_LOAD_MUX_REG,
    441		       bcm4908_pinctrl->base + BCM4908_TEST_PORT_COMMAND);
    442	}
    443	mutex_unlock(&bcm4908_pinctrl->mutex);
    444
    445	return 0;
    446}
    447
    448static const struct pinmux_ops bcm4908_pinctrl_pmxops = {
    449	.get_functions_count = pinmux_generic_get_function_count,
    450	.get_function_name = pinmux_generic_get_function_name,
    451	.get_function_groups = pinmux_generic_get_function_groups,
    452	.set_mux = bcm4908_pinctrl_set_mux,
    453};
    454
    455/*
    456 * Controller code
    457 */
    458
    459static struct pinctrl_desc bcm4908_pinctrl_desc = {
    460	.name = "bcm4908-pinctrl",
    461	.pctlops = &bcm4908_pinctrl_ops,
    462	.pmxops = &bcm4908_pinctrl_pmxops,
    463};
    464
    465static const struct of_device_id bcm4908_pinctrl_of_match_table[] = {
    466	{ .compatible = "brcm,bcm4908-pinctrl", },
    467	{ }
    468};
    469
    470static int bcm4908_pinctrl_probe(struct platform_device *pdev)
    471{
    472	struct device *dev = &pdev->dev;
    473	struct bcm4908_pinctrl *bcm4908_pinctrl;
    474	struct pinctrl_desc *pctldesc;
    475	struct pinctrl_pin_desc *pins;
    476	char **pin_names;
    477	int i;
    478
    479	bcm4908_pinctrl = devm_kzalloc(dev, sizeof(*bcm4908_pinctrl), GFP_KERNEL);
    480	if (!bcm4908_pinctrl)
    481		return -ENOMEM;
    482	pctldesc = &bcm4908_pinctrl->pctldesc;
    483	platform_set_drvdata(pdev, bcm4908_pinctrl);
    484
    485	/* Set basic properties */
    486
    487	bcm4908_pinctrl->dev = dev;
    488
    489	bcm4908_pinctrl->base = devm_platform_ioremap_resource(pdev, 0);
    490	if (IS_ERR(bcm4908_pinctrl->base))
    491		return PTR_ERR(bcm4908_pinctrl->base);
    492
    493	mutex_init(&bcm4908_pinctrl->mutex);
    494
    495	memcpy(pctldesc, &bcm4908_pinctrl_desc, sizeof(*pctldesc));
    496
    497	/* Set pinctrl properties */
    498
    499	pin_names = devm_kasprintf_strarray(dev, "pin", BCM4908_NUM_PINS);
    500	if (IS_ERR(pin_names))
    501		return PTR_ERR(pin_names);
    502
    503	pins = devm_kcalloc(dev, BCM4908_NUM_PINS, sizeof(*pins), GFP_KERNEL);
    504	if (!pins)
    505		return -ENOMEM;
    506	for (i = 0; i < BCM4908_NUM_PINS; i++) {
    507		pins[i].number = i;
    508		pins[i].name = pin_names[i];
    509	}
    510	pctldesc->pins = pins;
    511	pctldesc->npins = BCM4908_NUM_PINS;
    512
    513	/* Register */
    514
    515	bcm4908_pinctrl->pctldev = devm_pinctrl_register(dev, pctldesc, bcm4908_pinctrl);
    516	if (IS_ERR(bcm4908_pinctrl->pctldev))
    517		return dev_err_probe(dev, PTR_ERR(bcm4908_pinctrl->pctldev),
    518				     "Failed to register pinctrl\n");
    519
    520	/* Groups */
    521
    522	for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_grps); i++) {
    523		const struct bcm4908_pinctrl_grp *group = &bcm4908_pinctrl_grps[i];
    524		int *pins;
    525		int j;
    526
    527		pins = devm_kcalloc(dev, group->num_pins, sizeof(*pins), GFP_KERNEL);
    528		if (!pins)
    529			return -ENOMEM;
    530		for (j = 0; j < group->num_pins; j++)
    531			pins[j] = group->pins[j].number;
    532
    533		pinctrl_generic_add_group(bcm4908_pinctrl->pctldev, group->name,
    534					  pins, group->num_pins, (void *)group);
    535	}
    536
    537	/* Functions */
    538
    539	for (i = 0; i < ARRAY_SIZE(bcm4908_pinctrl_functions); i++) {
    540		const struct bcm4908_pinctrl_function *function = &bcm4908_pinctrl_functions[i];
    541
    542		pinmux_generic_add_function(bcm4908_pinctrl->pctldev,
    543					    function->name,
    544					    function->groups,
    545					    function->num_groups, NULL);
    546	}
    547
    548	return 0;
    549}
    550
    551static struct platform_driver bcm4908_pinctrl_driver = {
    552	.probe = bcm4908_pinctrl_probe,
    553	.driver = {
    554		.name = "bcm4908-pinctrl",
    555		.of_match_table = bcm4908_pinctrl_of_match_table,
    556	},
    557};
    558
    559module_platform_driver(bcm4908_pinctrl_driver);
    560
    561MODULE_AUTHOR("Rafał Miłecki");
    562MODULE_LICENSE("GPL v2");
    563MODULE_DEVICE_TABLE(of, bcm4908_pinctrl_of_match_table);