mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-10 15:10:38 +00:00
Merge tag 'pinctrl-mergebase-20120418' into HEAD
Conflicts: drivers/pinctrl/core.c
This commit is contained in:
commit
b9e3b72d4a
@ -0,0 +1,132 @@
|
||||
NVIDIA Tegra20 pinmux controller
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra20-pinmux"
|
||||
- reg: Should contain the register physical address and length for each of
|
||||
the tri-state, mux, pull-up/down, and pad control register sets.
|
||||
|
||||
Please refer to pinctrl-bindings.txt in this directory for details of the
|
||||
common pinctrl bindings used by client devices, including the meaning of the
|
||||
phrase "pin configuration node".
|
||||
|
||||
Tegra's pin configuration nodes act as a container for an abitrary number of
|
||||
subnodes. Each of these subnodes represents some desired configuration for a
|
||||
pin, a group, or a list of pins or groups. This configuration can include the
|
||||
mux function to select on those pin(s)/group(s), and various pin configuration
|
||||
parameters, such as pull-up, tristate, drive strength, etc.
|
||||
|
||||
The name of each subnode is not important; all subnodes should be enumerated
|
||||
and processed purely based on their content.
|
||||
|
||||
Each subnode only affects those parameters that are explicitly listed. In
|
||||
other words, a subnode that lists a mux function but no pin configuration
|
||||
parameters implies no information about any pin configuration parameters.
|
||||
Similarly, a pin subnode that describes a pullup parameter implies no
|
||||
information about e.g. the mux function or tristate parameter. For this
|
||||
reason, even seemingly boolean values are actually tristates in this binding:
|
||||
unspecified, off, or on. Unspecified is represented as an absent property,
|
||||
and off/on are represented as integer values 0 and 1.
|
||||
|
||||
Required subnode-properties:
|
||||
- nvidia,pins : An array of strings. Each string contains the name of a pin or
|
||||
group. Valid values for these names are listed below.
|
||||
|
||||
Optional subnode-properties:
|
||||
- nvidia,function: A string containing the name of the function to mux to the
|
||||
pin or group. Valid values for function names are listed below. See the Tegra
|
||||
TRM to determine which are valid for each pin or group.
|
||||
- nvidia,pull: Integer, representing the pull-down/up to apply to the pin.
|
||||
0: none, 1: down, 2: up.
|
||||
- nvidia,tristate: Integer.
|
||||
0: drive, 1: tristate.
|
||||
- nvidia,high-speed-mode: Integer. Enable high speed mode the pins.
|
||||
0: no, 1: yes.
|
||||
- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input.
|
||||
0: no, 1: yes.
|
||||
- nvidia,low-power-mode: Integer. Valid values 0-3. 0 is least power, 3 is
|
||||
most power. Controls the drive power or current. See "Low Power Mode"
|
||||
or "LPMD1" and "LPMD0" in the Tegra TRM.
|
||||
- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest.
|
||||
The range of valid values depends on the pingroup. See "CAL_DRVDN" in the
|
||||
Tegra TRM.
|
||||
- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest.
|
||||
The range of valid values depends on the pingroup. See "CAL_DRVUP" in the
|
||||
Tegra TRM.
|
||||
- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is
|
||||
fastest. The range of valid values depends on the pingroup. See
|
||||
"DRVDN_SLWR" in the Tegra TRM.
|
||||
- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is
|
||||
fastest. The range of valid values depends on the pingroup. See
|
||||
"DRVUP_SLWF" in the Tegra TRM.
|
||||
|
||||
Note that many of these properties are only valid for certain specific pins
|
||||
or groups. See the Tegra TRM and various pinmux spreadsheets for complete
|
||||
details regarding which groups support which functionality. The Linux pinctrl
|
||||
driver may also be a useful reference, since it consolidates, disambiguates,
|
||||
and corrects data from all those sources.
|
||||
|
||||
Valid values for pin and group names are:
|
||||
|
||||
mux groups:
|
||||
|
||||
These all support nvidia,function, nvidia,tristate, and many support
|
||||
nvidia,pull.
|
||||
|
||||
ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1, dap2, dap3, dap4,
|
||||
ddc, dta, dtb, dtc, dtd, dte, dtf, gma, gmb, gmc, gmd, gme, gpu, gpu7,
|
||||
gpv, hdint, i2cp, irrx, irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn,
|
||||
ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12, ld13,
|
||||
ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2, lhs, lm0, lm1, lpp,
|
||||
lpw0, lpw1, lpw2, lsc0, lsc1, lsck, lsda, lsdi, lspi, lvp0, lvp1, lvs,
|
||||
owc, pmc, pta, rm, sdb, sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi,
|
||||
spdo, spia, spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac, uad,
|
||||
uca, ucb, uda.
|
||||
|
||||
tristate groups:
|
||||
|
||||
These only support nvidia,pull.
|
||||
|
||||
ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls, lc, ld17_0,
|
||||
ld19_18, ld21_20, ld23_22.
|
||||
|
||||
drive groups:
|
||||
|
||||
With some exceptions, these support nvidia,high-speed-mode,
|
||||
nvidia,schmitt, nvidia,low-power-mode, nvidia,pull-down-strength,
|
||||
nvidia,pull-up-strength, nvidia,slew_rate-rising, nvidia,slew_rate-falling.
|
||||
|
||||
drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1, drive_cdev2,
|
||||
drive_csus, drive_dap1, drive_dap2, drive_dap3, drive_dap4, drive_dbg,
|
||||
drive_lcd1, drive_lcd2, drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa,
|
||||
drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2, drive_xm2a,
|
||||
drive_xm2c, drive_xm2d, drive_xm2clk, drive_sdio1, drive_crt, drive_ddc,
|
||||
drive_gma, drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_owr,
|
||||
drive_uda.
|
||||
|
||||
Example:
|
||||
|
||||
pinctrl@70000000 {
|
||||
compatible = "nvidia,tegra20-pinmux";
|
||||
reg = < 0x70000014 0x10 /* Tri-state registers */
|
||||
0x70000080 0x20 /* Mux registers */
|
||||
0x700000a0 0x14 /* Pull-up/down registers */
|
||||
0x70000868 0xa8 >; /* Pad control registers */
|
||||
};
|
||||
|
||||
Example board file extract:
|
||||
|
||||
pinctrl@70000000 {
|
||||
sdio4_default: sdio4_default {
|
||||
atb {
|
||||
nvidia,pins = "atb", "gma", "gme";
|
||||
nvidia,function = "sdio4";
|
||||
nvidia,pull = <0>;
|
||||
nvidia,tristate = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sdhci@c8000600 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdio4_default>;
|
||||
};
|
@ -0,0 +1,132 @@
|
||||
NVIDIA Tegra30 pinmux controller
|
||||
|
||||
The Tegra30 pinctrl binding is very similar to the Tegra20 pinctrl binding,
|
||||
as described in nvidia,tegra20-pinmux.txt. In fact, this document assumes
|
||||
that binding as a baseline, and only documents the differences between the
|
||||
two bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible: "nvidia,tegra30-pinmux"
|
||||
- reg: Should contain the register physical address and length for each of
|
||||
the pad control and mux registers.
|
||||
|
||||
Tegra30 adds the following optional properties for pin configuration subnodes:
|
||||
- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes.
|
||||
- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes.
|
||||
- nvidia,lock: Integer. Lock the pin configuration against further changes
|
||||
until reset. 0: no, 1: yes.
|
||||
- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes.
|
||||
|
||||
As with Tegra20, see the Tegra TRM for complete details regarding which groups
|
||||
support which functionality.
|
||||
|
||||
Valid values for pin and group names are:
|
||||
|
||||
per-pin mux groups:
|
||||
|
||||
These all support nvidia,function, nvidia,tristate, nvidia,pull,
|
||||
nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain,
|
||||
nvidia,io-reset.
|
||||
|
||||
clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2, dap2_sclk_pa3,
|
||||
dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6, sdmmc3_cmd_pa7, gmi_a17_pb0,
|
||||
gmi_a18_pb1, lcd_pwr0_pb2, lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5,
|
||||
sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0, lcd_pwr1_pc1,
|
||||
uart2_txd_pc2, uart2_rxd_pc3, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5,
|
||||
lcd_pwr2_pc6, gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1, lcd_dc1_pd2,
|
||||
sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5, vi_vsync_pd6, vi_hsync_pd7,
|
||||
lcd_d0_pe0, lcd_d1_pe1, lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5,
|
||||
lcd_d6_pe6, lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2, lcd_d11_pf3,
|
||||
lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6, lcd_d15_pf7, gmi_ad0_pg0,
|
||||
gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5,
|
||||
gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2,
|
||||
gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7,
|
||||
gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2, gmi_cs6_n_pi3, gmi_rst_n_pi4,
|
||||
gmi_iordy_pi5, gmi_cs7_n_pi6, gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1,
|
||||
gmi_cs1_n_pj2, lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5,
|
||||
uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs4_n_pk2,
|
||||
gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5, spdif_in_pk6, gmi_a19_pk7,
|
||||
vi_d2_pl0, vi_d3_pl1, vi_d4_pl2, vi_d5_pl3, vi_d6_pl4, vi_d7_pl5,
|
||||
vi_d8_pl6, vi_d9_pl7, lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3,
|
||||
lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7, dap1_fs_pn0,
|
||||
dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, lcd_cs0_n_pn4, lcd_sdout_pn5,
|
||||
lcd_dc0_pn6, hdmi_int_pn7, ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2,
|
||||
ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6,
|
||||
ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3,
|
||||
dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0,
|
||||
kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5,
|
||||
kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2,
|
||||
kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7,
|
||||
kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4,
|
||||
kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1,
|
||||
vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6,
|
||||
sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4, pu5, pu6, jtag_rtck_pu7, pv0,
|
||||
pv1, pv2, pv3, ddc_scl_pv4, ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7,
|
||||
lcd_cs1_n_pw0, lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4,
|
||||
clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0, spi2_miso_px1,
|
||||
spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4, spi1_sck_px5, spi1_cs0_n_px6,
|
||||
spi1_miso_px7, ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3,
|
||||
sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7,
|
||||
sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3, lcd_sck_pz4,
|
||||
sys_clk_req_pz5, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, sdmmc4_dat0_paa0,
|
||||
sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4,
|
||||
sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0,
|
||||
cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7,
|
||||
cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3, sdmmc4_clk_pcc4,
|
||||
clk2_req_pcc5, pex_l2_rst_n_pcc6, pex_l2_clkreq_n_pcc7,
|
||||
pex_l0_prsnt_n_pdd0, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2,
|
||||
pex_wake_n_pdd3, pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5,
|
||||
pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0, clk3_req_pee1,
|
||||
clk1_req_pee2, hdmi_cec_pee3, clk_32k_in, core_pwr_req, cpu_pwr_req, owr,
|
||||
pwr_int_n.
|
||||
|
||||
drive groups:
|
||||
|
||||
These all support nvidia,pull-down-strength, nvidia,pull-up-strength,
|
||||
nvidia,slew_rate-rising, nvidia,slew_rate-falling. Most but not all
|
||||
support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode.
|
||||
|
||||
ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, cec, crt, csus, dap1,
|
||||
dap2, dap3, dap4, dbg, ddc, dev3, gma, gmb, gmc, gmd, gme, gmf, gmg,
|
||||
gmh, gpv, lcd1, lcd2, owr, sdio1, sdio2, sdio3, spi, uaa, uab, uart2,
|
||||
uart3, uda, vi1.
|
||||
|
||||
Example:
|
||||
|
||||
pinctrl@70000000 {
|
||||
compatible = "nvidia,tegra30-pinmux";
|
||||
reg = < 0x70000868 0xd0 /* Pad control registers */
|
||||
0x70003000 0x3e0 >; /* Mux registers */
|
||||
};
|
||||
|
||||
Example board file extract:
|
||||
|
||||
pinctrl@70000000 {
|
||||
sdmmc4_default: pinmux {
|
||||
sdmmc4_clk_pcc4 {
|
||||
nvidia,pins = "sdmmc4_clk_pcc4",
|
||||
"sdmmc4_rst_n_pcc3";
|
||||
nvidia,function = "sdmmc4";
|
||||
nvidia,pull = <0>;
|
||||
nvidia,tristate = <0>;
|
||||
};
|
||||
sdmmc4_dat0_paa0 {
|
||||
nvidia,pins = "sdmmc4_dat0_paa0",
|
||||
"sdmmc4_dat1_paa1",
|
||||
"sdmmc4_dat2_paa2",
|
||||
"sdmmc4_dat3_paa3",
|
||||
"sdmmc4_dat4_paa4",
|
||||
"sdmmc4_dat5_paa5",
|
||||
"sdmmc4_dat6_paa6",
|
||||
"sdmmc4_dat7_paa7";
|
||||
nvidia,function = "sdmmc4";
|
||||
nvidia,pull = <2>;
|
||||
nvidia,tristate = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sdhci@78000400 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdmmc4_default>;
|
||||
};
|
128
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
Normal file
128
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
Normal file
@ -0,0 +1,128 @@
|
||||
== Introduction ==
|
||||
|
||||
Hardware modules that control pin multiplexing or configuration parameters
|
||||
such as pull-up/down, tri-state, drive-strength etc are designated as pin
|
||||
controllers. Each pin controller must be represented as a node in device tree,
|
||||
just like any other hardware module.
|
||||
|
||||
Hardware modules whose signals are affected by pin configuration are
|
||||
designated client devices. Again, each client device must be represented as a
|
||||
node in device tree, just like any other hardware module.
|
||||
|
||||
For a client device to operate correctly, certain pin controllers must
|
||||
set up certain specific pin configurations. Some client devices need a
|
||||
single static pin configuration, e.g. set up during initialization. Others
|
||||
need to reconfigure pins at run-time, for example to tri-state pins when the
|
||||
device is inactive. Hence, each client device can define a set of named
|
||||
states. The number and names of those states is defined by the client device's
|
||||
own binding.
|
||||
|
||||
The common pinctrl bindings defined in this file provide an infrastructure
|
||||
for client device device tree nodes to map those state names to the pin
|
||||
configuration used by those states.
|
||||
|
||||
Note that pin controllers themselves may also be client devices of themselves.
|
||||
For example, a pin controller may set up its own "active" state when the
|
||||
driver loads. This would allow representing a board's static pin configuration
|
||||
in a single place, rather than splitting it across multiple client device
|
||||
nodes. The decision to do this or not somewhat rests with the author of
|
||||
individual board device tree files, and any requirements imposed by the
|
||||
bindings for the individual client devices in use by that board, i.e. whether
|
||||
they require certain specific named states for dynamic pin configuration.
|
||||
|
||||
== Pinctrl client devices ==
|
||||
|
||||
For each client device individually, every pin state is assigned an integer
|
||||
ID. These numbers start at 0, and are contiguous. For each state ID, a unique
|
||||
property exists to define the pin configuration. Each state may also be
|
||||
assigned a name. When names are used, another property exists to map from
|
||||
those names to the integer IDs.
|
||||
|
||||
Each client device's own binding determines the set of states the must be
|
||||
defined in its device tree node, and whether to define the set of state
|
||||
IDs that must be provided, or whether to define the set of state names that
|
||||
must be provided.
|
||||
|
||||
Required properties:
|
||||
pinctrl-0: List of phandles, each pointing at a pin configuration
|
||||
node. These referenced pin configuration nodes must be child
|
||||
nodes of the pin controller that they configure. Multiple
|
||||
entries may exist in this list so that multiple pin
|
||||
controllers may be configured, or so that a state may be built
|
||||
from multiple nodes for a single pin controller, each
|
||||
contributing part of the overall configuration. See the next
|
||||
section of this document for details of the format of these
|
||||
pin configuration nodes.
|
||||
|
||||
In some cases, it may be useful to define a state, but for it
|
||||
to be empty. This may be required when a common IP block is
|
||||
used in an SoC either without a pin controller, or where the
|
||||
pin controller does not affect the HW module in question. If
|
||||
the binding for that IP block requires certain pin states to
|
||||
exist, they must still be defined, but may be left empty.
|
||||
|
||||
Optional properties:
|
||||
pinctrl-1: List of phandles, each pointing at a pin configuration
|
||||
node within a pin controller.
|
||||
...
|
||||
pinctrl-n: List of phandles, each pointing at a pin configuration
|
||||
node within a pin controller.
|
||||
pinctrl-names: The list of names to assign states. List entry 0 defines the
|
||||
name for integer state ID 0, list entry 1 for state ID 1, and
|
||||
so on.
|
||||
|
||||
For example:
|
||||
|
||||
/* For a client device requiring named states */
|
||||
device {
|
||||
pinctrl-names = "active", "idle";
|
||||
pinctrl-0 = <&state_0_node_a>;
|
||||
pinctrl-1 = <&state_1_node_a &state_1_node_b>;
|
||||
};
|
||||
|
||||
/* For the same device if using state IDs */
|
||||
device {
|
||||
pinctrl-0 = <&state_0_node_a>;
|
||||
pinctrl-1 = <&state_1_node_a &state_1_node_b>;
|
||||
};
|
||||
|
||||
/*
|
||||
* For an IP block whose binding supports pin configuration,
|
||||
* but in use on an SoC that doesn't have any pin control hardware
|
||||
*/
|
||||
device {
|
||||
pinctrl-names = "active", "idle";
|
||||
pinctrl-0 = <>;
|
||||
pinctrl-1 = <>;
|
||||
};
|
||||
|
||||
== Pin controller devices ==
|
||||
|
||||
Pin controller devices should contain the pin configuration nodes that client
|
||||
devices reference.
|
||||
|
||||
For example:
|
||||
|
||||
pincontroller {
|
||||
... /* Standard DT properties for the device itself elided */
|
||||
|
||||
state_0_node_a {
|
||||
...
|
||||
};
|
||||
state_1_node_a {
|
||||
...
|
||||
};
|
||||
state_1_node_b {
|
||||
...
|
||||
};
|
||||
}
|
||||
|
||||
The contents of each of those pin configuration child nodes is defined
|
||||
entirely by the binding for the individual pin controller device. There
|
||||
exists no common standard for this content.
|
||||
|
||||
The pin configuration nodes need not be direct children of the pin controller
|
||||
device; they may be grandchildren, for example. Whether this is legal, and
|
||||
whether there is any interaction between the child and intermediate parent
|
||||
nodes, is again defined entirely by the binding for the individual pin
|
||||
controller device.
|
@ -1,5 +0,0 @@
|
||||
NVIDIA Tegra 2 pinmux controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "nvidia,tegra20-pinmux"
|
||||
|
@ -276,3 +276,7 @@ REGULATOR
|
||||
devm_regulator_get()
|
||||
devm_regulator_put()
|
||||
devm_regulator_bulk_get()
|
||||
|
||||
PINCTRL
|
||||
devm_pinctrl_get()
|
||||
devm_pinctrl_put()
|
||||
|
@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = {
|
||||
};
|
||||
|
||||
|
||||
static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int foo_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(foo_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(foo_groups);
|
||||
}
|
||||
|
||||
static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
|
||||
@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
}
|
||||
|
||||
static struct pinctrl_ops foo_pctrl_ops = {
|
||||
.list_groups = foo_list_groups,
|
||||
.get_groups_count = foo_get_groups_count,
|
||||
.get_group_name = foo_get_group_name,
|
||||
.get_group_pins = foo_get_group_pins,
|
||||
};
|
||||
@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = {
|
||||
.pctlops = &foo_pctrl_ops,
|
||||
};
|
||||
|
||||
The pin control subsystem will call the .list_groups() function repeatedly
|
||||
beginning on 0 until it returns non-zero to determine legal selectors, then
|
||||
it will call the other functions to retrieve the name and pins of the group.
|
||||
Maintaining the data structure of the groups is up to the driver, this is
|
||||
just a simple example - in practice you may need more entries in your group
|
||||
structure, for example specific register ranges associated with each group
|
||||
and so on.
|
||||
The pin control subsystem will call the .get_groups_count() function to
|
||||
determine total number of legal selectors, then it will call the other functions
|
||||
to retrieve the name and pins of the group. Maintaining the data structure of
|
||||
the groups is up to the driver, this is just a simple example - in practice you
|
||||
may need more entries in your group structure, for example specific register
|
||||
ranges associated with each group and so on.
|
||||
|
||||
|
||||
Pin configuration
|
||||
@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = {
|
||||
};
|
||||
|
||||
|
||||
static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int foo_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(foo_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(foo_groups);
|
||||
}
|
||||
|
||||
static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
|
||||
@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
}
|
||||
|
||||
static struct pinctrl_ops foo_pctrl_ops = {
|
||||
.list_groups = foo_list_groups,
|
||||
.get_groups_count = foo_get_groups_count,
|
||||
.get_group_name = foo_get_group_name,
|
||||
.get_group_pins = foo_get_group_pins,
|
||||
};
|
||||
@ -640,7 +635,7 @@ struct foo_pmx_func {
|
||||
const unsigned num_groups;
|
||||
};
|
||||
|
||||
static const char * const spi0_groups[] = { "spi0_1_grp" };
|
||||
static const char * const spi0_groups[] = { "spi0_0_grp", "spi0_1_grp" };
|
||||
static const char * const i2c0_groups[] = { "i2c0_grp" };
|
||||
static const char * const mmc0_groups[] = { "mmc0_1_grp", "mmc0_2_grp",
|
||||
"mmc0_3_grp" };
|
||||
@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = {
|
||||
},
|
||||
};
|
||||
|
||||
int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
int foo_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(foo_functions))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(foo_functions);
|
||||
}
|
||||
|
||||
const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
}
|
||||
|
||||
struct pinmux_ops foo_pmxops = {
|
||||
.list_functions = foo_list_funcs,
|
||||
.get_functions_count = foo_get_functions_count,
|
||||
.get_function_name = foo_get_fname,
|
||||
.get_function_groups = foo_get_groups,
|
||||
.enable = foo_enable,
|
||||
@ -786,7 +779,7 @@ and spi on the second function mapping:
|
||||
|
||||
#include <linux/pinctrl/machine.h>
|
||||
|
||||
static const struct pinctrl_map __initdata mapping[] = {
|
||||
static const struct pinctrl_map mapping[] __initconst = {
|
||||
{
|
||||
.dev_name = "foo-spi.0",
|
||||
.name = PINCTRL_STATE_DEFAULT,
|
||||
@ -952,13 +945,13 @@ case), we define a mapping like this:
|
||||
The result of grabbing this mapping from the device with something like
|
||||
this (see next paragraph):
|
||||
|
||||
p = pinctrl_get(dev);
|
||||
p = devm_pinctrl_get(dev);
|
||||
s = pinctrl_lookup_state(p, "8bit");
|
||||
ret = pinctrl_select_state(p, s);
|
||||
|
||||
or more simply:
|
||||
|
||||
p = pinctrl_get_select(dev, "8bit");
|
||||
p = devm_pinctrl_get_select(dev, "8bit");
|
||||
|
||||
Will be that you activate all the three bottom records in the mapping at
|
||||
once. Since they share the same name, pin controller device, function and
|
||||
@ -992,7 +985,7 @@ foo_probe()
|
||||
/* Allocate a state holder named "foo" etc */
|
||||
struct foo_state *foo = ...;
|
||||
|
||||
foo->p = pinctrl_get(&device);
|
||||
foo->p = devm_pinctrl_get(&device);
|
||||
if (IS_ERR(foo->p)) {
|
||||
/* FIXME: clean up "foo" here */
|
||||
return PTR_ERR(foo->p);
|
||||
@ -1000,24 +993,17 @@ foo_probe()
|
||||
|
||||
foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
|
||||
if (IS_ERR(foo->s)) {
|
||||
pinctrl_put(foo->p);
|
||||
/* FIXME: clean up "foo" here */
|
||||
return PTR_ERR(s);
|
||||
}
|
||||
|
||||
ret = pinctrl_select_state(foo->s);
|
||||
if (ret < 0) {
|
||||
pinctrl_put(foo->p);
|
||||
/* FIXME: clean up "foo" here */
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
foo_remove()
|
||||
{
|
||||
pinctrl_put(state->p);
|
||||
}
|
||||
|
||||
This get/lookup/select/put sequence can just as well be handled by bus drivers
|
||||
if you don't want each and every driver to handle it and you know the
|
||||
arrangement on your bus.
|
||||
@ -1029,6 +1015,11 @@ The semantics of the pinctrl APIs are:
|
||||
kernel memory to hold the pinmux state. All mapping table parsing or similar
|
||||
slow operations take place within this API.
|
||||
|
||||
- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put()
|
||||
to be called automatically on the retrieved pointer when the associated
|
||||
device is removed. It is recommended to use this function over plain
|
||||
pinctrl_get().
|
||||
|
||||
- pinctrl_lookup_state() is called in process context to obtain a handle to a
|
||||
specific state for a the client device. This operation may be slow too.
|
||||
|
||||
@ -1041,14 +1032,30 @@ The semantics of the pinctrl APIs are:
|
||||
|
||||
- pinctrl_put() frees all information associated with a pinctrl handle.
|
||||
|
||||
- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to
|
||||
explicitly destroy a pinctrl object returned by devm_pinctrl_get().
|
||||
However, use of this function will be rare, due to the automatic cleanup
|
||||
that will occur even without calling it.
|
||||
|
||||
pinctrl_get() must be paired with a plain pinctrl_put().
|
||||
pinctrl_get() may not be paired with devm_pinctrl_put().
|
||||
devm_pinctrl_get() can optionally be paired with devm_pinctrl_put().
|
||||
devm_pinctrl_get() may not be paired with plain pinctrl_put().
|
||||
|
||||
Usually the pin control core handled the get/put pair and call out to the
|
||||
device drivers bookkeeping operations, like checking available functions and
|
||||
the associated pins, whereas the enable/disable pass on to the pin controller
|
||||
driver which takes care of activating and/or deactivating the mux setting by
|
||||
quickly poking some registers.
|
||||
|
||||
The pins are allocated for your device when you issue the pinctrl_get() call,
|
||||
after this you should be able to see this in the debugfs listing of all pins.
|
||||
The pins are allocated for your device when you issue the devm_pinctrl_get()
|
||||
call, after this you should be able to see this in the debugfs listing of all
|
||||
pins.
|
||||
|
||||
NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
|
||||
requested pinctrl handles, for example if the pinctrl driver has not yet
|
||||
registered. Thus make sure that the error path in your driver gracefully
|
||||
cleans up and is ready to retry the probing later in the startup process.
|
||||
|
||||
|
||||
System pin control hogging
|
||||
@ -1094,13 +1101,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
|
||||
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
foo_switch()
|
||||
{
|
||||
struct pinctrl *p;
|
||||
struct pinctrl_state *s1, *s2;
|
||||
struct pinctrl *p;
|
||||
struct pinctrl_state *s1, *s2;
|
||||
|
||||
foo_probe()
|
||||
{
|
||||
/* Setup */
|
||||
p = pinctrl_get(&device);
|
||||
p = devm_pinctrl_get(&device);
|
||||
if (IS_ERR(p))
|
||||
...
|
||||
|
||||
@ -1111,7 +1118,10 @@ foo_switch()
|
||||
s2 = pinctrl_lookup_state(foo->p, "pos-B");
|
||||
if (IS_ERR(s2))
|
||||
...
|
||||
}
|
||||
|
||||
foo_switch()
|
||||
{
|
||||
/* Enable on position A */
|
||||
ret = pinctrl_select_state(s1);
|
||||
if (ret < 0)
|
||||
@ -1125,8 +1135,6 @@ foo_switch()
|
||||
...
|
||||
|
||||
...
|
||||
|
||||
pinctrl_put(p);
|
||||
}
|
||||
|
||||
The above has to be done from process context.
|
||||
|
@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *np, const char *stem)
|
||||
return id;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_alias_get_id);
|
||||
|
||||
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
||||
u32 *pu)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur) {
|
||||
curv = prop->value;
|
||||
goto out_val;
|
||||
}
|
||||
|
||||
curv += sizeof(*cur);
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
out_val:
|
||||
*pu = be32_to_cpup(curv);
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_u32);
|
||||
|
||||
const char *of_prop_next_string(struct property *prop, const char *cur)
|
||||
{
|
||||
const void *curv = cur;
|
||||
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (!cur)
|
||||
return prop->value;
|
||||
|
||||
curv += strlen(cur) + 1;
|
||||
if (curv >= prop->value + prop->length)
|
||||
return NULL;
|
||||
|
||||
return curv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_prop_next_string);
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
config PINCTRL
|
||||
bool
|
||||
depends on EXPERIMENTAL
|
||||
|
||||
if PINCTRL
|
||||
|
||||
|
@ -5,6 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
|
||||
obj-$(CONFIG_PINCTRL) += core.o
|
||||
obj-$(CONFIG_PINMUX) += pinmux.o
|
||||
obj-$(CONFIG_PINCONF) += pinconf.o
|
||||
ifeq ($(CONFIG_OF),y)
|
||||
obj-$(CONFIG_PINCTRL) += devicetree.o
|
||||
endif
|
||||
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
|
||||
obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
|
||||
obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
|
||||
|
@ -23,9 +23,11 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include "core.h"
|
||||
#include "devicetree.h"
|
||||
#include "pinmux.h"
|
||||
#include "pinconf.h"
|
||||
|
||||
@ -45,7 +47,7 @@ struct pinctrl_maps {
|
||||
DEFINE_MUTEX(pinctrl_mutex);
|
||||
|
||||
/* Global list of pin control devices (struct pinctrl_dev) */
|
||||
static LIST_HEAD(pinctrldev_list);
|
||||
LIST_HEAD(pinctrldev_list);
|
||||
|
||||
/* List of pin controller handles (struct pinctrl) */
|
||||
static LIST_HEAD(pinctrl_list);
|
||||
@ -123,6 +125,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pin_get_name_from_id() - look up a pin name from a pin id
|
||||
* @pctldev: the pin control device to lookup the pin on
|
||||
* @name: the name of the pin to look up
|
||||
*/
|
||||
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
|
||||
{
|
||||
const struct pin_desc *desc;
|
||||
|
||||
desc = pin_desc_get(pctldev, pin);
|
||||
if (desc == NULL) {
|
||||
dev_err(pctldev->dev, "failed to get pin(%d) name\n",
|
||||
pin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return desc->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* pin_is_valid() - check if pin exists on controller
|
||||
* @pctldev: the pin control device to check the pin on
|
||||
@ -318,9 +339,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
|
||||
const char *pin_group)
|
||||
{
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
unsigned ngroups = pctlops->get_groups_count(pctldev);
|
||||
unsigned group_selector = 0;
|
||||
|
||||
while (pctlops->list_groups(pctldev, group_selector) >= 0) {
|
||||
while (group_selector < ngroups) {
|
||||
const char *gname = pctlops->get_group_name(pctldev,
|
||||
group_selector);
|
||||
if (!strcmp(gname, pin_group)) {
|
||||
@ -516,11 +538,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
|
||||
|
||||
setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
|
||||
if (setting->pctldev == NULL) {
|
||||
dev_err(p->dev, "unknown pinctrl device %s in map entry",
|
||||
dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
|
||||
map->ctrl_dev_name);
|
||||
kfree(setting);
|
||||
/* Eventually, this should trigger deferred probe */
|
||||
return -ENODEV;
|
||||
/*
|
||||
* OK let us guess that the driver is not there yet, and
|
||||
* let's defer obtaining this pinctrl handle to later...
|
||||
*/
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
switch (map->type) {
|
||||
@ -579,6 +604,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
|
||||
}
|
||||
p->dev = dev;
|
||||
INIT_LIST_HEAD(&p->states);
|
||||
INIT_LIST_HEAD(&p->dt_maps);
|
||||
|
||||
ret = pinctrl_dt_to_map(p);
|
||||
if (ret < 0) {
|
||||
kfree(p);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
devname = dev_name(dev);
|
||||
|
||||
@ -662,6 +694,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
pinctrl_dt_free_maps(p);
|
||||
|
||||
if (inlist)
|
||||
list_del(&p->node);
|
||||
kfree(p);
|
||||
@ -787,15 +821,63 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pinctrl_select_state);
|
||||
|
||||
static void devm_pinctrl_release(struct device *dev, void *res)
|
||||
{
|
||||
pinctrl_put(*(struct pinctrl **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* pinctrl_register_mappings() - register a set of pin controller mappings
|
||||
* @maps: the pincontrol mappings table to register. This should probably be
|
||||
* marked with __initdata so it can be discarded after boot. This
|
||||
* function will perform a shallow copy for the mapping entries.
|
||||
* @num_maps: the number of maps in the mapping table
|
||||
* struct devm_pinctrl_get() - Resource managed pinctrl_get()
|
||||
* @dev: the device to obtain the handle for
|
||||
*
|
||||
* If there is a need to explicitly destroy the returned struct pinctrl,
|
||||
* devm_pinctrl_put() should be used, rather than plain pinctrl_put().
|
||||
*/
|
||||
int pinctrl_register_mappings(struct pinctrl_map const *maps,
|
||||
unsigned num_maps)
|
||||
struct pinctrl *devm_pinctrl_get(struct device *dev)
|
||||
{
|
||||
struct pinctrl **ptr, *p;
|
||||
|
||||
ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p = pinctrl_get(dev);
|
||||
if (!IS_ERR(p)) {
|
||||
*ptr = p;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pinctrl_get);
|
||||
|
||||
static int devm_pinctrl_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct pinctrl **p = res;
|
||||
|
||||
return *p == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pinctrl_put() - Resource managed pinctrl_put()
|
||||
* @p: the pinctrl handle to release
|
||||
*
|
||||
* Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
|
||||
* this function will not need to be called and the resource management
|
||||
* code will ensure that the resource is freed.
|
||||
*/
|
||||
void devm_pinctrl_put(struct pinctrl *p)
|
||||
{
|
||||
WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
|
||||
devm_pinctrl_match, p));
|
||||
pinctrl_put(p);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
|
||||
|
||||
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
|
||||
bool dup, bool locked)
|
||||
{
|
||||
int i, ret;
|
||||
struct pinctrl_maps *maps_node;
|
||||
@ -851,20 +933,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
|
||||
}
|
||||
|
||||
maps_node->num_maps = num_maps;
|
||||
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
|
||||
if (!maps_node->maps) {
|
||||
pr_err("failed to duplicate mapping table\n");
|
||||
kfree(maps_node);
|
||||
return -ENOMEM;
|
||||
if (dup) {
|
||||
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
|
||||
GFP_KERNEL);
|
||||
if (!maps_node->maps) {
|
||||
pr_err("failed to duplicate mapping table\n");
|
||||
kfree(maps_node);
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
maps_node->maps = maps;
|
||||
}
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
if (!locked)
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
list_add_tail(&maps_node->node, &pinctrl_maps);
|
||||
mutex_unlock(&pinctrl_mutex);
|
||||
if (!locked)
|
||||
mutex_unlock(&pinctrl_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinctrl_register_mappings() - register a set of pin controller mappings
|
||||
* @maps: the pincontrol mappings table to register. This should probably be
|
||||
* marked with __initdata so it can be discarded after boot. This
|
||||
* function will perform a shallow copy for the mapping entries.
|
||||
* @num_maps: the number of maps in the mapping table
|
||||
*/
|
||||
int pinctrl_register_mappings(struct pinctrl_map const *maps,
|
||||
unsigned num_maps)
|
||||
{
|
||||
return pinctrl_register_map(maps, num_maps, true, false);
|
||||
}
|
||||
|
||||
void pinctrl_unregister_map(struct pinctrl_map const *map)
|
||||
{
|
||||
struct pinctrl_maps *maps_node;
|
||||
|
||||
list_for_each_entry(maps_node, &pinctrl_maps, node) {
|
||||
if (maps_node->maps == map) {
|
||||
list_del(&maps_node->node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int pinctrl_pins_show(struct seq_file *s, void *what)
|
||||
@ -906,15 +1020,17 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
unsigned selector = 0;
|
||||
unsigned ngroups, selector = 0;
|
||||
|
||||
ngroups = ops->get_groups_count(pctldev);
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
seq_puts(s, "registered pin groups:\n");
|
||||
while (ops->list_groups(pctldev, selector) >= 0) {
|
||||
while (selector < ngroups) {
|
||||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
const char *gname = ops->get_group_name(pctldev, selector);
|
||||
const char *pname;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@ -924,10 +1040,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
|
||||
seq_printf(s, "%s [ERROR GETTING PINS]\n",
|
||||
gname);
|
||||
else {
|
||||
seq_printf(s, "group: %s, pins = [ ", gname);
|
||||
for (i = 0; i < num_pins; i++)
|
||||
seq_printf(s, "%d ", pins[i]);
|
||||
seq_puts(s, "]\n");
|
||||
seq_printf(s, "group: %s\n", gname);
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
pname = pin_get_name(pctldev, pins[i]);
|
||||
if (WARN_ON(!pname))
|
||||
return -EINVAL;
|
||||
seq_printf(s, "pin %d (%s)\n", pins[i], pname);
|
||||
}
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
selector++;
|
||||
}
|
||||
@ -1226,11 +1346,14 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
|
||||
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
|
||||
if (!ops ||
|
||||
!ops->list_groups ||
|
||||
!ops->get_groups_count ||
|
||||
!ops->get_group_name ||
|
||||
!ops->get_group_pins)
|
||||
return -EINVAL;
|
||||
|
||||
if (ops->dt_node_to_map && !ops->dt_free_map)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,15 @@ struct pinctrl_dev {
|
||||
* @dev: the device using this pin control handle
|
||||
* @states: a list of states for this device
|
||||
* @state: the current state
|
||||
* @dt_maps: the mapping table chunks dynamically parsed from device tree for
|
||||
* this device, if any
|
||||
*/
|
||||
struct pinctrl {
|
||||
struct list_head node;
|
||||
struct device *dev;
|
||||
struct list_head states;
|
||||
struct pinctrl_state *state;
|
||||
struct list_head dt_maps;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
|
||||
* struct pinctrl_setting - an individual mux or config setting
|
||||
* @node: list node for struct pinctrl_settings's @settings field
|
||||
* @type: the type of setting
|
||||
* @pctldev: pin control device handling to be programmed
|
||||
* @pctldev: pin control device handling to be programmed. Not used for
|
||||
* PIN_MAP_TYPE_DUMMY_STATE.
|
||||
* @data: Data specific to the setting type
|
||||
*/
|
||||
struct pinctrl_setting {
|
||||
@ -144,6 +148,7 @@ struct pin_desc {
|
||||
|
||||
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
|
||||
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
|
||||
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
|
||||
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
|
||||
const char *pin_group);
|
||||
|
||||
@ -153,4 +158,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
|
||||
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
|
||||
}
|
||||
|
||||
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
|
||||
bool dup, bool locked);
|
||||
void pinctrl_unregister_map(struct pinctrl_map const *map);
|
||||
|
||||
extern struct mutex pinctrl_mutex;
|
||||
extern struct list_head pinctrldev_list;
|
||||
|
249
drivers/pinctrl/devicetree.c
Normal file
249
drivers/pinctrl/devicetree.c
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Device tree integration for the pin control subsystem
|
||||
*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "devicetree.h"
|
||||
|
||||
/**
|
||||
* struct pinctrl_dt_map - mapping table chunk parsed from device tree
|
||||
* @node: list node for struct pinctrl's @dt_maps field
|
||||
* @pctldev: the pin controller that allocated this struct, and will free it
|
||||
* @maps: the mapping table entries
|
||||
*/
|
||||
struct pinctrl_dt_map {
|
||||
struct list_head node;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_map *map;
|
||||
unsigned num_maps;
|
||||
};
|
||||
|
||||
static void dt_free_map(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
if (pctldev) {
|
||||
struct pinctrl_ops *ops = pctldev->desc->pctlops;
|
||||
ops->dt_free_map(pctldev, map, num_maps);
|
||||
} else {
|
||||
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
|
||||
kfree(map);
|
||||
}
|
||||
}
|
||||
|
||||
void pinctrl_dt_free_maps(struct pinctrl *p)
|
||||
{
|
||||
struct pinctrl_dt_map *dt_map, *n1;
|
||||
|
||||
list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
|
||||
pinctrl_unregister_map(dt_map->map);
|
||||
list_del(&dt_map->node);
|
||||
dt_free_map(dt_map->pctldev, dt_map->map,
|
||||
dt_map->num_maps);
|
||||
kfree(dt_map);
|
||||
}
|
||||
|
||||
of_node_put(p->dev->of_node);
|
||||
}
|
||||
|
||||
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
|
||||
struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
int i;
|
||||
struct pinctrl_dt_map *dt_map;
|
||||
|
||||
/* Initialize common mapping table entry fields */
|
||||
for (i = 0; i < num_maps; i++) {
|
||||
map[i].dev_name = dev_name(p->dev);
|
||||
map[i].name = statename;
|
||||
if (pctldev)
|
||||
map[i].ctrl_dev_name = dev_name(pctldev->dev);
|
||||
}
|
||||
|
||||
/* Remember the converted mapping table entries */
|
||||
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
|
||||
if (!dt_map) {
|
||||
dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
|
||||
dt_free_map(pctldev, map, num_maps);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dt_map->pctldev = pctldev;
|
||||
dt_map->map = map;
|
||||
dt_map->num_maps = num_maps;
|
||||
list_add_tail(&dt_map->node, &p->dt_maps);
|
||||
|
||||
return pinctrl_register_map(map, num_maps, false, true);
|
||||
}
|
||||
|
||||
static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
|
||||
list_for_each_entry(pctldev, &pinctrldev_list, node)
|
||||
if (pctldev->dev->of_node == np)
|
||||
return pctldev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
|
||||
struct device_node *np_config)
|
||||
{
|
||||
struct device_node *np_pctldev;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct pinctrl_ops *ops;
|
||||
int ret;
|
||||
struct pinctrl_map *map;
|
||||
unsigned num_maps;
|
||||
|
||||
/* Find the pin controller containing np_config */
|
||||
np_pctldev = of_node_get(np_config);
|
||||
for (;;) {
|
||||
np_pctldev = of_get_next_parent(np_pctldev);
|
||||
if (!np_pctldev || of_node_is_root(np_pctldev)) {
|
||||
dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
|
||||
np_config->full_name);
|
||||
of_node_put(np_pctldev);
|
||||
/* OK let's just assume this will appear later then */
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
pctldev = find_pinctrl_by_of_node(np_pctldev);
|
||||
if (pctldev)
|
||||
break;
|
||||
}
|
||||
of_node_put(np_pctldev);
|
||||
|
||||
/*
|
||||
* Call pinctrl driver to parse device tree node, and
|
||||
* generate mapping table entries
|
||||
*/
|
||||
ops = pctldev->desc->pctlops;
|
||||
if (!ops->dt_node_to_map) {
|
||||
dev_err(p->dev, "pctldev %s doesn't support DT\n",
|
||||
dev_name(pctldev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Stash the mapping table chunk away for later use */
|
||||
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
|
||||
}
|
||||
|
||||
static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
|
||||
{
|
||||
struct pinctrl_map *map;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map) {
|
||||
dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
|
||||
map->type = PIN_MAP_TYPE_DUMMY_STATE;
|
||||
|
||||
return dt_remember_or_free_map(p, statename, NULL, map, 1);
|
||||
}
|
||||
|
||||
int pinctrl_dt_to_map(struct pinctrl *p)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
int state, ret;
|
||||
char *propname;
|
||||
struct property *prop;
|
||||
const char *statename;
|
||||
const __be32 *list;
|
||||
int size, config;
|
||||
phandle phandle;
|
||||
struct device_node *np_config;
|
||||
|
||||
/* CONFIG_OF enabled, p->dev not instantiated from DT */
|
||||
if (!np) {
|
||||
dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We may store pointers to property names within the node */
|
||||
of_node_get(np);
|
||||
|
||||
/* For each defined state ID */
|
||||
for (state = 0; ; state++) {
|
||||
/* Retrieve the pinctrl-* property */
|
||||
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
|
||||
prop = of_find_property(np, propname, &size);
|
||||
kfree(propname);
|
||||
if (!prop)
|
||||
break;
|
||||
list = prop->value;
|
||||
size /= sizeof(*list);
|
||||
|
||||
/* Determine whether pinctrl-names property names the state */
|
||||
ret = of_property_read_string_index(np, "pinctrl-names",
|
||||
state, &statename);
|
||||
/*
|
||||
* If not, statename is just the integer state ID. But rather
|
||||
* than dynamically allocate it and have to free it later,
|
||||
* just point part way into the property name for the string.
|
||||
*/
|
||||
if (ret < 0) {
|
||||
/* strlen("pinctrl-") == 8 */
|
||||
statename = prop->name + 8;
|
||||
}
|
||||
|
||||
/* For every referenced pin configuration node in it */
|
||||
for (config = 0; config < size; config++) {
|
||||
phandle = be32_to_cpup(list++);
|
||||
|
||||
/* Look up the pin configuration node */
|
||||
np_config = of_find_node_by_phandle(phandle);
|
||||
if (!np_config) {
|
||||
dev_err(p->dev,
|
||||
"prop %s index %i invalid phandle\n",
|
||||
prop->name, config);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Parse the node */
|
||||
ret = dt_to_map_one_config(p, statename, np_config);
|
||||
of_node_put(np_config);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* No entries in DT? Generate a dummy state table entry */
|
||||
if (!size) {
|
||||
ret = dt_remember_dummy_state(p, statename);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pinctrl_dt_free_maps(p);
|
||||
return ret;
|
||||
}
|
35
drivers/pinctrl/devicetree.h
Normal file
35
drivers/pinctrl/devicetree.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Internal interface to pinctrl device tree integration
|
||||
*
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
void pinctrl_dt_free_maps(struct pinctrl *p);
|
||||
int pinctrl_dt_to_map(struct pinctrl *p);
|
||||
|
||||
#else
|
||||
|
||||
static inline int pinctrl_dt_to_map(struct pinctrl *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void pinctrl_dt_free_maps(struct pinctrl *p)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
@ -379,8 +379,16 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
|
||||
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
|
||||
{
|
||||
struct pinctrl_dev *pctldev;
|
||||
const struct pinconf_ops *confops;
|
||||
int i;
|
||||
|
||||
pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
|
||||
if (pctldev)
|
||||
confops = pctldev->desc->confops;
|
||||
else
|
||||
confops = NULL;
|
||||
|
||||
switch (map->type) {
|
||||
case PIN_MAP_TYPE_CONFIGS_PIN:
|
||||
seq_printf(s, "pin ");
|
||||
@ -394,8 +402,15 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map)
|
||||
|
||||
seq_printf(s, "%s\n", map->data.configs.group_or_pin);
|
||||
|
||||
for (i = 0; i < map->data.configs.num_configs; i++)
|
||||
seq_printf(s, "config %08lx\n", map->data.configs.configs[i]);
|
||||
for (i = 0; i < map->data.configs.num_configs; i++) {
|
||||
seq_printf(s, "config ");
|
||||
if (confops && confops->pin_config_config_dbg_show)
|
||||
confops->pin_config_config_dbg_show(pctldev, s,
|
||||
map->data.configs.configs[i]);
|
||||
else
|
||||
seq_printf(s, "%08lx", map->data.configs.configs[i]);
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
@ -403,6 +418,7 @@ void pinconf_show_setting(struct seq_file *s,
|
||||
{
|
||||
struct pinctrl_dev *pctldev = setting->pctldev;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
const struct pinconf_ops *confops = pctldev->desc->confops;
|
||||
struct pin_desc *desc;
|
||||
int i;
|
||||
|
||||
@ -428,8 +444,15 @@ void pinconf_show_setting(struct seq_file *s,
|
||||
* FIXME: We should really get the pin controler to dump the config
|
||||
* values, so they can be decoded to something meaningful.
|
||||
*/
|
||||
for (i = 0; i < setting->data.configs.num_configs; i++)
|
||||
seq_printf(s, " %08lx", setting->data.configs.configs[i]);
|
||||
for (i = 0; i < setting->data.configs.num_configs; i++) {
|
||||
seq_printf(s, " ");
|
||||
if (confops && confops->pin_config_config_dbg_show)
|
||||
confops->pin_config_config_dbg_show(pctldev, s,
|
||||
setting->data.configs.configs[i]);
|
||||
else
|
||||
seq_printf(s, "%08lx",
|
||||
setting->data.configs.configs[i]);
|
||||
}
|
||||
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
@ -448,10 +471,14 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
|
||||
static int pinconf_pins_show(struct seq_file *s, void *what)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinconf_ops *ops = pctldev->desc->confops;
|
||||
unsigned i, pin;
|
||||
|
||||
if (!ops || !ops->pin_config_get)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pin config settings per pin\n");
|
||||
seq_puts(s, "Format: pin (name): pinmux setting array\n");
|
||||
seq_puts(s, "Format: pin (name): configs\n");
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
@ -495,17 +522,18 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
|
||||
const struct pinconf_ops *ops = pctldev->desc->confops;
|
||||
unsigned ngroups = pctlops->get_groups_count(pctldev);
|
||||
unsigned selector = 0;
|
||||
|
||||
if (!ops || !ops->pin_config_group_get)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pin config settings per pin group\n");
|
||||
seq_puts(s, "Format: group (name): pinmux setting array\n");
|
||||
seq_puts(s, "Format: group (name): configs\n");
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
|
||||
while (pctlops->list_groups(pctldev, selector) >= 0) {
|
||||
while (selector < ngroups) {
|
||||
const char *gname = pctlops->get_group_name(pctldev, selector);
|
||||
|
||||
seq_printf(s, "%u (%s):", selector, gname);
|
||||
|
@ -19,11 +19,6 @@ int pinconf_map_to_setting(struct pinctrl_map const *map,
|
||||
struct pinctrl_setting *setting);
|
||||
void pinconf_free_setting(struct pinctrl_setting const *setting);
|
||||
int pinconf_apply_setting(struct pinctrl_setting const *setting);
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinconf_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
/*
|
||||
* You will only be interested in these if you're using PINCONF
|
||||
@ -61,6 +56,18 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
|
||||
|
||||
void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinconf_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinconf_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void pinconf_show_map(struct seq_file *s,
|
||||
struct pinctrl_map const *map)
|
||||
{
|
||||
|
@ -174,7 +174,7 @@ struct u300_gpio_confdata {
|
||||
|
||||
|
||||
/* Initial configuration */
|
||||
static const struct __initdata u300_gpio_confdata
|
||||
static const struct __initconst u300_gpio_confdata
|
||||
bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
@ -255,7 +255,7 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct __initdata u300_gpio_confdata
|
||||
static const struct __initconst u300_gpio_confdata
|
||||
bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
|
@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
|
||||
.pin_base = 0,
|
||||
};
|
||||
|
||||
static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
|
||||
static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
return info->num_grps;
|
||||
}
|
||||
|
||||
static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return NULL;
|
||||
|
||||
return info->grps[selector].name;
|
||||
}
|
||||
|
||||
@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (selector >= info->num_grps)
|
||||
return -EINVAL;
|
||||
|
||||
*pins = info->grps[selector].pins;
|
||||
*num_pins = info->grps[selector].npins;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops pxa3xx_pctrl_ops = {
|
||||
.list_groups = pxa3xx_list_groups,
|
||||
.get_groups_count = pxa3xx_get_groups_count,
|
||||
.get_group_name = pxa3xx_get_group_name,
|
||||
.get_group_pins = pxa3xx_get_group_pins,
|
||||
};
|
||||
|
||||
static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
|
||||
static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
|
||||
{
|
||||
struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
|
||||
if (func >= info->num_funcs)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
return info->num_funcs;
|
||||
}
|
||||
|
||||
static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
|
||||
@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
|
||||
}
|
||||
|
||||
static struct pinmux_ops pxa3xx_pmx_ops = {
|
||||
.list_functions = pxa3xx_pmx_list_func,
|
||||
.get_functions_count = pxa3xx_pmx_get_funcs_count,
|
||||
.get_function_name = pxa3xx_pmx_get_func_name,
|
||||
.get_function_groups = pxa3xx_pmx_get_groups,
|
||||
.enable = pxa3xx_pmx_enable,
|
||||
|
@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
|
||||
SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
|
||||
};
|
||||
|
||||
static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(sirfsoc_pin_groups);
|
||||
}
|
||||
|
||||
static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return NULL;
|
||||
return sirfsoc_pin_groups[selector].name;
|
||||
}
|
||||
|
||||
@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
|
||||
const unsigned **pins,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
|
||||
return -EINVAL;
|
||||
*pins = sirfsoc_pin_groups[selector].pins;
|
||||
*num_pins = sirfsoc_pin_groups[selector].num_pins;
|
||||
return 0;
|
||||
@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
|
||||
}
|
||||
|
||||
static struct pinctrl_ops sirfsoc_pctrl_ops = {
|
||||
.list_groups = sirfsoc_list_groups,
|
||||
.get_groups_count = sirfsoc_get_groups_count,
|
||||
.get_group_name = sirfsoc_get_group_name,
|
||||
.get_group_pins = sirfsoc_get_group_pins,
|
||||
.pin_dbg_show = sirfsoc_pin_dbg_show,
|
||||
@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
|
||||
sirfsoc_pinmux_endisable(spmx, selector, false);
|
||||
}
|
||||
|
||||
static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
|
||||
static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(sirfsoc_pmx_functions);
|
||||
}
|
||||
|
||||
static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
|
||||
@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
|
||||
}
|
||||
|
||||
static struct pinmux_ops sirfsoc_pinmux_ops = {
|
||||
.list_functions = sirfsoc_pinmux_list_funcs,
|
||||
.enable = sirfsoc_pinmux_enable,
|
||||
.disable = sirfsoc_pinmux_disable,
|
||||
.get_functions_count = sirfsoc_pinmux_get_funcs_count,
|
||||
.get_function_name = sirfsoc_pinmux_get_func_name,
|
||||
.get_function_groups = sirfsoc_pinmux_get_groups,
|
||||
.gpio_request_enable = sirfsoc_pinmux_request_gpio,
|
||||
|
@ -23,9 +23,11 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <mach/pinconf-tegra.h>
|
||||
|
||||
@ -53,15 +55,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
|
||||
writel(val, pmx->regs[bank] + reg);
|
||||
}
|
||||
|
||||
static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned group)
|
||||
static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return pmx->soc->ngroups;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
@ -69,9 +67,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->groups[group].name;
|
||||
}
|
||||
|
||||
@ -82,9 +77,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
|
||||
*pins = pmx->soc->groups[group].pins;
|
||||
*num_pins = pmx->soc->groups[group].npins;
|
||||
|
||||
@ -98,22 +90,221 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
||||
seq_printf(s, " " DRIVER_NAME);
|
||||
}
|
||||
|
||||
static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, unsigned reserve)
|
||||
{
|
||||
unsigned old_num = *reserved_maps;
|
||||
unsigned new_num = *num_maps + reserve;
|
||||
struct pinctrl_map *new_map;
|
||||
|
||||
if (old_num >= new_num)
|
||||
return 0;
|
||||
|
||||
new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
|
||||
if (!new_map)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
|
||||
|
||||
*map = new_map;
|
||||
*reserved_maps = new_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, const char *group,
|
||||
const char *function)
|
||||
{
|
||||
if (*num_maps == *reserved_maps)
|
||||
return -ENOSPC;
|
||||
|
||||
(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
|
||||
(*map)[*num_maps].data.mux.group = group;
|
||||
(*map)[*num_maps].data.mux.function = function;
|
||||
(*num_maps)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps,
|
||||
unsigned *num_maps, const char *group,
|
||||
unsigned long *configs, unsigned num_configs)
|
||||
{
|
||||
unsigned long *dup_configs;
|
||||
|
||||
if (*num_maps == *reserved_maps)
|
||||
return -ENOSPC;
|
||||
|
||||
dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
|
||||
GFP_KERNEL);
|
||||
if (!dup_configs)
|
||||
return -ENOMEM;
|
||||
|
||||
(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
|
||||
(*map)[*num_maps].data.configs.group_or_pin = group;
|
||||
(*map)[*num_maps].data.configs.configs = dup_configs;
|
||||
(*map)[*num_maps].data.configs.num_configs = num_configs;
|
||||
(*num_maps)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_config(unsigned long **configs, unsigned *num_configs,
|
||||
unsigned long config)
|
||||
{
|
||||
unsigned old_num = *num_configs;
|
||||
unsigned new_num = old_num + 1;
|
||||
unsigned long *new_configs;
|
||||
|
||||
new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
|
||||
GFP_KERNEL);
|
||||
if (!new_configs)
|
||||
return -ENOMEM;
|
||||
|
||||
new_configs[old_num] = config;
|
||||
|
||||
*configs = new_configs;
|
||||
*num_configs = new_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_maps; i++)
|
||||
if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
|
||||
kfree(map[i].data.configs.configs);
|
||||
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
static const struct cfg_param {
|
||||
const char *property;
|
||||
enum tegra_pinconf_param param;
|
||||
} cfg_params[] = {
|
||||
{"nvidia,pull", TEGRA_PINCONF_PARAM_PULL},
|
||||
{"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE},
|
||||
{"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT},
|
||||
{"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN},
|
||||
{"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK},
|
||||
{"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET},
|
||||
{"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE},
|
||||
{"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT},
|
||||
{"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE},
|
||||
{"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH},
|
||||
{"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH},
|
||||
{"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING},
|
||||
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
|
||||
};
|
||||
|
||||
int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
|
||||
struct pinctrl_map **map,
|
||||
unsigned *reserved_maps,
|
||||
unsigned *num_maps)
|
||||
{
|
||||
int ret, i;
|
||||
const char *function;
|
||||
u32 val;
|
||||
unsigned long config;
|
||||
unsigned long *configs = NULL;
|
||||
unsigned num_configs = 0;
|
||||
unsigned reserve;
|
||||
struct property *prop;
|
||||
const char *group;
|
||||
|
||||
ret = of_property_read_string(np, "nvidia,function", &function);
|
||||
if (ret < 0)
|
||||
function = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
|
||||
ret = of_property_read_u32(np, cfg_params[i].property, &val);
|
||||
if (!ret) {
|
||||
config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
|
||||
ret = add_config(&configs, &num_configs, config);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
reserve = 0;
|
||||
if (function != NULL)
|
||||
reserve++;
|
||||
if (num_configs)
|
||||
reserve++;
|
||||
ret = of_property_count_strings(np, "nvidia,pins");
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
reserve *= ret;
|
||||
|
||||
ret = reserve_map(map, reserved_maps, num_maps, reserve);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
of_property_for_each_string(np, "nvidia,pins", prop, group) {
|
||||
if (function) {
|
||||
ret = add_map_mux(map, reserved_maps, num_maps,
|
||||
group, function);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (num_configs) {
|
||||
ret = add_map_configs(map, reserved_maps, num_maps,
|
||||
group, configs, num_configs);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit:
|
||||
kfree(configs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
struct device_node *np_config,
|
||||
struct pinctrl_map **map, unsigned *num_maps)
|
||||
{
|
||||
unsigned reserved_maps;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
reserved_maps = 0;
|
||||
*map = NULL;
|
||||
*num_maps = 0;
|
||||
|
||||
for_each_child_of_node(np_config, np) {
|
||||
ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps,
|
||||
num_maps);
|
||||
if (ret < 0) {
|
||||
tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pinctrl_ops tegra_pinctrl_ops = {
|
||||
.list_groups = tegra_pinctrl_list_groups,
|
||||
.get_groups_count = tegra_pinctrl_get_groups_count,
|
||||
.get_group_name = tegra_pinctrl_get_group_name,
|
||||
.get_group_pins = tegra_pinctrl_get_group_pins,
|
||||
.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
|
||||
.dt_node_to_map = tegra_pinctrl_dt_node_to_map,
|
||||
.dt_free_map = tegra_pinctrl_dt_free_map,
|
||||
};
|
||||
|
||||
static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
|
||||
unsigned function)
|
||||
static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
return pmx->soc->nfunctions;
|
||||
}
|
||||
|
||||
static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
||||
@ -121,9 +312,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return NULL;
|
||||
|
||||
return pmx->soc->functions[function].name;
|
||||
}
|
||||
|
||||
@ -134,9 +322,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
|
||||
{
|
||||
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
|
||||
if (function >= pmx->soc->nfunctions)
|
||||
return -EINVAL;
|
||||
|
||||
*groups = pmx->soc->functions[function].groups;
|
||||
*num_groups = pmx->soc->functions[function].ngroups;
|
||||
|
||||
@ -151,8 +336,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
@ -180,8 +363,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
||||
const struct tegra_pingroup *g;
|
||||
u32 val;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
if (g->mux_reg < 0)
|
||||
@ -194,7 +375,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
|
||||
}
|
||||
|
||||
static struct pinmux_ops tegra_pinmux_ops = {
|
||||
.list_functions = tegra_pinctrl_list_funcs,
|
||||
.get_functions_count = tegra_pinctrl_get_funcs_count,
|
||||
.get_function_name = tegra_pinctrl_get_func_name,
|
||||
.get_function_groups = tegra_pinctrl_get_func_groups,
|
||||
.enable = tegra_pinctrl_enable,
|
||||
@ -324,8 +505,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
|
||||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
@ -353,8 +532,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
|
||||
s16 reg;
|
||||
u32 val, mask;
|
||||
|
||||
if (group >= pmx->soc->ngroups)
|
||||
return -EINVAL;
|
||||
g = &pmx->soc->groups[group];
|
||||
|
||||
ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
|
||||
|
@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int u300_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(u300_pin_groups);
|
||||
}
|
||||
|
||||
static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return NULL;
|
||||
return u300_pin_groups[selector].name;
|
||||
}
|
||||
|
||||
@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
const unsigned **pins,
|
||||
unsigned *num_pins)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pin_groups))
|
||||
return -EINVAL;
|
||||
*pins = u300_pin_groups[selector].pins;
|
||||
*num_pins = u300_pin_groups[selector].num_pins;
|
||||
return 0;
|
||||
@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
||||
}
|
||||
|
||||
static struct pinctrl_ops u300_pctrl_ops = {
|
||||
.list_groups = u300_list_groups,
|
||||
.get_groups_count = u300_get_groups_count,
|
||||
.get_group_name = u300_get_group_name,
|
||||
.get_group_pins = u300_get_group_pins,
|
||||
.pin_dbg_show = u300_pin_dbg_show,
|
||||
@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
u300_pmx_endisable(upmx, selector, false);
|
||||
}
|
||||
|
||||
static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
|
||||
static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(u300_pmx_functions))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return ARRAY_SIZE(u300_pmx_functions);
|
||||
}
|
||||
|
||||
static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
||||
@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
|
||||
}
|
||||
|
||||
static struct pinmux_ops u300_pmx_ops = {
|
||||
.list_functions = u300_pmx_list_funcs,
|
||||
.get_functions_count = u300_pmx_get_funcs_count,
|
||||
.get_function_name = u300_pmx_get_func_name,
|
||||
.get_function_groups = u300_pmx_get_groups,
|
||||
.enable = u300_pmx_enable,
|
||||
|
@ -33,10 +33,12 @@
|
||||
int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs;
|
||||
unsigned selector = 0;
|
||||
|
||||
/* Check that we implement required operations */
|
||||
if (!ops->list_functions ||
|
||||
if (!ops ||
|
||||
!ops->get_functions_count ||
|
||||
!ops->get_function_name ||
|
||||
!ops->get_function_groups ||
|
||||
!ops->enable ||
|
||||
@ -44,11 +46,12 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check that all functions registered have names */
|
||||
while (ops->list_functions(pctldev, selector) >= 0) {
|
||||
nfuncs = ops->get_functions_count(pctldev);
|
||||
while (selector < nfuncs) {
|
||||
const char *fname = ops->get_function_name(pctldev,
|
||||
selector);
|
||||
if (!fname) {
|
||||
pr_err("pinmux ops has no name for function%u\n",
|
||||
dev_err(pctldev->dev, "pinmux ops has no name for function%u\n",
|
||||
selector);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -85,8 +88,6 @@ static int pin_request(struct pinctrl_dev *pctldev,
|
||||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
int status = -EINVAL;
|
||||
|
||||
dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
|
||||
|
||||
desc = pin_desc_get(pctldev, pin);
|
||||
if (desc == NULL) {
|
||||
dev_err(pctldev->dev,
|
||||
@ -94,6 +95,9 @@ static int pin_request(struct pinctrl_dev *pctldev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
|
||||
pin, desc->name, owner);
|
||||
|
||||
if (gpio_range) {
|
||||
/* There's no need to support multiple GPIO requests */
|
||||
if (desc->gpio_owner) {
|
||||
@ -287,10 +291,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
|
||||
const char *function)
|
||||
{
|
||||
const struct pinmux_ops *ops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs = ops->get_functions_count(pctldev);
|
||||
unsigned selector = 0;
|
||||
|
||||
/* See if this pctldev has this function */
|
||||
while (ops->list_functions(pctldev, selector) >= 0) {
|
||||
while (selector < nfuncs) {
|
||||
const char *fname = ops->get_function_name(pctldev,
|
||||
selector);
|
||||
|
||||
@ -319,6 +324,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
|
||||
const unsigned *pins;
|
||||
unsigned num_pins;
|
||||
|
||||
if (!pmxops) {
|
||||
dev_err(pctldev->dev, "does not support mux function\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
setting->data.mux.func =
|
||||
pinmux_func_name_to_selector(pctldev, map->data.mux.function);
|
||||
if (setting->data.mux.func < 0)
|
||||
@ -477,11 +487,15 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
|
||||
{
|
||||
struct pinctrl_dev *pctldev = s->private;
|
||||
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
|
||||
unsigned nfuncs;
|
||||
unsigned func_selector = 0;
|
||||
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
if (!pmxops)
|
||||
return 0;
|
||||
|
||||
while (pmxops->list_functions(pctldev, func_selector) >= 0) {
|
||||
mutex_lock(&pinctrl_mutex);
|
||||
nfuncs = pmxops->get_functions_count(pctldev);
|
||||
while (func_selector < nfuncs) {
|
||||
const char *func = pmxops->get_function_name(pctldev,
|
||||
func_selector);
|
||||
const char * const *groups;
|
||||
@ -515,6 +529,9 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
|
||||
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
|
||||
unsigned i, pin;
|
||||
|
||||
if (!pmxops)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Pinmux settings per pin\n");
|
||||
seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
|
||||
|
||||
|
@ -31,12 +31,6 @@ void pinmux_free_setting(struct pinctrl_setting const *setting);
|
||||
int pinmux_enable_setting(struct pinctrl_setting const *setting);
|
||||
void pinmux_disable_setting(struct pinctrl_setting const *setting);
|
||||
|
||||
void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinmux_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int pinmux_check_ops(struct pinctrl_dev *pctldev)
|
||||
@ -89,6 +83,18 @@ static inline void pinmux_disable_setting(
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS)
|
||||
|
||||
void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map);
|
||||
void pinmux_show_setting(struct seq_file *s,
|
||||
struct pinctrl_setting const *setting);
|
||||
void pinmux_init_device_debugfs(struct dentry *devroot,
|
||||
struct pinctrl_dev *pctldev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void pinmux_show_map(struct seq_file *s,
|
||||
struct pinctrl_map const *map)
|
||||
{
|
||||
|
@ -259,6 +259,37 @@ extern void of_detach_node(struct device_node *);
|
||||
#endif
|
||||
|
||||
#define of_match_ptr(_ptr) (_ptr)
|
||||
|
||||
/*
|
||||
* struct property *prop;
|
||||
* const __be32 *p;
|
||||
* u32 u;
|
||||
*
|
||||
* of_property_for_each_u32(np, "propname", prop, p, u)
|
||||
* printk("U32 value: %x\n", u);
|
||||
*/
|
||||
const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
|
||||
u32 *pu);
|
||||
#define of_property_for_each_u32(np, propname, prop, p, u) \
|
||||
for (prop = of_find_property(np, propname, NULL), \
|
||||
p = of_prop_next_u32(prop, NULL, &u); \
|
||||
p; \
|
||||
p = of_prop_next_u32(prop, p, &u))
|
||||
|
||||
/*
|
||||
* struct property *prop;
|
||||
* const char *s;
|
||||
*
|
||||
* of_property_for_each_string(np, "propname", prop, s)
|
||||
* printk("String value: %s\n", s);
|
||||
*/
|
||||
const char *of_prop_next_string(struct property *prop, const char *cur);
|
||||
#define of_property_for_each_string(np, propname, prop, s) \
|
||||
for (prop = of_find_property(np, propname, NULL), \
|
||||
s = of_prop_next_string(prop, NULL); \
|
||||
s; \
|
||||
s = of_prop_next_string(prop, s))
|
||||
|
||||
#else /* CONFIG_OF */
|
||||
|
||||
static inline bool of_have_populated_dt(void)
|
||||
@ -349,6 +380,10 @@ static inline int of_machine_is_compatible(const char *compat)
|
||||
|
||||
#define of_match_ptr(_ptr) NULL
|
||||
#define of_match_node(_matches, _node) NULL
|
||||
#define of_property_for_each_u32(np, propname, prop, p, u) \
|
||||
while (0)
|
||||
#define of_property_for_each_string(np, propname, prop, s) \
|
||||
while (0)
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
|
||||
const char *name);
|
||||
extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
|
||||
|
||||
extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
|
||||
extern void devm_pinctrl_put(struct pinctrl *p);
|
||||
|
||||
#else /* !CONFIG_PINCTRL */
|
||||
|
||||
static inline int pinctrl_request_gpio(unsigned gpio)
|
||||
@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void devm_pinctrl_put(struct pinctrl *p)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PINCTRL */
|
||||
|
||||
static inline struct pinctrl * __must_check pinctrl_get_select(
|
||||
@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default(
|
||||
return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
static inline struct pinctrl * __must_check devm_pinctrl_get_select(
|
||||
struct device *dev, const char *name)
|
||||
{
|
||||
struct pinctrl *p;
|
||||
struct pinctrl_state *s;
|
||||
int ret;
|
||||
|
||||
p = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(p))
|
||||
return p;
|
||||
|
||||
s = pinctrl_lookup_state(p, name);
|
||||
if (IS_ERR(s)) {
|
||||
devm_pinctrl_put(p);
|
||||
return ERR_PTR(PTR_ERR(s));
|
||||
}
|
||||
|
||||
ret = pinctrl_select_state(p, s);
|
||||
if (ret < 0) {
|
||||
devm_pinctrl_put(p);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
|
||||
struct device *dev)
|
||||
{
|
||||
return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PINCONF
|
||||
|
||||
extern int pin_config_get(const char *dev_name, const char *name,
|
||||
|
@ -33,6 +33,8 @@ struct seq_file;
|
||||
* per-device info for a certain pin in debugfs
|
||||
* @pin_config_group_dbg_show: optional debugfs display hook that will provide
|
||||
* per-device info for a certain group in debugfs
|
||||
* @pin_config_config_dbg_show: optional debugfs display hook that will decode
|
||||
* and display a driver's pin configuration parameter
|
||||
*/
|
||||
struct pinconf_ops {
|
||||
#ifdef CONFIG_GENERIC_PINCONF
|
||||
@ -56,6 +58,9 @@ struct pinconf_ops {
|
||||
void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s,
|
||||
unsigned selector);
|
||||
void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s,
|
||||
unsigned long config);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
struct device;
|
||||
struct pinctrl_dev;
|
||||
struct pinctrl_map;
|
||||
struct pinmux_ops;
|
||||
struct pinconf_ops;
|
||||
struct gpio_chip;
|
||||
struct device_node;
|
||||
|
||||
/**
|
||||
* struct pinctrl_pin_desc - boards/machines provide information on their
|
||||
@ -64,9 +66,7 @@ struct pinctrl_gpio_range {
|
||||
/**
|
||||
* struct pinctrl_ops - global pin control operations, to be implemented by
|
||||
* pin controller drivers.
|
||||
* @list_groups: list the number of selectable named groups available
|
||||
* in this pinmux driver, the core will begin on 0 and call this
|
||||
* repeatedly as long as it returns >= 0 to enumerate the groups
|
||||
* @get_groups_count: Returns the count of total number of groups registered.
|
||||
* @get_group_name: return the group name of the pin group
|
||||
* @get_group_pins: return an array of pins corresponding to a certain
|
||||
* group selector @pins, and the size of the array in @num_pins
|
||||
@ -74,7 +74,7 @@ struct pinctrl_gpio_range {
|
||||
* info for a certain pin in debugfs
|
||||
*/
|
||||
struct pinctrl_ops {
|
||||
int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector);
|
||||
int (*get_groups_count) (struct pinctrl_dev *pctldev);
|
||||
const char *(*get_group_name) (struct pinctrl_dev *pctldev,
|
||||
unsigned selector);
|
||||
int (*get_group_pins) (struct pinctrl_dev *pctldev,
|
||||
@ -83,6 +83,11 @@ struct pinctrl_ops {
|
||||
unsigned *num_pins);
|
||||
void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
|
||||
unsigned offset);
|
||||
int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
|
||||
struct device_node *np_config,
|
||||
struct pinctrl_map **map, unsigned *num_maps);
|
||||
void (*dt_free_map) (struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -29,9 +29,8 @@ struct pinctrl_dev;
|
||||
* is allowed to answer "no" by returning a negative error code
|
||||
* @free: the reverse function of the request() callback, frees a pin after
|
||||
* being requested
|
||||
* @list_functions: list the number of selectable named functions available
|
||||
* in this pinmux driver, the core will begin on 0 and call this
|
||||
* repeatedly as long as it returns >= 0 to enumerate mux settings
|
||||
* @get_functions_count: returns number of selectable named functions available
|
||||
* in this pinmux driver
|
||||
* @get_function_name: return the function name of the muxing selector,
|
||||
* called by the core to figure out which mux setting it shall map a
|
||||
* certain device to
|
||||
@ -62,7 +61,7 @@ struct pinctrl_dev;
|
||||
struct pinmux_ops {
|
||||
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
|
||||
int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
|
||||
int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector);
|
||||
int (*get_functions_count) (struct pinctrl_dev *pctldev);
|
||||
const char *(*get_function_name) (struct pinctrl_dev *pctldev,
|
||||
unsigned selector);
|
||||
int (*get_function_groups) (struct pinctrl_dev *pctldev,
|
||||
|
Loading…
x
Reference in New Issue
Block a user