Commit 88e0abcd7a8171ca7af3402373e7bd81fe9b6754
1 parent
3ecbf05be1
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mfd: Versatile Express system registers driver
This is a platform driver for Versatile Express' "system register" block. It's a random collection of registers providing the following functionality: - low level platform functions like board ID access; in order to use those, the driver must be initialized early, either statically or based on the DT - config bus bridge via "system control" interface; as the response from the controller does not generate interrupt (yet), the status register is periodically polled using a timer - pseudo GPIO lines providing MMC card status and Flash WP# signal control - LED interface for a set of 8 LEDs on the motherboard, with "heartbeat", "mmc0" and "cpu0" to "cpu5" as default triggers Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Showing 4 changed files with 628 additions and 1 deletions Inline Diff
Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
File was created | 1 | ARM Versatile Express system registers | |
2 | -------------------------------------- | ||
3 | |||
4 | This is a system control registers block, providing multiple low level | ||
5 | platform functions like board detection and identification, software | ||
6 | interrupt generation, MMC and NOR Flash control etc. | ||
7 | |||
8 | Required node properties: | ||
9 | - compatible value : = "arm,vexpress,sysreg"; | ||
10 | - reg : physical base address and the size of the registers window | ||
11 | - gpio-controller : specifies that the node is a GPIO controller | ||
12 | - #gpio-cells : size of the GPIO specifier, should be 2: | ||
13 | - first cell is the pseudo-GPIO line number: | ||
14 | 0 - MMC CARDIN | ||
15 | 1 - MMC WPROT | ||
16 | 2 - NOR FLASH WPn | ||
17 | - second cell can take standard GPIO flags (currently ignored). | ||
18 | |||
19 | Example: | ||
20 | v2m_sysreg: sysreg@10000000 { | ||
21 | compatible = "arm,vexpress-sysreg"; | ||
22 | reg = <0x10000000 0x1000>; | ||
23 | gpio-controller; | ||
24 | #gpio-cells = <2>; | ||
25 | }; | ||
26 | |||
27 | This block also can also act a bridge to the platform's configuration | ||
28 | bus via "system control" interface, addressing devices with site number, | ||
29 | position in the board stack, config controller, function and device | ||
30 | numbers - see motherboard's TRM for more details. | ||
31 | |||
32 | The node describing a config device must refer to the sysreg node via | ||
33 | "arm,vexpress,config-bridge" phandle (can be also defined in the node's | ||
34 | parent) and relies on the board topology properties - see main vexpress | ||
35 | node documentation for more details. It must must also define the | ||
36 | following property: | ||
37 | - arm,vexpress-sysreg,func : must contain two cells: | ||
38 | - first cell defines function number (eg. 1 for clock generator, | ||
39 | 2 for voltage regulators etc.) | ||
40 | - device number (eg. osc 0, osc 1 etc.) | ||
41 | |||
42 | Example: | ||
43 | mcc { | ||
44 | arm,vexpress,config-bridge = <&v2m_sysreg>; | ||
45 | |||
46 | osc@0 { | ||
47 | compatible = "arm,vexpress-osc"; | ||
48 | arm,vexpress-sysreg,func = <1 0>; | ||
49 | }; | ||
50 | }; | ||
51 |
drivers/mfd/Makefile
1 | # | 1 | # |
2 | # Makefile for multifunction miscellaneous devices | 2 | # Makefile for multifunction miscellaneous devices |
3 | # | 3 | # |
4 | 4 | ||
5 | 88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o | 5 | 88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o |
6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o | 6 | obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o |
7 | obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o | 7 | obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o |
8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o | 8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o |
9 | obj-$(CONFIG_MFD_SM501) += sm501.o | 9 | obj-$(CONFIG_MFD_SM501) += sm501.o |
10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
11 | 11 | ||
12 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 12 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
13 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o | 13 | obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o |
14 | obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o | 14 | obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o |
15 | 15 | ||
16 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o | 16 | obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o |
17 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o | 17 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
18 | obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o | 18 | obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o |
19 | 19 | ||
20 | obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o | 20 | obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o |
21 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 21 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
22 | obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o | 22 | obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o |
23 | obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o | 23 | obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o |
24 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o | 24 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o |
25 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | 25 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o |
26 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | 26 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o |
27 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | 27 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o |
28 | 28 | ||
29 | obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o | 29 | obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o |
30 | obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o | 30 | obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o |
31 | obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o | 31 | obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o |
32 | obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o | 32 | obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o |
33 | ifneq ($(CONFIG_MFD_WM5102),n) | 33 | ifneq ($(CONFIG_MFD_WM5102),n) |
34 | obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o | 34 | obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o |
35 | endif | 35 | endif |
36 | ifneq ($(CONFIG_MFD_WM5110),n) | 36 | ifneq ($(CONFIG_MFD_WM5110),n) |
37 | obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o | 37 | obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o |
38 | endif | 38 | endif |
39 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | 39 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
40 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 40 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
41 | wm831x-objs += wm831x-auxadc.o | 41 | wm831x-objs += wm831x-auxadc.o |
42 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 42 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
43 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o | 43 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o |
44 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o | 44 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o |
45 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o | 45 | wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o |
46 | wm8350-objs += wm8350-irq.o | 46 | wm8350-objs += wm8350-irq.o |
47 | obj-$(CONFIG_MFD_WM8350) += wm8350.o | 47 | obj-$(CONFIG_MFD_WM8350) += wm8350.o |
48 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o | 48 | obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o |
49 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o | 49 | obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o |
50 | 50 | ||
51 | obj-$(CONFIG_TPS6105X) += tps6105x.o | 51 | obj-$(CONFIG_TPS6105X) += tps6105x.o |
52 | obj-$(CONFIG_TPS65010) += tps65010.o | 52 | obj-$(CONFIG_TPS65010) += tps65010.o |
53 | obj-$(CONFIG_TPS6507X) += tps6507x.o | 53 | obj-$(CONFIG_TPS6507X) += tps6507x.o |
54 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o | 54 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o |
55 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o | 55 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o |
56 | tps65912-objs := tps65912-core.o tps65912-irq.o | 56 | tps65912-objs := tps65912-core.o tps65912-irq.o |
57 | obj-$(CONFIG_MFD_TPS65912) += tps65912.o | 57 | obj-$(CONFIG_MFD_TPS65912) += tps65912.o |
58 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o | 58 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o |
59 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o | 59 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o |
60 | obj-$(CONFIG_MENELAUS) += menelaus.o | 60 | obj-$(CONFIG_MENELAUS) += menelaus.o |
61 | 61 | ||
62 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o | 62 | obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o |
63 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o | 63 | obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o |
64 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o | 64 | obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o |
65 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o | 65 | obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o |
66 | obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o | 66 | obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o |
67 | 67 | ||
68 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o | 68 | obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o |
69 | obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o | 69 | obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o |
70 | obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o | 70 | obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o |
71 | 71 | ||
72 | obj-$(CONFIG_MFD_CORE) += mfd-core.o | 72 | obj-$(CONFIG_MFD_CORE) += mfd-core.o |
73 | 73 | ||
74 | obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o | 74 | obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o |
75 | 75 | ||
76 | obj-$(CONFIG_MCP) += mcp-core.o | 76 | obj-$(CONFIG_MCP) += mcp-core.o |
77 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o | 77 | obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o |
78 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o | 78 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o |
79 | obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o | 79 | obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o |
80 | obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o | 80 | obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o |
81 | 81 | ||
82 | ifeq ($(CONFIG_SA1100_ASSABET),y) | 82 | ifeq ($(CONFIG_SA1100_ASSABET),y) |
83 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o | 83 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o |
84 | endif | 84 | endif |
85 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | 85 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o |
86 | 86 | ||
87 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 87 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
88 | 88 | ||
89 | obj-$(CONFIG_PMIC_DA9052) += da9052-core.o | 89 | obj-$(CONFIG_PMIC_DA9052) += da9052-core.o |
90 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o | 90 | obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o |
91 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o | 91 | obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o |
92 | 92 | ||
93 | obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o | 93 | obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o |
94 | 94 | ||
95 | da9055-objs := da9055-core.o da9055-i2c.o | 95 | da9055-objs := da9055-core.o da9055-i2c.o |
96 | obj-$(CONFIG_MFD_DA9055) += da9055.o | 96 | obj-$(CONFIG_MFD_DA9055) += da9055.o |
97 | 97 | ||
98 | obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o | 98 | obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o |
99 | obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o | 99 | obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o |
100 | obj-$(CONFIG_MFD_MAX8907) += max8907.o | 100 | obj-$(CONFIG_MFD_MAX8907) += max8907.o |
101 | max8925-objs := max8925-core.o max8925-i2c.o | 101 | max8925-objs := max8925-core.o max8925-i2c.o |
102 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 102 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
103 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o | 103 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o |
104 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o | 104 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o |
105 | 105 | ||
106 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o | 106 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o |
107 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o | 107 | obj-$(CONFIG_MFD_PCF50633) += pcf50633.o |
108 | obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o | 108 | obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o |
109 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o | 109 | obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o |
110 | obj-$(CONFIG_ABX500_CORE) += abx500-core.o | 110 | obj-$(CONFIG_ABX500_CORE) += abx500-core.o |
111 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 111 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
112 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 112 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
113 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | 113 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o |
114 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o | 114 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o |
115 | obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o | 115 | obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o |
116 | # ab8500-core need to come after db8500-prcmu (which provides the channel) | 116 | # ab8500-core need to come after db8500-prcmu (which provides the channel) |
117 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o | 117 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o |
118 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 118 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
119 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 119 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
120 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 120 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
121 | obj-$(CONFIG_LPC_ICH) += lpc_ich.o | 121 | obj-$(CONFIG_LPC_ICH) += lpc_ich.o |
122 | obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o | 122 | obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o |
123 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o | 123 | obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o |
124 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o | 124 | obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o |
125 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | 125 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o |
126 | obj-$(CONFIG_MFD_VX855) += vx855.o | 126 | obj-$(CONFIG_MFD_VX855) += vx855.o |
127 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | 127 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o |
128 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | 128 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o |
129 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o | 129 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o |
130 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o | 130 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o |
131 | obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o | 131 | obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o |
132 | obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o | 132 | obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o |
133 | obj-$(CONFIG_MFD_TPS65090) += tps65090.o | 133 | obj-$(CONFIG_MFD_TPS65090) += tps65090.o |
134 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o | 134 | obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o |
135 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o | 135 | obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o |
136 | obj-$(CONFIG_MFD_PALMAS) += palmas.o | 136 | obj-$(CONFIG_MFD_PALMAS) += palmas.o |
137 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o | 137 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o |
138 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o | 138 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o |
139 | obj-$(CONFIG_MFD_SYSCON) += syscon.o | 139 | obj-$(CONFIG_MFD_SYSCON) += syscon.o |
140 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o | 140 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o |
141 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o | 141 | obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o |
142 | 142 |
drivers/mfd/vexpress-sysreg.c
File was created | 1 | /* | |
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * Copyright (C) 2012 ARM Limited | ||
12 | */ | ||
13 | |||
14 | #include <linux/err.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/leds.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regulator/driver.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/stat.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <linux/vexpress.h> | ||
25 | |||
26 | #define SYS_ID 0x000 | ||
27 | #define SYS_SW 0x004 | ||
28 | #define SYS_LED 0x008 | ||
29 | #define SYS_100HZ 0x024 | ||
30 | #define SYS_FLAGS 0x030 | ||
31 | #define SYS_FLAGSSET 0x030 | ||
32 | #define SYS_FLAGSCLR 0x034 | ||
33 | #define SYS_NVFLAGS 0x038 | ||
34 | #define SYS_NVFLAGSSET 0x038 | ||
35 | #define SYS_NVFLAGSCLR 0x03c | ||
36 | #define SYS_MCI 0x048 | ||
37 | #define SYS_FLASH 0x04c | ||
38 | #define SYS_CFGSW 0x058 | ||
39 | #define SYS_24MHZ 0x05c | ||
40 | #define SYS_MISC 0x060 | ||
41 | #define SYS_DMA 0x064 | ||
42 | #define SYS_PROCID0 0x084 | ||
43 | #define SYS_PROCID1 0x088 | ||
44 | #define SYS_CFGDATA 0x0a0 | ||
45 | #define SYS_CFGCTRL 0x0a4 | ||
46 | #define SYS_CFGSTAT 0x0a8 | ||
47 | |||
48 | #define SYS_HBI_MASK 0xfff | ||
49 | #define SYS_ID_HBI_SHIFT 16 | ||
50 | #define SYS_PROCIDx_HBI_SHIFT 0 | ||
51 | |||
52 | #define SYS_MCI_CARDIN (1 << 0) | ||
53 | #define SYS_MCI_WPROT (1 << 1) | ||
54 | |||
55 | #define SYS_FLASH_WPn (1 << 0) | ||
56 | |||
57 | #define SYS_MISC_MASTERSITE (1 << 14) | ||
58 | |||
59 | #define SYS_CFGCTRL_START (1 << 31) | ||
60 | #define SYS_CFGCTRL_WRITE (1 << 30) | ||
61 | #define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26) | ||
62 | #define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20) | ||
63 | #define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16) | ||
64 | #define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12) | ||
65 | #define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0) | ||
66 | |||
67 | #define SYS_CFGSTAT_ERR (1 << 1) | ||
68 | #define SYS_CFGSTAT_COMPLETE (1 << 0) | ||
69 | |||
70 | |||
71 | static void __iomem *vexpress_sysreg_base; | ||
72 | static struct device *vexpress_sysreg_dev; | ||
73 | static int vexpress_master_site; | ||
74 | |||
75 | |||
76 | void vexpress_flags_set(u32 data) | ||
77 | { | ||
78 | writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR); | ||
79 | writel(data, vexpress_sysreg_base + SYS_FLAGSSET); | ||
80 | } | ||
81 | |||
82 | u32 vexpress_get_procid(int site) | ||
83 | { | ||
84 | if (site == VEXPRESS_SITE_MASTER) | ||
85 | site = vexpress_master_site; | ||
86 | |||
87 | return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ? | ||
88 | SYS_PROCID0 : SYS_PROCID1)); | ||
89 | } | ||
90 | |||
91 | u32 vexpress_get_hbi(int site) | ||
92 | { | ||
93 | u32 id; | ||
94 | |||
95 | switch (site) { | ||
96 | case VEXPRESS_SITE_MB: | ||
97 | id = readl(vexpress_sysreg_base + SYS_ID); | ||
98 | return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK; | ||
99 | case VEXPRESS_SITE_MASTER: | ||
100 | case VEXPRESS_SITE_DB1: | ||
101 | case VEXPRESS_SITE_DB2: | ||
102 | id = vexpress_get_procid(site); | ||
103 | return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; | ||
104 | } | ||
105 | |||
106 | return ~0; | ||
107 | } | ||
108 | |||
109 | void __iomem *vexpress_get_24mhz_clock_base(void) | ||
110 | { | ||
111 | return vexpress_sysreg_base + SYS_24MHZ; | ||
112 | } | ||
113 | |||
114 | |||
115 | static void vexpress_sysreg_find_prop(struct device_node *node, | ||
116 | const char *name, u32 *val) | ||
117 | { | ||
118 | of_node_get(node); | ||
119 | while (node) { | ||
120 | if (of_property_read_u32(node, name, val) == 0) { | ||
121 | of_node_put(node); | ||
122 | return; | ||
123 | } | ||
124 | node = of_get_next_parent(node); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | unsigned __vexpress_get_site(struct device *dev, struct device_node *node) | ||
129 | { | ||
130 | u32 site = 0; | ||
131 | |||
132 | WARN_ON(dev && node && dev->of_node != node); | ||
133 | if (dev && !node) | ||
134 | node = dev->of_node; | ||
135 | |||
136 | if (node) { | ||
137 | vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); | ||
138 | } else if (dev && dev->bus == &platform_bus_type) { | ||
139 | struct platform_device *pdev = to_platform_device(dev); | ||
140 | |||
141 | if (pdev->num_resources == 1 && | ||
142 | pdev->resource[0].flags == IORESOURCE_BUS) | ||
143 | site = pdev->resource[0].start; | ||
144 | } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) { | ||
145 | site = VEXPRESS_SITE_MASTER; | ||
146 | } | ||
147 | |||
148 | if (site == VEXPRESS_SITE_MASTER) | ||
149 | site = vexpress_master_site; | ||
150 | |||
151 | return site; | ||
152 | } | ||
153 | |||
154 | |||
155 | struct vexpress_sysreg_config_func { | ||
156 | u32 template; | ||
157 | u32 device; | ||
158 | }; | ||
159 | |||
160 | static struct vexpress_config_bridge *vexpress_sysreg_config_bridge; | ||
161 | static struct timer_list vexpress_sysreg_config_timer; | ||
162 | static u32 *vexpress_sysreg_config_data; | ||
163 | static int vexpress_sysreg_config_tries; | ||
164 | |||
165 | static void *vexpress_sysreg_config_func_get(struct device *dev, | ||
166 | struct device_node *node) | ||
167 | { | ||
168 | struct vexpress_sysreg_config_func *config_func; | ||
169 | u32 site; | ||
170 | u32 position = 0; | ||
171 | u32 dcc = 0; | ||
172 | u32 func_device[2]; | ||
173 | int err = -EFAULT; | ||
174 | |||
175 | if (node) { | ||
176 | of_node_get(node); | ||
177 | vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); | ||
178 | vexpress_sysreg_find_prop(node, "arm,vexpress,position", | ||
179 | &position); | ||
180 | vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc); | ||
181 | err = of_property_read_u32_array(node, | ||
182 | "arm,vexpress-sysreg,func", func_device, | ||
183 | ARRAY_SIZE(func_device)); | ||
184 | of_node_put(node); | ||
185 | } else if (dev && dev->bus == &platform_bus_type) { | ||
186 | struct platform_device *pdev = to_platform_device(dev); | ||
187 | |||
188 | if (pdev->num_resources == 1 && | ||
189 | pdev->resource[0].flags == IORESOURCE_BUS) { | ||
190 | site = pdev->resource[0].start; | ||
191 | func_device[0] = pdev->resource[0].end; | ||
192 | func_device[1] = pdev->id; | ||
193 | err = 0; | ||
194 | } | ||
195 | } | ||
196 | if (err) | ||
197 | return NULL; | ||
198 | |||
199 | config_func = kzalloc(sizeof(*config_func), GFP_KERNEL); | ||
200 | if (!config_func) | ||
201 | return NULL; | ||
202 | |||
203 | config_func->template = SYS_CFGCTRL_DCC(dcc); | ||
204 | config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]); | ||
205 | config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ? | ||
206 | vexpress_master_site : site); | ||
207 | config_func->template |= SYS_CFGCTRL_POSITION(position); | ||
208 | config_func->device |= func_device[1]; | ||
209 | |||
210 | dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func, | ||
211 | config_func->template, config_func->device); | ||
212 | |||
213 | return config_func; | ||
214 | } | ||
215 | |||
216 | static void vexpress_sysreg_config_func_put(void *func) | ||
217 | { | ||
218 | kfree(func); | ||
219 | } | ||
220 | |||
221 | static int vexpress_sysreg_config_func_exec(void *func, int offset, | ||
222 | bool write, u32 *data) | ||
223 | { | ||
224 | int status; | ||
225 | struct vexpress_sysreg_config_func *config_func = func; | ||
226 | u32 command; | ||
227 | |||
228 | if (WARN_ON(!vexpress_sysreg_base)) | ||
229 | return -ENOENT; | ||
230 | |||
231 | command = readl(vexpress_sysreg_base + SYS_CFGCTRL); | ||
232 | if (WARN_ON(command & SYS_CFGCTRL_START)) | ||
233 | return -EBUSY; | ||
234 | |||
235 | command = SYS_CFGCTRL_START; | ||
236 | command |= write ? SYS_CFGCTRL_WRITE : 0; | ||
237 | command |= config_func->template; | ||
238 | command |= SYS_CFGCTRL_DEVICE(config_func->device + offset); | ||
239 | |||
240 | /* Use a canary for reads */ | ||
241 | if (!write) | ||
242 | *data = 0xdeadbeef; | ||
243 | |||
244 | dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n", | ||
245 | command, *data); | ||
246 | writel(*data, vexpress_sysreg_base + SYS_CFGDATA); | ||
247 | writel(0, vexpress_sysreg_base + SYS_CFGSTAT); | ||
248 | writel(command, vexpress_sysreg_base + SYS_CFGCTRL); | ||
249 | mb(); | ||
250 | |||
251 | if (vexpress_sysreg_dev) { | ||
252 | /* Schedule completion check */ | ||
253 | if (!write) | ||
254 | vexpress_sysreg_config_data = data; | ||
255 | vexpress_sysreg_config_tries = 100; | ||
256 | mod_timer(&vexpress_sysreg_config_timer, | ||
257 | jiffies + usecs_to_jiffies(100)); | ||
258 | status = VEXPRESS_CONFIG_STATUS_WAIT; | ||
259 | } else { | ||
260 | /* Early execution, no timer available, have to spin */ | ||
261 | u32 cfgstat; | ||
262 | |||
263 | do { | ||
264 | cpu_relax(); | ||
265 | cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); | ||
266 | } while (!cfgstat); | ||
267 | |||
268 | if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE)) | ||
269 | *data = readl(vexpress_sysreg_base + SYS_CFGDATA); | ||
270 | status = VEXPRESS_CONFIG_STATUS_DONE; | ||
271 | |||
272 | if (cfgstat & SYS_CFGSTAT_ERR) | ||
273 | status = -EINVAL; | ||
274 | } | ||
275 | |||
276 | return status; | ||
277 | } | ||
278 | |||
279 | struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = { | ||
280 | .name = "vexpress-sysreg", | ||
281 | .func_get = vexpress_sysreg_config_func_get, | ||
282 | .func_put = vexpress_sysreg_config_func_put, | ||
283 | .func_exec = vexpress_sysreg_config_func_exec, | ||
284 | }; | ||
285 | |||
286 | static void vexpress_sysreg_config_complete(unsigned long data) | ||
287 | { | ||
288 | int status = VEXPRESS_CONFIG_STATUS_DONE; | ||
289 | u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); | ||
290 | |||
291 | if (cfgstat & SYS_CFGSTAT_ERR) | ||
292 | status = -EINVAL; | ||
293 | if (!vexpress_sysreg_config_tries--) | ||
294 | status = -ETIMEDOUT; | ||
295 | |||
296 | if (status < 0) { | ||
297 | dev_err(vexpress_sysreg_dev, "error %d\n", status); | ||
298 | } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) { | ||
299 | mod_timer(&vexpress_sysreg_config_timer, | ||
300 | jiffies + usecs_to_jiffies(50)); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | if (vexpress_sysreg_config_data) { | ||
305 | *vexpress_sysreg_config_data = readl(vexpress_sysreg_base + | ||
306 | SYS_CFGDATA); | ||
307 | dev_dbg(vexpress_sysreg_dev, "read data %x\n", | ||
308 | *vexpress_sysreg_config_data); | ||
309 | vexpress_sysreg_config_data = NULL; | ||
310 | } | ||
311 | |||
312 | vexpress_config_complete(vexpress_sysreg_config_bridge, status); | ||
313 | } | ||
314 | |||
315 | |||
316 | void __init vexpress_sysreg_early_init(void __iomem *base) | ||
317 | { | ||
318 | struct device_node *node = of_find_compatible_node(NULL, NULL, | ||
319 | "arm,vexpress-sysreg"); | ||
320 | |||
321 | if (node) | ||
322 | base = of_iomap(node, 0); | ||
323 | |||
324 | if (WARN_ON(!base)) | ||
325 | return; | ||
326 | |||
327 | vexpress_sysreg_base = base; | ||
328 | |||
329 | if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) | ||
330 | vexpress_master_site = VEXPRESS_SITE_DB2; | ||
331 | else | ||
332 | vexpress_master_site = VEXPRESS_SITE_DB1; | ||
333 | |||
334 | vexpress_sysreg_config_bridge = vexpress_config_bridge_register( | ||
335 | node, &vexpress_sysreg_config_bridge_info); | ||
336 | WARN_ON(!vexpress_sysreg_config_bridge); | ||
337 | } | ||
338 | |||
339 | void __init vexpress_sysreg_of_early_init(void) | ||
340 | { | ||
341 | vexpress_sysreg_early_init(NULL); | ||
342 | } | ||
343 | |||
344 | |||
345 | static struct vexpress_sysreg_gpio { | ||
346 | unsigned long reg; | ||
347 | u32 value; | ||
348 | } vexpress_sysreg_gpios[] = { | ||
349 | [VEXPRESS_GPIO_MMC_CARDIN] = { | ||
350 | .reg = SYS_MCI, | ||
351 | .value = SYS_MCI_CARDIN, | ||
352 | }, | ||
353 | [VEXPRESS_GPIO_MMC_WPROT] = { | ||
354 | .reg = SYS_MCI, | ||
355 | .value = SYS_MCI_WPROT, | ||
356 | }, | ||
357 | [VEXPRESS_GPIO_FLASH_WPn] = { | ||
358 | .reg = SYS_FLASH, | ||
359 | .value = SYS_FLASH_WPn, | ||
360 | }, | ||
361 | }; | ||
362 | |||
363 | static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip, | ||
364 | unsigned offset) | ||
365 | { | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip, | ||
370 | unsigned offset, int value) | ||
371 | { | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int vexpress_sysreg_gpio_get(struct gpio_chip *chip, | ||
376 | unsigned offset) | ||
377 | { | ||
378 | struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; | ||
379 | u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); | ||
380 | |||
381 | return !!(reg_value & gpio->value); | ||
382 | } | ||
383 | |||
384 | static void vexpress_sysreg_gpio_set(struct gpio_chip *chip, | ||
385 | unsigned offset, int value) | ||
386 | { | ||
387 | struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; | ||
388 | u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); | ||
389 | |||
390 | if (value) | ||
391 | reg_value |= gpio->value; | ||
392 | else | ||
393 | reg_value &= ~gpio->value; | ||
394 | |||
395 | writel(reg_value, vexpress_sysreg_base + gpio->reg); | ||
396 | } | ||
397 | |||
398 | static struct gpio_chip vexpress_sysreg_gpio_chip = { | ||
399 | .label = "vexpress-sysreg", | ||
400 | .direction_input = vexpress_sysreg_gpio_direction_input, | ||
401 | .direction_output = vexpress_sysreg_gpio_direction_output, | ||
402 | .get = vexpress_sysreg_gpio_get, | ||
403 | .set = vexpress_sysreg_gpio_set, | ||
404 | .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios), | ||
405 | .base = 0, | ||
406 | }; | ||
407 | |||
408 | |||
409 | static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, | ||
410 | struct device_attribute *attr, char *buf) | ||
411 | { | ||
412 | return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID)); | ||
413 | } | ||
414 | |||
415 | DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL); | ||
416 | |||
417 | static int __devinit vexpress_sysreg_probe(struct platform_device *pdev) | ||
418 | { | ||
419 | int err; | ||
420 | struct resource *res = platform_get_resource(pdev, | ||
421 | IORESOURCE_MEM, 0); | ||
422 | |||
423 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
424 | resource_size(res), pdev->name)) { | ||
425 | dev_err(&pdev->dev, "Failed to request memory region!\n"); | ||
426 | return -EBUSY; | ||
427 | } | ||
428 | |||
429 | if (!vexpress_sysreg_base) | ||
430 | vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, | ||
431 | resource_size(res)); | ||
432 | |||
433 | if (!vexpress_sysreg_base) { | ||
434 | dev_err(&pdev->dev, "Failed to obtain base address!\n"); | ||
435 | return -EFAULT; | ||
436 | } | ||
437 | |||
438 | setup_timer(&vexpress_sysreg_config_timer, | ||
439 | vexpress_sysreg_config_complete, 0); | ||
440 | |||
441 | vexpress_sysreg_gpio_chip.dev = &pdev->dev; | ||
442 | err = gpiochip_add(&vexpress_sysreg_gpio_chip); | ||
443 | if (err) { | ||
444 | vexpress_config_bridge_unregister( | ||
445 | vexpress_sysreg_config_bridge); | ||
446 | dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n", | ||
447 | err); | ||
448 | return err; | ||
449 | } | ||
450 | |||
451 | vexpress_sysreg_dev = &pdev->dev; | ||
452 | |||
453 | device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static const struct of_device_id vexpress_sysreg_match[] = { | ||
459 | { .compatible = "arm,vexpress-sysreg", }, | ||
460 | {}, | ||
461 | }; | ||
462 | |||
463 | static struct platform_driver vexpress_sysreg_driver = { | ||
464 | .driver = { | ||
465 | .name = "vexpress-sysreg", | ||
466 | .of_match_table = vexpress_sysreg_match, | ||
467 | }, | ||
468 | .probe = vexpress_sysreg_probe, | ||
469 | }; | ||
470 | |||
471 | static int __init vexpress_sysreg_init(void) | ||
472 | { | ||
473 | return platform_driver_register(&vexpress_sysreg_driver); | ||
474 | } | ||
475 | core_initcall(vexpress_sysreg_init); | ||
476 | |||
477 | |||
478 | #if defined(CONFIG_LEDS_CLASS) | ||
479 | |||
480 | struct vexpress_sysreg_led { | ||
481 | u32 mask; | ||
482 | struct led_classdev cdev; | ||
483 | } vexpress_sysreg_leds[] = { | ||
484 | { .mask = 1 << 0, .cdev.name = "v2m:green:user1", | ||
485 | .cdev.default_trigger = "heartbeat", }, | ||
486 | { .mask = 1 << 1, .cdev.name = "v2m:green:user2", | ||
487 | .cdev.default_trigger = "mmc0", }, | ||
488 | { .mask = 1 << 2, .cdev.name = "v2m:green:user3", | ||
489 | .cdev.default_trigger = "cpu0", }, | ||
490 | { .mask = 1 << 3, .cdev.name = "v2m:green:user4", | ||
491 | .cdev.default_trigger = "cpu1", }, | ||
492 | { .mask = 1 << 4, .cdev.name = "v2m:green:user5", | ||
493 | .cdev.default_trigger = "cpu2", }, | ||
494 | { .mask = 1 << 5, .cdev.name = "v2m:green:user6", | ||
495 | .cdev.default_trigger = "cpu3", }, | ||
496 | { .mask = 1 << 6, .cdev.name = "v2m:green:user7", | ||
497 | .cdev.default_trigger = "cpu4", }, | ||
498 | { .mask = 1 << 7, .cdev.name = "v2m:green:user8", | ||
499 | .cdev.default_trigger = "cpu5", }, | ||
500 | }; | ||
501 | |||
502 | static DEFINE_SPINLOCK(vexpress_sysreg_leds_lock); | ||
503 | |||
504 | static void vexpress_sysreg_led_brightness_set(struct led_classdev *cdev, | ||
505 | enum led_brightness brightness) | ||
506 | { | ||
507 | struct vexpress_sysreg_led *led = container_of(cdev, | ||
508 | struct vexpress_sysreg_led, cdev); | ||
509 | unsigned long flags; | ||
510 | u32 val; | ||
511 | |||
512 | spin_lock_irqsave(&vexpress_sysreg_leds_lock, flags); | ||
513 | |||
514 | val = readl(vexpress_sysreg_base + SYS_LED); | ||
515 | if (brightness == LED_OFF) | ||
516 | val &= ~led->mask; | ||
517 | else | ||
518 | val |= led->mask; | ||
519 | writel(val, vexpress_sysreg_base + SYS_LED); | ||
520 | |||
521 | spin_unlock_irqrestore(&vexpress_sysreg_leds_lock, flags); | ||
522 | } | ||
523 | |||
524 | static int __init vexpress_sysreg_init_leds(void) | ||
525 | { | ||
526 | struct vexpress_sysreg_led *led; | ||
527 | int i; | ||
528 | |||
529 | /* Clear all user LEDs */ | ||
530 | writel(0, vexpress_sysreg_base + SYS_LED); | ||
531 | |||
532 | for (i = 0, led = vexpress_sysreg_leds; | ||
533 | i < ARRAY_SIZE(vexpress_sysreg_leds); i++, led++) { | ||
534 | int err; | ||
535 | |||
536 | led->cdev.brightness_set = vexpress_sysreg_led_brightness_set; | ||
537 | err = led_classdev_register(vexpress_sysreg_dev, &led->cdev); | ||
538 | if (err) { | ||
539 | dev_err(vexpress_sysreg_dev, | ||
540 | "Failed to register LED %d! (%d)\n", | ||
541 | i, err); | ||
542 | while (led--, i--) | ||
543 | led_classdev_unregister(&led->cdev); | ||
544 | return err; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | device_initcall(vexpress_sysreg_init_leds); | ||
551 | |||
552 | #endif | ||
553 |
include/linux/vexpress.h
1 | /* | 1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | 2 | * This program is free software; you can redistribute it and/or modify |
3 | * it under the terms of the GNU General Public License version 2 as | 3 | * it under the terms of the GNU General Public License version 2 as |
4 | * published by the Free Software Foundation. | 4 | * published by the Free Software Foundation. |
5 | * | 5 | * |
6 | * This program is distributed in the hope that it will be useful, | 6 | * This program is distributed in the hope that it will be useful, |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
9 | * GNU General Public License for more details. | 9 | * GNU General Public License for more details. |
10 | * | 10 | * |
11 | * Copyright (C) 2012 ARM Limited | 11 | * Copyright (C) 2012 ARM Limited |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #ifndef _LINUX_VEXPRESS_H | 14 | #ifndef _LINUX_VEXPRESS_H |
15 | #define _LINUX_VEXPRESS_H | 15 | #define _LINUX_VEXPRESS_H |
16 | 16 | ||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | 18 | ||
19 | #define VEXPRESS_SITE_MB 0 | 19 | #define VEXPRESS_SITE_MB 0 |
20 | #define VEXPRESS_SITE_DB1 1 | 20 | #define VEXPRESS_SITE_DB1 1 |
21 | #define VEXPRESS_SITE_DB2 2 | 21 | #define VEXPRESS_SITE_DB2 2 |
22 | #define VEXPRESS_SITE_MASTER 0xf | 22 | #define VEXPRESS_SITE_MASTER 0xf |
23 | 23 | ||
24 | #define VEXPRESS_CONFIG_STATUS_DONE 0 | 24 | #define VEXPRESS_CONFIG_STATUS_DONE 0 |
25 | #define VEXPRESS_CONFIG_STATUS_WAIT 1 | 25 | #define VEXPRESS_CONFIG_STATUS_WAIT 1 |
26 | 26 | ||
27 | #define VEXPRESS_GPIO_MMC_CARDIN 0 | ||
28 | #define VEXPRESS_GPIO_MMC_WPROT 1 | ||
29 | #define VEXPRESS_GPIO_FLASH_WPn 2 | ||
30 | |||
31 | #define VEXPRESS_RES_FUNC(_site, _func) \ | ||
32 | { \ | ||
33 | .start = (_site), \ | ||
34 | .end = (_func), \ | ||
35 | .flags = IORESOURCE_BUS, \ | ||
36 | } | ||
37 | |||
27 | /* Config bridge API */ | 38 | /* Config bridge API */ |
28 | 39 | ||
29 | /** | 40 | /** |
30 | * struct vexpress_config_bridge_info - description of the platform | 41 | * struct vexpress_config_bridge_info - description of the platform |
31 | * configuration infrastructure bridge. | 42 | * configuration infrastructure bridge. |
32 | * | 43 | * |
33 | * @name: Bridge name | 44 | * @name: Bridge name |
34 | * | 45 | * |
35 | * @func_get: Obtains pointer to a configuration function for a given | 46 | * @func_get: Obtains pointer to a configuration function for a given |
36 | * device or a Device Tree node, to be used with @func_put | 47 | * device or a Device Tree node, to be used with @func_put |
37 | * and @func_exec. The node pointer should take precedence | 48 | * and @func_exec. The node pointer should take precedence |
38 | * over device pointer when both are passed. | 49 | * over device pointer when both are passed. |
39 | * | 50 | * |
40 | * @func_put: Tells the bridge that the function will not be used any | 51 | * @func_put: Tells the bridge that the function will not be used any |
41 | * more, so all allocated resources can be released. | 52 | * more, so all allocated resources can be released. |
42 | * | 53 | * |
43 | * @func_exec: Executes a configuration function read or write operation. | 54 | * @func_exec: Executes a configuration function read or write operation. |
44 | * The offset selects a 32 bit word of the value accessed. | 55 | * The offset selects a 32 bit word of the value accessed. |
45 | * Must return VEXPRESS_CONFIG_STATUS_DONE when operation | 56 | * Must return VEXPRESS_CONFIG_STATUS_DONE when operation |
46 | * is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when | 57 | * is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when |
47 | * will be completed in some time or negative value in case | 58 | * will be completed in some time or negative value in case |
48 | * of error. | 59 | * of error. |
49 | */ | 60 | */ |
50 | struct vexpress_config_bridge_info { | 61 | struct vexpress_config_bridge_info { |
51 | const char *name; | 62 | const char *name; |
52 | void *(*func_get)(struct device *dev, struct device_node *node); | 63 | void *(*func_get)(struct device *dev, struct device_node *node); |
53 | void (*func_put)(void *func); | 64 | void (*func_put)(void *func); |
54 | int (*func_exec)(void *func, int offset, bool write, u32 *data); | 65 | int (*func_exec)(void *func, int offset, bool write, u32 *data); |
55 | }; | 66 | }; |
56 | 67 | ||
57 | struct vexpress_config_bridge; | 68 | struct vexpress_config_bridge; |
58 | 69 | ||
59 | struct vexpress_config_bridge *vexpress_config_bridge_register( | 70 | struct vexpress_config_bridge *vexpress_config_bridge_register( |
60 | struct device_node *node, | 71 | struct device_node *node, |
61 | struct vexpress_config_bridge_info *info); | 72 | struct vexpress_config_bridge_info *info); |
62 | void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge); | 73 | void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge); |
63 | 74 | ||
64 | void vexpress_config_complete(struct vexpress_config_bridge *bridge, | 75 | void vexpress_config_complete(struct vexpress_config_bridge *bridge, |
65 | int status); | 76 | int status); |
66 | 77 | ||
67 | /* Config function API */ | 78 | /* Config function API */ |
68 | 79 | ||
69 | struct vexpress_config_func; | 80 | struct vexpress_config_func; |
70 | 81 | ||
71 | struct vexpress_config_func *__vexpress_config_func_get(struct device *dev, | 82 | struct vexpress_config_func *__vexpress_config_func_get(struct device *dev, |
72 | struct device_node *node); | 83 | struct device_node *node); |
73 | #define vexpress_config_func_get_by_dev(dev) \ | 84 | #define vexpress_config_func_get_by_dev(dev) \ |
74 | __vexpress_config_func_get(dev, NULL) | 85 | __vexpress_config_func_get(dev, NULL) |
75 | #define vexpress_config_func_get_by_node(node) \ | 86 | #define vexpress_config_func_get_by_node(node) \ |
76 | __vexpress_config_func_get(NULL, node) | 87 | __vexpress_config_func_get(NULL, node) |
77 | void vexpress_config_func_put(struct vexpress_config_func *func); | 88 | void vexpress_config_func_put(struct vexpress_config_func *func); |
78 | 89 | ||
79 | /* Both may sleep! */ | 90 | /* Both may sleep! */ |
80 | int vexpress_config_read(struct vexpress_config_func *func, int offset, | 91 | int vexpress_config_read(struct vexpress_config_func *func, int offset, |
81 | u32 *data); | 92 | u32 *data); |
82 | int vexpress_config_write(struct vexpress_config_func *func, int offset, | 93 | int vexpress_config_write(struct vexpress_config_func *func, int offset, |
83 | u32 data); | 94 | u32 data); |
95 | |||
96 | /* Platform control */ | ||
97 | |||
98 | u32 vexpress_get_procid(int site); | ||
99 | u32 vexpress_get_hbi(int site); | ||
100 | void *vexpress_get_24mhz_clock_base(void); | ||
101 | void vexpress_flags_set(u32 data); | ||
102 | |||
103 | #define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node) | ||
104 | #define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL) | ||
105 | unsigned __vexpress_get_site(struct device *dev, struct device_node *node); | ||
106 | |||
107 | void vexpress_sysreg_early_init(void __iomem *base); | ||
108 | void vexpress_sysreg_of_early_init(void); | ||
84 | 109 | ||
85 | #endif | 110 | #endif |
86 | 111 |