diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 14:05:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 14:05:46 -0700 |
commit | 914311c9fb9bc01a215de9d848b72b5449c0e342 (patch) | |
tree | e130f41c9c721bae03d6e293ffe0039d1a9018ea | |
parent | 5dedb9f3bd5bcb186313ea0c0cff8f2c525d4122 (diff) | |
parent | 8b8b091bf07fa7ef7f13c1ac40b30bcf74050b60 (diff) |
Merge tag 'pinctrl-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control changes from Linus Walleij:
"These are the accumulated pin control patches for v3.6:
- Various cleanups to the U300 driver
- Refactor the pin control core to automatically remove any GPIO
ranges when the drivers are removed, instead of having the drivers
do this explicitly.
- Add a function for registering a batch of GPIO ranges.
- Fix a number of incorrect but non-regressive error checks.
- Incremental improvements to the COH901, i.MX and Nomadik drivers
- Add a one-register-per-pin entirely Device Tree-based pin control
driver from Tony Lindgren."
* tag 'pinctrl-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl:
pinctrl: Add one-register-per-pin type device tree based pinctrl driver
pinctrl/nomadik: add spi2_oc1_2 pin group
pinctrl/nomadik: kerneldoc fix
pinctrl/nomadik: use devm_* allocators for gpio probe
pinctrl/nomadik: add pin group to mco function
pinctrl/nomadik: add hsit_a_2 pin group
pinctrl/nomadik: add pin group smcs1 and smps0
pinctrl/nomadik: fix hsir_a_1_pins pin list
pinctrl: pinctrl-imx: fix map setting problem if NO_PAD_CTL is set
pinctrl/coh901: use clk_prepare_[en|dis]able()
pinctrl/pinctrl-tegra: remove IS_ERR checking of pmx->pctl
pinctrl/pinctrl-spear: remove IS_ERR checking of pmx->pctl
pinctrl/u300: drop unused variable
pinctrl: select the proper symbol
pinctrl: add pinctrl_add_gpio_ranges function
pinctrl: remove pinctrl_remove_gpio_range
pinctrl/pinctrl-core: cleanup pinctrl_register
pinctrl/u300: delete pointless debug print
pinctrl/pinctrl-u300: remove devm_kfree at driver unload
-rw-r--r-- | Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt | 93 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/core.c | 41 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-coh901.c | 6 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-imx.c | 13 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-nomadik-db8500.c | 33 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-nomadik.c | 37 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 987 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-tegra.c | 5 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-u300.c | 6 | ||||
-rw-r--r-- | drivers/pinctrl/spear/pinctrl-spear.c | 4 | ||||
-rw-r--r-- | include/linux/pinctrl/pinctrl.h | 5 |
13 files changed, 1160 insertions, 81 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt new file mode 100644 index 000000000000..5187f0dd8b28 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt @@ -0,0 +1,93 @@ +One-register-per-pin type device tree based pinctrl driver + +Required properties: +- compatible : "pinctrl-single" + +- reg : offset and length of the register set for the mux registers + +- pinctrl-single,register-width : pinmux register access width in bits + +- pinctrl-single,function-mask : mask of allowed pinmux function bits + in the pinmux register + +Optional properties: +- pinctrl-single,function-off : function off mode for disabled state if + available and same for all registers; if not specified, disabling of + pin functions is ignored + +This driver assumes that there is only one register for each pin, +and uses the common pinctrl bindings as specified in the pinctrl-bindings.txt +document in this directory. + +The pin configuration nodes for pinctrl-single are specified as pinctrl +register offset and value pairs using pinctrl-single,pins. Only the bits +specified in pinctrl-single,function-mask are updated. For example, setting +a pin for a device could be done with: + + pinctrl-single,pins = <0xdc 0x118>; + +Where 0xdc is the offset from the pinctrl register base address for the +device pinctrl register, and 0x118 contains the desired value of the +pinctrl register. See the device example and static board pins example +below for more information. + +Example: + +/* SoC common file */ + +/* first controller instance for pins in core domain */ +pmx_core: pinmux@4a100040 { + compatible = "pinctrl-single"; + reg = <0x4a100040 0x0196>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0xffff>; +}; + +/* second controller instance for pins in wkup domain */ +pmx_wkup: pinmux@4a31e040 { + compatible = "pinctrl-single; + reg = <0x4a31e040 0x0038>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0xffff>; +}; + + +/* board specific .dts file */ + +&pmx_core { + + /* + * map all board specific static pins enabled by the pinctrl driver + * itself during the boot (or just set them up in the bootloader) + */ + pinctrl-names = "default"; + pinctrl-0 = <&board_pins>; + + board_pins: pinmux_board_pins { + pinctrl-single,pins = < + 0x6c 0xf + 0x6e 0xf + 0x70 0xf + 0x72 0xf + >; + }; + + /* map uart2 pins */ + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + 0xd8 0x118 + 0xda 0 + 0xdc 0x118 + 0xde 0 + >; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c6e6ae0aa3b1..54e3588bef62 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -102,6 +102,14 @@ config PINCTRL_PXA910 select PINCTRL_PXA3xx select PINCONF +config PINCTRL_SINGLE + tristate "One-register-per-pin type device tree based pinctrl driver" + depends on OF + select PINMUX + select PINCONF + help + This selects the device tree based generic pinctrl driver. + config PINCTRL_SIRF bool "CSR SiRFprimaII pin controller driver" depends on ARCH_PRIMA2 @@ -130,7 +138,7 @@ config PINCTRL_U300 config PINCTRL_COH901 bool "ST-Ericsson U300 COH 901 335/571 GPIO" - depends on GPIOLIB && ARCH_U300 && PINMUX_U300 + depends on GPIOLIB && ARCH_U300 && PINCTRL_U300 help Say yes here to support GPIO interface on ST-Ericsson U300. The names of the two IP block variants supported are diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 8c074376cdea..f40b1f81ff2c 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o +obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 0cc053af70bd..fb7f3bebdc69 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -332,19 +332,16 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range); -/** - * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller - * @pctldev: pin controller device to remove the range from - * @range: the GPIO range to remove - */ -void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range) +void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *ranges, + unsigned nranges) { - mutex_lock(&pinctrl_mutex); - list_del(&range->node); - mutex_unlock(&pinctrl_mutex); + int i; + + for (i = 0; i < nranges; i++) + pinctrl_add_gpio_range(pctldev, &ranges[i]); } -EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); +EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); /** * pinctrl_get_group_selector() - returns the group selector for a group @@ -1395,9 +1392,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct pinctrl_dev *pctldev; int ret; - if (pctldesc == NULL) + if (!pctldesc) return NULL; - if (pctldesc->name == NULL) + if (!pctldesc->name) return NULL; pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL); @@ -1415,23 +1412,20 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, pctldev->dev = dev; /* check core ops for sanity */ - ret = pinctrl_check_ops(pctldev); - if (ret) { + if (pinctrl_check_ops(pctldev)) { dev_err(dev, "pinctrl ops lacks necessary functions\n"); goto out_err; } /* If we're implementing pinmuxing, check the ops for sanity */ if (pctldesc->pmxops) { - ret = pinmux_check_ops(pctldev); - if (ret) + if (pinmux_check_ops(pctldev)) goto out_err; } /* If we're implementing pinconfig, check the ops for sanity */ if (pctldesc->confops) { - ret = pinconf_check_ops(pctldev); - if (ret) + if (pinconf_check_ops(pctldev)) goto out_err; } @@ -1457,11 +1451,9 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, if (IS_ERR(s)) { dev_dbg(dev, "failed to lookup the default state\n"); } else { - ret = pinctrl_select_state_locked(pctldev->p, s); - if (ret) { + if (pinctrl_select_state_locked(pctldev->p, s)) dev_err(dev, "failed to select default state\n"); - } } } @@ -1485,6 +1477,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register); */ void pinctrl_unregister(struct pinctrl_dev *pctldev) { + struct pinctrl_gpio_range *range, *n; if (pctldev == NULL) return; @@ -1500,6 +1493,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev) /* Destroy descriptor tree */ pinctrl_free_pindescs(pctldev, pctldev->desc->pins, pctldev->desc->npins); + /* remove gpio ranges map */ + list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node) + list_del(&range->node); + kfree(pctldev); mutex_unlock(&pinctrl_mutex); diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 55697a5d7482..cc0f00d73d15 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -770,7 +770,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev) dev_err(gpio->dev, "could not get GPIO clock\n"); goto err_no_clk; } - err = clk_enable(gpio->clk); + err = clk_prepare_enable(gpio->clk); if (err) { dev_err(gpio->dev, "could not enable GPIO clock\n"); goto err_no_clk_enable; @@ -912,7 +912,7 @@ err_no_ioremap: release_mem_region(gpio->memres->start, resource_size(gpio->memres)); err_no_ioregion: err_no_resource: - clk_disable(gpio->clk); + clk_disable_unprepare(gpio->clk); err_no_clk_enable: clk_put(gpio->clk); err_no_clk: @@ -943,7 +943,7 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) iounmap(gpio->base); release_mem_region(gpio->memres->start, resource_size(gpio->memres)); - clk_disable(gpio->clk); + clk_disable_unprepare(gpio->clk); clk_put(gpio->clk); platform_set_drvdata(pdev, NULL); kfree(gpio); diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index 90c837f469a6..44e97265cd7d 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -146,7 +146,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct pinctrl_map *new_map; struct device_node *parent; int map_num = 1; - int i; + int i, j; /* * first find the group of this node and check if we need create @@ -184,13 +184,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, /* create config map */ new_map++; - for (i = 0; i < grp->npins; i++) { + for (i = j = 0; i < grp->npins; i++) { if (!(grp->configs[i] & IMX_NO_PAD_CTL)) { - new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; - new_map[i].data.configs.group_or_pin = + new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[j].data.configs.group_or_pin = pin_get_name(pctldev, grp->pins[i]); - new_map[i].data.configs.configs = &grp->configs[i]; - new_map[i].data.configs.num_configs = 1; + new_map[j].data.configs.configs = &grp->configs[i]; + new_map[j].data.configs.num_configs = 1; + j++; } } diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index 8b2022276f71..6f99769c6733 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -467,9 +467,12 @@ static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15, DB8500_PIN_AH15 }; static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, DB8500_PIN_AH12, DB8500_PIN_AH11 }; -static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10 }; -static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ11, DB8500_PIN_AJ9, - DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; +static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10, + DB8500_PIN_AJ11 }; +static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; +static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8 }; static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 }; static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29, @@ -508,9 +511,11 @@ static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5, - DB8500_PIN_C9, DB8500_PIN_B14 }; -/* This chip select pin can be "ps0" in alt B so have it separately */ + DB8500_PIN_C9 }; +/* This chip select pin can be "ps0" in alt C so have it separately */ static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 }; +/* This chip select pin can be "ps1" in alt C so have it separately */ +static const unsigned smcs1_b_1_pins[] = { DB8500_PIN_B14 }; static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 }; static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 }; static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 }; @@ -572,6 +577,7 @@ static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 }; static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11, DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16, DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned smps0_c_1_pins[] = { DB8500_PIN_E8 }; static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 }; static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 }; static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, @@ -595,6 +601,8 @@ static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_D6, DB8500_PIN_B7 }; static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, DB8500_PIN_AH12, DB8500_PIN_AH11 }; +static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12, + DB8500_PIN_AH11 }; #define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \ .npins = ARRAY_SIZE(a##_pins), .altsetting = b } @@ -610,6 +618,8 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0_dat47_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0dat31dir_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A), @@ -631,6 +641,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), @@ -653,6 +664,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B), DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B), DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(smcs1_b_1, NMK_GPIO_ALT_B), DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B), DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B), DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B), @@ -693,6 +705,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smps0_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C), @@ -709,6 +722,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { /* Other alt C1 column, these are still configured as alt C */ DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C), }; /* We use this macro to define the groups applicable to a function */ @@ -731,7 +745,7 @@ DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2"); */ DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1", "msp0txrx_b_1", "msp0sck_b_1"); -DB8500_FUNC_GROUPS(mc0, "mc0_a_1"); +DB8500_FUNC_GROUPS(mc0, "mc0_a_1", "mc0_dat47_a_1", "mc0dat31dir_a_1"); /* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1"); DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1"); @@ -752,7 +766,7 @@ DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1", DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1"); -DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1"); +DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1", "hsit_a_2"); DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1"); DB8500_FUNC_GROUPS(usb, "usb_a_1"); DB8500_FUNC_GROUPS(trig, "trig_b_1"); @@ -768,7 +782,8 @@ DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2", DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1"); DB8500_FUNC_GROUPS(spi3, "spi3_b_1"); /* Select between CS0 on alt B or PS1 on alt C */ -DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcleale_c_1", "smps1_c_1"); +DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1", + "smps0_c_1", "smps1_c_1"); DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1"); DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1"); DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4"); @@ -783,7 +798,7 @@ DB8500_FUNC_GROUPS(mc5, "mc5_c_1"); DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2"); DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2"); DB8500_FUNC_GROUPS(spi0, "spi0_c_1"); -DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1"); +DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2"); #define FUNCTION(fname) \ { \ diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index dd9e6f26416d..53b0d49a7a1c 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -434,7 +434,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) /** * nmk_config_pin - configure a pin's mux attributes * @cfg: pin confguration - * + * @sleep: Non-zero to apply the sleep mode configuration * Configures a pin's mode (alternate function or GPIO), its pull up status, * and its sleep mode based on the specified configuration. The @cfg is * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These @@ -1194,7 +1194,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) } if (np) { - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -1229,29 +1229,23 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) goto out; } - if (request_mem_region(res->start, resource_size(res), - dev_name(&dev->dev)) == NULL) { - ret = -EBUSY; - goto out; - } - - base = ioremap(res->start, resource_size(res)); + base = devm_request_and_ioremap(&dev->dev, res); if (!base) { ret = -ENOMEM; - goto out_release; + goto out; } - clk = clk_get(&dev->dev, NULL); + clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - goto out_unmap; + goto out; } clk_prepare(clk); - nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); + nmk_chip = devm_kzalloc(&dev->dev, sizeof(*nmk_chip), GFP_KERNEL); if (!nmk_chip) { ret = -ENOMEM; - goto out_clk; + goto out; } /* @@ -1286,7 +1280,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) ret = gpiochip_add(&nmk_chip->chip); if (ret) - goto out_free; + goto out; BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); @@ -1300,7 +1294,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) if (!nmk_chip->domain) { pr_err("%s: Failed to create irqdomain\n", np->full_name); ret = -ENOSYS; - goto out_free; + goto out; } nmk_gpio_init_irq(nmk_chip); @@ -1309,20 +1303,9 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) return 0; -out_free: - kfree(nmk_chip); -out_clk: - clk_disable(clk); - clk_put(clk); -out_unmap: - iounmap(base); -out_release: - release_mem_region(res->start, resource_size(res)); out: dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, pdata->first_gpio, pdata->first_gpio+31); - if (np) - kfree(pdata); return ret; } diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c new file mode 100644 index 000000000000..76a4260f20f3 --- /dev/null +++ b/drivers/pinctrl/pinctrl-single.c @@ -0,0 +1,987 @@ +/* + * Generic device tree based pinctrl driver for one register per pin + * type pinmux controllers + * + * Copyright (C) 2012 Texas Instruments, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/list.h> + +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> + +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "core.h" + +#define DRIVER_NAME "pinctrl-single" +#define PCS_MUX_NAME "pinctrl-single,pins" +#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) +#define PCS_OFF_DISABLED ~0U + +/** + * struct pcs_pingroup - pingroups for a function + * @np: pingroup device node pointer + * @name: pingroup name + * @gpins: array of the pins in the group + * @ngpins: number of pins in the group + * @node: list node + */ +struct pcs_pingroup { + struct device_node *np; + const char *name; + int *gpins; + int ngpins; + struct list_head node; +}; + +/** + * struct pcs_func_vals - mux function register offset and value pair + * @reg: register virtual address + * @val: register value + */ +struct pcs_func_vals { + void __iomem *reg; + unsigned val; +}; + +/** + * struct pcs_function - pinctrl function + * @name: pinctrl function name + * @vals: register and vals array + * @nvals: number of entries in vals array + * @pgnames: array of pingroup names the function uses + * @npgnames: number of pingroup names the function uses + * @node: list node + */ +struct pcs_function { + const char *name; + struct pcs_func_vals *vals; + unsigned nvals; + const char **pgnames; + int npgnames; + struct list_head node; +}; + +/** + * struct pcs_data - wrapper for data needed by pinctrl framework + * @pa: pindesc array + * @cur: index to current element + * + * REVISIT: We should be able to drop this eventually by adding + * support for registering pins individually in the pinctrl + * framework for those drivers that don't need a static array. + */ +struct pcs_data { + struct pinctrl_pin_desc *pa; + int cur; +}; + +/** + * struct pcs_name - register name for a pin + * @name: name of the pinctrl register + * + * REVISIT: We may want to make names optional in the pinctrl + * framework as some drivers may not care about pin names to + * avoid kernel bloat. The pin names can be deciphered by user + * space tools using debugfs based on the register address and + * SoC packaging information. + */ +struct pcs_name { + char name[PCS_REG_NAME_LEN]; +}; + +/** + * struct pcs_device - pinctrl device instance + * @res: resources + * @base: virtual address of the controller + * @size: size of the ioremapped area + * @dev: device entry + * @pctl: pin controller device + * @mutex: mutex protecting the lists + * @width: bits per mux register + * @fmask: function register mask + * @fshift: function register shift + * @foff: value to turn mux off + * @fmax: max number of functions in fmask + * @names: array of register names for pins + * @pins: physical pins on the SoC + * @pgtree: pingroup index radix tree + * @ftree: function index radix tree + * @pingroups: list of pingroups + * @functions: list of functions + * @ngroups: number of pingroups + * @nfuncs: number of functions + * @desc: pin controller descriptor + * @read: register read function to use + * @write: register write function to use + */ +struct pcs_device { + struct resource *res; + void __iomem *base; + unsigned size; + struct device *dev; + struct pinctrl_dev *pctl; + struct mutex mutex; + unsigned width; + unsigned fmask; + unsigned fshift; + unsigned foff; + unsigned fmax; + struct pcs_name *names; + struct pcs_data pins; + struct radix_tree_root pgtree; + struct radix_tree_root ftree; + struct list_head pingroups; + struct list_head functions; + unsigned ngroups; + unsigned nfuncs; + struct pinctrl_desc desc; + unsigned (*read)(void __iomem *reg); + void (*write)(unsigned val, void __iomem *reg); +}; + +/* + * REVISIT: Reads and writes could eventually use regmap or something + * generic. But at least on omaps, some mux registers are performance + * critical as they may need to be remuxed every time before and after + * idle. Adding tests for register access width for every read and + * write like regmap is doing is not desired, and caching the registers + * does not help in this case. + */ + +static unsigned __maybe_unused pcs_readb(void __iomem *reg) +{ + return readb(reg); +} + +static unsigned __maybe_unused pcs_readw(void __iomem *reg) +{ + return readw(reg); +} + +static unsigned __maybe_unused pcs_readl(void __iomem *reg) +{ + return readl(reg); +} + +static void __maybe_unused pcs_writeb(unsigned val, void __iomem *reg) +{ + writeb(val, reg); +} + +static void __maybe_unused pcs_writew(unsigned val, void __iomem *reg) +{ + writew(val, reg); +} + +static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg) +{ + writel(val, reg); +} + +static int pcs_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pcs_device *pcs; + + pcs = pinctrl_dev_get_drvdata(pctldev); + + return pcs->ngroups; +} + +static const char *pcs_get_group_name(struct pinctrl_dev *pctldev, + unsigned gselector) +{ + struct pcs_device *pcs; + struct pcs_pingroup *group; + + pcs = pinctrl_dev_get_drvdata(pctldev); + group = radix_tree_lookup(&pcs->pgtree, gselector); + if (!group) { + dev_err(pcs->dev, "%s could not find pingroup%i\n", + __func__, gselector); + return NULL; + } + + return group->name; +} + +static int pcs_get_group_pins(struct pinctrl_dev *pctldev, + unsigned gselector, + const unsigned **pins, + unsigned *npins) +{ + struct pcs_device *pcs; + struct pcs_pingroup *group; + + pcs = pinctrl_dev_get_drvdata(pctldev); + group = radix_tree_lookup(&pcs->pgtree, gselector); + if (!group) { + dev_err(pcs->dev, "%s could not find pingroup%i\n", + __func__, gselector); + return -EINVAL; + } + + *pins = group->gpins; + *npins = group->ngpins; + + return 0; +} + +static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned offset) +{ + seq_printf(s, " " DRIVER_NAME); +} + +static void pcs_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + struct pcs_device *pcs; + + pcs = pinctrl_dev_get_drvdata(pctldev); + devm_kfree(pcs->dev, map); +} + +static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps); + +static struct pinctrl_ops pcs_pinctrl_ops = { + .get_groups_count = pcs_get_groups_count, + .get_group_name = pcs_get_group_name, + .get_group_pins = pcs_get_group_pins, + .pin_dbg_show = pcs_pin_dbg_show, + .dt_node_to_map = pcs_dt_node_to_map, + .dt_free_map = pcs_dt_free_map, +}; + +static int pcs_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct pcs_device *pcs; + + pcs = pinctrl_dev_get_drvdata(pctldev); + + return pcs->nfuncs; +} + +static const char *pcs_get_function_name(struct pinctrl_dev *pctldev, + unsigned fselector) +{ + struct pcs_device *pcs; + struct pcs_function *func; + + pcs = pinctrl_dev_get_drvdata(pctldev); + func = radix_tree_lookup(&pcs->ftree, fselector); + if (!func) { + dev_err(pcs->dev, "%s could not find function%i\n", + __func__, fselector); + return NULL; + } + + return func->name; +} + +static int pcs_get_function_groups(struct pinctrl_dev *pctldev, + unsigned fselector, + const char * const **groups, + unsigned * const ngroups) +{ + struct pcs_device *pcs; + struct pcs_function *func; + + pcs = pinctrl_dev_get_drvdata(pctldev); + func = radix_tree_lookup(&pcs->ftree, fselector); + if (!func) { + dev_err(pcs->dev, "%s could not find function%i\n", + __func__, fselector); + return -EINVAL; + } + *groups = func->pgnames; + *ngroups = func->npgnames; + + return 0; +} + +static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, + unsigned group) +{ + struct pcs_device *pcs; + struct pcs_function *func; + int i; + + pcs = pinctrl_dev_get_drvdata(pctldev); + func = radix_tree_lookup(&pcs->ftree, fselector); + if (!func) + return -EINVAL; + + dev_dbg(pcs->dev, "enabling %s function%i\n", + func->name, fselector); + + for (i = 0; i < func->nvals; i++) { + struct pcs_func_vals *vals; + unsigned val; + + vals = &func->vals[i]; + val = pcs->read(vals->reg); + val &= ~pcs->fmask; + val |= vals->val; + pcs->write(val, vals->reg); + } + + return 0; +} + +static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, + unsigned group) +{ + struct pcs_device *pcs; + struct pcs_function *func; + int i; + + pcs = pinctrl_dev_get_drvdata(pctldev); + func = radix_tree_lookup(&pcs->ftree, fselector); + if (!func) { + dev_err(pcs->dev, "%s could not find function%i\n", + __func__, fselector); + return; + } + + /* + * Ignore disable if function-off is not specified. Some hardware + * does not have clearly defined disable function. For pin specific + * off modes, you can use alternate named states as described in + * pinctrl-bindings.txt. + */ + if (pcs->foff == PCS_OFF_DISABLED) { + dev_dbg(pcs->dev, "ignoring disable for %s function%i\n", + func->name, fselector); + return; + } + + dev_dbg(pcs->dev, "disabling function%i %s\n", + fselector, func->name); + + for (i = 0; i < func->nvals; i++) { + struct pcs_func_vals *vals; + unsigned val; + + vals = &func->vals[i]; + val = pcs->read(vals->reg); + val &= ~pcs->fmask; + val |= pcs->foff << pcs->fshift; + pcs->write(val, vals->reg); + } +} + +static int pcs_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + return -ENOTSUPP; +} + +static struct pinmux_ops pcs_pinmux_ops = { + .get_functions_count = pcs_get_functions_count, + .get_function_name = pcs_get_function_name, + .get_function_groups = pcs_get_function_groups, + .enable = pcs_enable, + .disable = pcs_disable, + .gpio_request_enable = pcs_request_gpio, +}; + +static int pcs_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long *config) +{ + return -ENOTSUPP; +} + +static int pcs_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long config) +{ + return -ENOTSUPP; +} + +static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned group, unsigned long *config) +{ + return -ENOTSUPP; +} + +static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned group, unsigned long config) +{ + return -ENOTSUPP; +} + +static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ +} + +static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned selector) +{ +} + +static struct pinconf_ops pcs_pinconf_ops = { + .pin_config_get = pcs_pinconf_get, + .pin_config_set = pcs_pinconf_set, + .pin_config_group_get = pcs_pinconf_group_get, + .pin_config_group_set = pcs_pinconf_group_set, + .pin_config_dbg_show = pcs_pinconf_dbg_show, + .pin_config_group_dbg_show = pcs_pinconf_group_dbg_show, +}; + +/** + * pcs_add_pin() - add a pin to the static per controller pin array + * @pcs: pcs driver instance + * @offset: register offset from base + */ +static int __devinit pcs_add_pin(struct pcs_device *pcs, unsigned offset) +{ + struct pinctrl_pin_desc *pin; + struct pcs_name *pn; + int i; + + i = pcs->pins.cur; + if (i >= pcs->desc.npins) { + dev_err(pcs->dev, "too many pins, max %i\n", + pcs->desc.npins); + return -ENOMEM; + } + + pin = &pcs->pins.pa[i]; + pn = &pcs->names[i]; + sprintf(pn->name, "%lx", + (unsigned long)pcs->res->start + offset); + pin->name = pn->name; + pin->number = i; + pcs->pins.cur++; + + return i; +} + +/** + * pcs_allocate_pin_table() - adds all the pins for the pinctrl driver + * @pcs: pcs driver instance + * + * In case of errors, resources are freed in pcs_free_resources. + * + * If your hardware needs holes in the address space, then just set + * up multiple driver instances. + */ +static int __devinit pcs_allocate_pin_table(struct pcs_device *pcs) +{ + int mux_bytes, nr_pins, i; + + mux_bytes = pcs->width / BITS_PER_BYTE; + nr_pins = pcs->size / mux_bytes; + + dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins); + pcs->pins.pa = devm_kzalloc(pcs->dev, + sizeof(*pcs->pins.pa) * nr_pins, + GFP_KERNEL); + if (!pcs->pins.pa) + return -ENOMEM; + + pcs->names = devm_kzalloc(pcs->dev, + sizeof(struct pcs_name) * nr_pins, + GFP_KERNEL); + if (!pcs->names) + return -ENOMEM; + + pcs->desc.pins = pcs->pins.pa; + pcs->desc.npins = nr_pins; + + for (i = 0; i < pcs->desc.npins; i++) { + unsigned offset; + int res; + + offset = i * mux_bytes; + res = pcs_add_pin(pcs, offset); + if (res < 0) { + dev_err(pcs->dev, "error adding pins: %i\n", res); + return res; + } + } + + return 0; +} + +/** + * pcs_add_function() - adds a new function to the function list + * @pcs: pcs driver instance + * @np: device node of the mux entry + * @name: name of the function + * @vals: array of mux register value pairs used by the function + * @nvals: number of mux register value pairs + * @pgnames: array of pingroup names for the function + * @npgnames: number of pingroup names + */ +static struct pcs_function *pcs_add_function(struct pcs_device *pcs, + struct device_node *np, + const char *name, + struct pcs_func_vals *vals, + unsigned nvals, + const char **pgnames, + unsigned npgnames) +{ + struct pcs_function *function; + + function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL); + if (!function) + return NULL; + + function->name = name; + function->vals = vals; + function->nvals = nvals; + function->pgnames = pgnames; + function->npgnames = npgnames; + + mutex_lock(&pcs->mutex); + list_add_tail(&function->node, &pcs->functions); + radix_tree_insert(&pcs->ftree, pcs->nfuncs, function); + pcs->nfuncs++; + mutex_unlock(&pcs->mutex); + + return function; +} + +static void pcs_remove_function(struct pcs_device *pcs, + struct pcs_function *function) +{ + int i; + + mutex_lock(&pcs->mutex); + for (i = 0; i < pcs->nfuncs; i++) { + struct pcs_function *found; + + found = radix_tree_lookup(&pcs->ftree, i); + if (found == function) + radix_tree_delete(&pcs->ftree, i); + } + list_del(&function->node); + mutex_unlock(&pcs->mutex); +} + +/** + * pcs_add_pingroup() - add a pingroup to the pingroup list + * @pcs: pcs driver instance + * @np: device node of the mux entry + * @name: name of the pingroup + * @gpins: array of the pins that belong to the group + * @ngpins: number of pins in the group + */ +static int pcs_add_pingroup(struct pcs_device *pcs, + struct device_node *np, + const char *name, + int *gpins, + int ngpins) +{ + struct pcs_pingroup *pingroup; + + pingroup = devm_kzalloc(pcs->dev, sizeof(*pingroup), GFP_KERNEL); + if (!pingroup) + return -ENOMEM; + + pingroup->name = name; + pingroup->np = np; + pingroup->gpins = gpins; + pingroup->ngpins = ngpins; + + mutex_lock(&pcs->mutex); + list_add_tail(&pingroup->node, &pcs->pingroups); + radix_tree_insert(&pcs->pgtree, pcs->ngroups, pingroup); + pcs->ngroups++; + mutex_unlock(&pcs->mutex); + + return 0; +} + +/** + * pcs_get_pin_by_offset() - get a pin index based on the register offset + * @pcs: pcs driver instance + * @offset: register offset from the base + * + * Note that this is OK as long as the pins are in a static array. + */ +static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset) +{ + unsigned index; + + if (offset >= pcs->size) { + dev_err(pcs->dev, "mux offset out of range: 0x%x (0x%x)\n", + offset, pcs->size); + return -EINVAL; + } + + index = offset / (pcs->width / BITS_PER_BYTE); + + return index; +} + +/** + * smux_parse_one_pinctrl_entry() - parses a device tree mux entry + * @pcs: pinctrl driver instance + * @np: device node of the mux entry + * @map: map entry + * @pgnames: pingroup names + * + * Note that this binding currently supports only sets of one register + value. + * + * Also note that this driver tries to avoid understanding pin and function + * names because of the extra bloat they would cause especially in the case of + * a large number of pins. This driver just sets what is specified for the board + * in the .dts file. Further user space debugging tools can be developed to + * decipher the pin and function names using debugfs. + * + * If you are concerned about the boot time, set up the static pins in + * the bootloader, and only set up selected pins as device tree entries. + */ +static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, + struct device_node *np, + struct pinctrl_map **map, + const char **pgnames) +{ + struct pcs_func_vals *vals; + const __be32 *mux; + int size, rows, *pins, index = 0, found = 0, res = -ENOMEM; + struct pcs_function *function; + + mux = of_get_property(np, PCS_MUX_NAME, &size); + if ((!mux) || (size < sizeof(*mux) * 2)) { + dev_err(pcs->dev, "bad data for mux %s\n", + np->name); + return -EINVAL; + } + + size /= sizeof(*mux); /* Number of elements in array */ + rows = size / 2; /* Each row is a key value pair */ + + vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL); + if (!vals) + return -ENOMEM; + + pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows, GFP_KERNEL); + if (!pins) + goto free_vals; + + while (index < size) { + unsigned offset, val; + int pin; + + offset = be32_to_cpup(mux + index++); + val = be32_to_cpup(mux + index++); + vals[found].reg = pcs->base + offset; + vals[found].val = val; + + pin = pcs_get_pin_by_offset(pcs, offset); + if (pin < 0) { + dev_err(pcs->dev, + "could not add functions for %s %ux\n", + np->name, offset); + break; + } + pins[found++] = pin; + } + + pgnames[0] = np->name; + function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1); + if (!function) + goto free_pins; + + res = pcs_add_pingroup(pcs, np, np->name, pins, found); + if (res < 0) + goto free_function; + + (*map)->type = PIN_MAP_TYPE_MUX_GROUP; + (*map)->data.mux.group = np->name; + (*map)->data.mux.function = np->name; + + return 0; + +free_function: + pcs_remove_function(pcs, function); + +free_pins: + devm_kfree(pcs->dev, pins); + +free_vals: + devm_kfree(pcs->dev, vals); + + return res; +} +/** + * pcs_dt_node_to_map() - allocates and parses pinctrl maps + * @pctldev: pinctrl instance + * @np_config: device tree pinmux entry + * @map: array of map entries + * @num_maps: number of maps + */ +static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct pcs_device *pcs; + const char **pgnames; + int ret; + + pcs = pinctrl_dev_get_drvdata(pctldev); + + *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + *num_maps = 0; + + pgnames = devm_kzalloc(pcs->dev, sizeof(*pgnames), GFP_KERNEL); + if (!pgnames) { + ret = -ENOMEM; + goto free_map; + } + + ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames); + if (ret < 0) { + dev_err(pcs->dev, "no pins entries for %s\n", + np_config->name); + goto free_pgnames; + } + *num_maps = 1; + + return 0; + +free_pgnames: + devm_kfree(pcs->dev, pgnames); +free_map: + devm_kfree(pcs->dev, *map); + + return ret; +} + +/** + * pcs_free_funcs() - free memory used by functions + * @pcs: pcs driver instance + */ +static void pcs_free_funcs(struct pcs_device *pcs) +{ + struct list_head *pos, *tmp; + int i; + + mutex_lock(&pcs->mutex); + for (i = 0; i < pcs->nfuncs; i++) { + struct pcs_function *func; + + func = radix_tree_lookup(&pcs->ftree, i); + if (!func) + continue; + radix_tree_delete(&pcs->ftree, i); + } + list_for_each_safe(pos, tmp, &pcs->functions) { + struct pcs_function *function; + + function = list_entry(pos, struct pcs_function, node); + list_del(&function->node); + } + mutex_unlock(&pcs->mutex); +} + +/** + * pcs_free_pingroups() - free memory used by pingroups + * @pcs: pcs driver instance + */ +static void pcs_free_pingroups(struct pcs_device *pcs) +{ + struct list_head *pos, *tmp; + int i; + + mutex_lock(&pcs->mutex); + for (i = 0; i < pcs->ngroups; i++) { + struct pcs_pingroup *pingroup; + + pingroup = radix_tree_lookup(&pcs->pgtree, i); + if (!pingroup) + continue; + radix_tree_delete(&pcs->pgtree, i); + } + list_for_each_safe(pos, tmp, &pcs->pingroups) { + struct pcs_pingroup *pingroup; + + pingroup = list_entry(pos, struct pcs_pingroup, node); + list_del(&pingroup->node); + } + mutex_unlock(&pcs->mutex); +} + +/** + * pcs_free_resources() - free memory used by this driver + * @pcs: pcs driver instance + */ +static void pcs_free_resources(struct pcs_device *pcs) +{ + if (pcs->pctl) + pinctrl_unregister(pcs->pctl); + + pcs_free_funcs(pcs); + pcs_free_pingroups(pcs); +} + +#define PCS_GET_PROP_U32(name, reg, err) \ + do { \ + ret = of_property_read_u32(np, name, reg); \ + if (ret) { \ + dev_err(pcs->dev, err); \ + return ret; \ + } \ + } while (0); + +static struct of_device_id pcs_of_match[]; + +static int __devinit pcs_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + struct resource *res; + struct pcs_device *pcs; + int ret; + + match = of_match_device(pcs_of_match, &pdev->dev); + if (!match) + return -EINVAL; + + pcs = devm_kzalloc(&pdev->dev, sizeof(*pcs), GFP_KERNEL); + if (!pcs) { + dev_err(&pdev->dev, "could not allocate\n"); + return -ENOMEM; + } + pcs->dev = &pdev->dev; + mutex_init(&pcs->mutex); + INIT_LIST_HEAD(&pcs->pingroups); + INIT_LIST_HEAD(&pcs->functions); + + PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width, + "register width not specified\n"); + + PCS_GET_PROP_U32("pinctrl-single,function-mask", &pcs->fmask, + "function register mask not specified\n"); + pcs->fshift = ffs(pcs->fmask) - 1; + pcs->fmax = pcs->fmask >> pcs->fshift; + + ret = of_property_read_u32(np, "pinctrl-single,function-off", + &pcs->foff); + if (ret) + pcs->foff = PCS_OFF_DISABLED; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(pcs->dev, "could not get resource\n"); + return -ENODEV; + } + + pcs->res = devm_request_mem_region(pcs->dev, res->start, + resource_size(res), DRIVER_NAME); + if (!pcs->res) { + dev_err(pcs->dev, "could not get mem_region\n"); + return -EBUSY; + } + + pcs->size = resource_size(pcs->res); + pcs->base = devm_ioremap(pcs->dev, pcs->res->start, pcs->size); + if (!pcs->base) { + dev_err(pcs->dev, "could not ioremap\n"); + return -ENODEV; + } + + INIT_RADIX_TREE(&pcs->pgtree, GFP_KERNEL); + INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL); + platform_set_drvdata(pdev, pcs); + + switch (pcs->width) { + case 8: + pcs->read = pcs_readb; + pcs->write = pcs_writeb; + break; + case 16: + pcs->read = pcs_readw; + pcs->write = pcs_writew; + break; + case 32: + pcs->read = pcs_readl; + pcs->write = pcs_writel; + break; + default: + break; + } + + pcs->desc.name = DRIVER_NAME; + pcs->desc.pctlops = &pcs_pinctrl_ops; + pcs->desc.pmxops = &pcs_pinmux_ops; + pcs->desc.confops = &pcs_pinconf_ops; + pcs->desc.owner = THIS_MODULE; + + ret = pcs_allocate_pin_table(pcs); + if (ret < 0) + goto free; + + pcs->pctl = pinctrl_register(&pcs->desc, pcs->dev, pcs); + if (!pcs->pctl) { + dev_err(pcs->dev, "could not register single pinctrl driver\n"); + ret = -EINVAL; + goto free; + } + + dev_info(pcs->dev, "%i pins at pa %p size %u\n", + pcs->desc.npins, pcs->base, pcs->size); + + return 0; + +free: + pcs_free_resources(pcs); + + return ret; +} + +static int __devexit pcs_remove(struct platform_device *pdev) +{ + struct pcs_device *pcs = platform_get_drvdata(pdev); + + if (!pcs) + return 0; + + pcs_free_resources(pcs); + + return 0; +} + +static struct of_device_id pcs_of_match[] __devinitdata = { + { .compatible = DRIVER_NAME, }, + { }, +}; +MODULE_DEVICE_TABLE(of, pcs_of_match); + +static struct platform_driver pcs_driver = { + .probe = pcs_probe, + .remove = __devexit_p(pcs_remove), + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .of_match_table = pcs_of_match, + }, +}; + +module_platform_driver(pcs_driver); + +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("One-register-per-pin type device tree based pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index b6934867d8d3..ae52e4e5d098 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -745,9 +745,9 @@ int __devinit tegra_pinctrl_probe(struct platform_device *pdev, } pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx); - if (IS_ERR(pmx->pctl)) { + if (!pmx->pctl) { dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); - return PTR_ERR(pmx->pctl); + return -ENODEV; } pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range); @@ -764,7 +764,6 @@ int __devexit tegra_pinctrl_remove(struct platform_device *pdev) { struct tegra_pmx *pmx = platform_get_drvdata(pdev); - pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range); pinctrl_unregister(pmx->pctl); return 0; diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 05d029911be6..a7ad8c112d91 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -1113,8 +1113,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) int ret; int i; - pr_err("U300 PMX PROBE\n"); - /* Create state holders etc for this driver */ upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL); if (!upmx) @@ -1175,15 +1173,11 @@ out_no_resource: static int __devexit u300_pmx_remove(struct platform_device *pdev) { struct u300_pmx *upmx = platform_get_drvdata(pdev); - int i; - for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) - pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]); pinctrl_unregister(upmx->pctl); iounmap(upmx->virtbase); release_mem_region(upmx->phybase, upmx->physize); platform_set_drvdata(pdev, NULL); - devm_kfree(&pdev->dev, upmx); return 0; } diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b3f6b2873fdd..5d4f44f462f0 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -336,9 +336,9 @@ int __devinit spear_pinctrl_probe(struct platform_device *pdev, spear_pinctrl_desc.npins = machdata->npins; pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx); - if (IS_ERR(pmx->pctl)) { + if (!pmx->pctl) { dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); - return PTR_ERR(pmx->pctl); + return -ENODEV; } return 0; diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 3b894a668d32..69393a662532 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -131,8 +131,9 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev); extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin); extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range); -extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range); +extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *ranges, + unsigned nranges); extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); #else |