diff options
| author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-03 05:31:54 -0500 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-03 05:31:58 -0500 |
| commit | cde9efef401563943d5a58eb9b7274bfdc08ca9b (patch) | |
| tree | 858a436055612db6282dc63db0fe3ba41147056a | |
| parent | 50401d77ee4904673042dd737eed436067cc23f5 (diff) | |
| parent | 60ebe1568fd15b7ffa101acc645069e27d546ed6 (diff) | |
Merge branch 'ux500-core' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson into devel-stable
55 files changed, 3387 insertions, 1629 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d571cdb79d81..4d1c3093a133 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -798,6 +798,7 @@ config ARCH_U8500 | |||
| 798 | select GENERIC_CLOCKEVENTS | 798 | select GENERIC_CLOCKEVENTS |
| 799 | select COMMON_CLKDEV | 799 | select COMMON_CLKDEV |
| 800 | select ARCH_REQUIRE_GPIOLIB | 800 | select ARCH_REQUIRE_GPIOLIB |
| 801 | select ARCH_HAS_CPUFREQ | ||
| 801 | help | 802 | help |
| 802 | Support for ST-Ericsson's Ux500 architecture | 803 | Support for ST-Ericsson's Ux500 architecture |
| 803 | 804 | ||
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 9e27a84433cb..12052e8e064c 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile | |||
| @@ -2,14 +2,16 @@ | |||
| 2 | # Makefile for the linux kernel, U8500 machine. | 2 | # Makefile for the linux kernel, U8500 machine. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := clock.o cpu.o devices.o | 5 | obj-y := clock.o cpu.o devices.o devices-common.o |
| 6 | obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o | 6 | obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o |
| 7 | obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o | 7 | obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o |
| 8 | obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o | 8 | obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o \ |
| 9 | obj-$(CONFIG_MACH_U5500) += board-u5500.o | 9 | board-mop500-keypads.o |
| 10 | obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o | ||
| 10 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 11 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
| 11 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 12 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
| 12 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o | 13 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o |
| 13 | obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o | 14 | obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o |
| 14 | obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o | 15 | obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o |
| 15 | obj-$(CONFIG_U5500_MBOX) += mbox.o | 16 | obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o |
| 17 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
diff --git a/arch/arm/mach-ux500/board-mop500-keypads.c b/arch/arm/mach-ux500/board-mop500-keypads.c new file mode 100644 index 000000000000..70318c354d32 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-keypads.c | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License v2 | ||
| 5 | * | ||
| 6 | * Keypad layouts for various boards | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/i2c.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/mfd/stmpe.h> | ||
| 14 | #include <linux/mfd/tc3589x.h> | ||
| 15 | #include <linux/input/matrix_keypad.h> | ||
| 16 | |||
| 17 | #include <plat/pincfg.h> | ||
| 18 | #include <plat/ske.h> | ||
| 19 | |||
| 20 | #include <mach/devices.h> | ||
| 21 | #include <mach/hardware.h> | ||
| 22 | |||
| 23 | #include "devices-db8500.h" | ||
| 24 | #include "board-mop500.h" | ||
| 25 | |||
| 26 | /* STMPE/SKE keypad use this key layout */ | ||
| 27 | static const unsigned int mop500_keymap[] = { | ||
| 28 | KEY(2, 5, KEY_END), | ||
| 29 | KEY(4, 1, KEY_POWER), | ||
| 30 | KEY(3, 5, KEY_VOLUMEDOWN), | ||
| 31 | KEY(1, 3, KEY_3), | ||
| 32 | KEY(5, 2, KEY_RIGHT), | ||
| 33 | KEY(5, 0, KEY_9), | ||
| 34 | |||
| 35 | KEY(0, 5, KEY_MENU), | ||
| 36 | KEY(7, 6, KEY_ENTER), | ||
| 37 | KEY(4, 5, KEY_0), | ||
| 38 | KEY(6, 7, KEY_2), | ||
| 39 | KEY(3, 4, KEY_UP), | ||
| 40 | KEY(3, 3, KEY_DOWN), | ||
| 41 | |||
| 42 | KEY(6, 4, KEY_SEND), | ||
| 43 | KEY(6, 2, KEY_BACK), | ||
| 44 | KEY(4, 2, KEY_VOLUMEUP), | ||
| 45 | KEY(5, 5, KEY_1), | ||
| 46 | KEY(4, 3, KEY_LEFT), | ||
| 47 | KEY(3, 2, KEY_7), | ||
| 48 | }; | ||
| 49 | |||
| 50 | static const struct matrix_keymap_data mop500_keymap_data = { | ||
| 51 | .keymap = mop500_keymap, | ||
| 52 | .keymap_size = ARRAY_SIZE(mop500_keymap), | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Nomadik SKE keypad | ||
| 57 | */ | ||
| 58 | #define ROW_PIN_I0 164 | ||
| 59 | #define ROW_PIN_I1 163 | ||
| 60 | #define ROW_PIN_I2 162 | ||
| 61 | #define ROW_PIN_I3 161 | ||
| 62 | #define ROW_PIN_I4 156 | ||
| 63 | #define ROW_PIN_I5 155 | ||
| 64 | #define ROW_PIN_I6 154 | ||
| 65 | #define ROW_PIN_I7 153 | ||
| 66 | #define COL_PIN_O0 168 | ||
| 67 | #define COL_PIN_O1 167 | ||
| 68 | #define COL_PIN_O2 166 | ||
| 69 | #define COL_PIN_O3 165 | ||
| 70 | #define COL_PIN_O4 160 | ||
| 71 | #define COL_PIN_O5 159 | ||
| 72 | #define COL_PIN_O6 158 | ||
| 73 | #define COL_PIN_O7 157 | ||
| 74 | |||
| 75 | #define SKE_KPD_MAX_ROWS 8 | ||
| 76 | #define SKE_KPD_MAX_COLS 8 | ||
| 77 | |||
| 78 | static int ske_kp_rows[] = { | ||
| 79 | ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3, | ||
| 80 | ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7, | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * ske_set_gpio_row: request and set gpio rows | ||
| 85 | */ | ||
| 86 | static int ske_set_gpio_row(int gpio) | ||
| 87 | { | ||
| 88 | int ret; | ||
| 89 | |||
| 90 | ret = gpio_request(gpio, "ske-kp"); | ||
| 91 | if (ret < 0) { | ||
| 92 | pr_err("ske_set_gpio_row: gpio request failed\n"); | ||
| 93 | return ret; | ||
| 94 | } | ||
| 95 | |||
| 96 | ret = gpio_direction_output(gpio, 1); | ||
| 97 | if (ret < 0) { | ||
| 98 | pr_err("ske_set_gpio_row: gpio direction failed\n"); | ||
| 99 | gpio_free(gpio); | ||
| 100 | } | ||
| 101 | |||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * ske_kp_init - enable the gpio configuration | ||
| 107 | */ | ||
| 108 | static int ske_kp_init(void) | ||
| 109 | { | ||
| 110 | int ret, i; | ||
| 111 | |||
| 112 | for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { | ||
| 113 | ret = ske_set_gpio_row(ske_kp_rows[i]); | ||
| 114 | if (ret < 0) { | ||
| 115 | pr_err("ske_kp_init: failed init\n"); | ||
| 116 | return ret; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static struct ske_keypad_platform_data ske_keypad_board = { | ||
| 124 | .init = ske_kp_init, | ||
| 125 | .keymap_data = &mop500_keymap_data, | ||
| 126 | .no_autorepeat = true, | ||
| 127 | .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */ | ||
| 128 | .kcol = SKE_KPD_MAX_COLS, | ||
| 129 | .debounce_ms = 40, /* in millisecs */ | ||
| 130 | }; | ||
| 131 | |||
| 132 | /* | ||
| 133 | * STMPE1601 | ||
| 134 | */ | ||
| 135 | static struct stmpe_keypad_platform_data stmpe1601_keypad_data = { | ||
| 136 | .debounce_ms = 64, | ||
| 137 | .scan_count = 8, | ||
| 138 | .no_autorepeat = true, | ||
| 139 | .keymap_data = &mop500_keymap_data, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static struct stmpe_platform_data stmpe1601_data = { | ||
| 143 | .id = 1, | ||
| 144 | .blocks = STMPE_BLOCK_KEYPAD, | ||
| 145 | .irq_trigger = IRQF_TRIGGER_FALLING, | ||
| 146 | .irq_base = MOP500_STMPE1601_IRQ(0), | ||
| 147 | .keypad = &stmpe1601_keypad_data, | ||
| 148 | .autosleep = true, | ||
| 149 | .autosleep_timeout = 1024, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static struct i2c_board_info mop500_i2c0_devices_stuib[] = { | ||
| 153 | { | ||
| 154 | I2C_BOARD_INFO("stmpe1601", 0x40), | ||
| 155 | .irq = NOMADIK_GPIO_TO_IRQ(218), | ||
| 156 | .platform_data = &stmpe1601_data, | ||
| 157 | .flags = I2C_CLIENT_WAKE, | ||
| 158 | }, | ||
| 159 | }; | ||
| 160 | |||
| 161 | /* | ||
| 162 | * TC35893 | ||
| 163 | */ | ||
| 164 | |||
| 165 | static const unsigned int uib_keymap[] = { | ||
| 166 | KEY(3, 1, KEY_END), | ||
| 167 | KEY(4, 1, KEY_POWER), | ||
| 168 | KEY(6, 4, KEY_VOLUMEDOWN), | ||
| 169 | KEY(4, 2, KEY_EMAIL), | ||
| 170 | KEY(3, 3, KEY_RIGHT), | ||
| 171 | KEY(2, 5, KEY_BACKSPACE), | ||
| 172 | |||
| 173 | KEY(6, 7, KEY_MENU), | ||
| 174 | KEY(5, 0, KEY_ENTER), | ||
| 175 | KEY(4, 3, KEY_0), | ||
| 176 | KEY(3, 4, KEY_DOT), | ||
| 177 | KEY(5, 2, KEY_UP), | ||
| 178 | KEY(3, 5, KEY_DOWN), | ||
| 179 | |||
| 180 | KEY(4, 5, KEY_SEND), | ||
| 181 | KEY(0, 5, KEY_BACK), | ||
| 182 | KEY(6, 2, KEY_VOLUMEUP), | ||
| 183 | KEY(1, 3, KEY_SPACE), | ||
| 184 | KEY(7, 6, KEY_LEFT), | ||
| 185 | KEY(5, 5, KEY_SEARCH), | ||
| 186 | }; | ||
| 187 | |||
| 188 | static struct matrix_keymap_data uib_keymap_data = { | ||
| 189 | .keymap = uib_keymap, | ||
| 190 | .keymap_size = ARRAY_SIZE(uib_keymap), | ||
| 191 | }; | ||
| 192 | |||
| 193 | static struct tc3589x_keypad_platform_data tc35893_data = { | ||
| 194 | .krow = TC_KPD_ROWS, | ||
| 195 | .kcol = TC_KPD_COLUMNS, | ||
| 196 | .debounce_period = TC_KPD_DEBOUNCE_PERIOD, | ||
| 197 | .settle_time = TC_KPD_SETTLE_TIME, | ||
| 198 | .irqtype = IRQF_TRIGGER_FALLING, | ||
| 199 | .enable_wakeup = true, | ||
| 200 | .keymap_data = &uib_keymap_data, | ||
| 201 | .no_autorepeat = true, | ||
| 202 | }; | ||
| 203 | |||
| 204 | static struct tc3589x_platform_data tc3589x_keypad_data = { | ||
| 205 | .block = TC3589x_BLOCK_KEYPAD, | ||
| 206 | .keypad = &tc35893_data, | ||
| 207 | .irq_base = MOP500_EGPIO_IRQ_BASE, | ||
| 208 | }; | ||
| 209 | |||
| 210 | static struct i2c_board_info mop500_i2c0_devices_uib[] = { | ||
| 211 | { | ||
| 212 | I2C_BOARD_INFO("tc3589x", 0x44), | ||
| 213 | .platform_data = &tc3589x_keypad_data, | ||
| 214 | .irq = NOMADIK_GPIO_TO_IRQ(218), | ||
| 215 | .flags = I2C_CLIENT_WAKE, | ||
| 216 | }, | ||
| 217 | }; | ||
| 218 | |||
| 219 | void mop500_keypad_init(void) | ||
| 220 | { | ||
| 221 | db8500_add_ske_keypad(&ske_keypad_board); | ||
| 222 | |||
| 223 | i2c_register_board_info(0, mop500_i2c0_devices_stuib, | ||
| 224 | ARRAY_SIZE(mop500_i2c0_devices_stuib)); | ||
| 225 | |||
| 226 | i2c_register_board_info(0, mop500_i2c0_devices_uib, | ||
| 227 | ARRAY_SIZE(mop500_i2c0_devices_uib)); | ||
| 228 | |||
| 229 | } | ||
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c index bac995665b58..4b996676594e 100644 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ b/arch/arm/mach-ux500/board-mop500-sdi.c | |||
| @@ -16,10 +16,24 @@ | |||
| 16 | #include <mach/devices.h> | 16 | #include <mach/devices.h> |
| 17 | #include <mach/hardware.h> | 17 | #include <mach/hardware.h> |
| 18 | 18 | ||
| 19 | #include "devices-db8500.h" | ||
| 19 | #include "pins-db8500.h" | 20 | #include "pins-db8500.h" |
| 20 | #include "board-mop500.h" | 21 | #include "board-mop500.h" |
| 21 | 22 | ||
| 22 | static pin_cfg_t mop500_sdi_pins[] = { | 23 | static pin_cfg_t mop500_sdi_pins[] = { |
| 24 | /* SDI0 (MicroSD slot) */ | ||
| 25 | GPIO18_MC0_CMDDIR, | ||
| 26 | GPIO19_MC0_DAT0DIR, | ||
| 27 | GPIO20_MC0_DAT2DIR, | ||
| 28 | GPIO21_MC0_DAT31DIR, | ||
| 29 | GPIO22_MC0_FBCLK, | ||
| 30 | GPIO23_MC0_CLK, | ||
| 31 | GPIO24_MC0_CMD, | ||
| 32 | GPIO25_MC0_DAT0, | ||
| 33 | GPIO26_MC0_DAT1, | ||
| 34 | GPIO27_MC0_DAT2, | ||
| 35 | GPIO28_MC0_DAT3, | ||
| 36 | |||
| 23 | /* SDI4 (on-board eMMC) */ | 37 | /* SDI4 (on-board eMMC) */ |
| 24 | GPIO197_MC4_DAT3, | 38 | GPIO197_MC4_DAT3, |
| 25 | GPIO198_MC4_DAT2, | 39 | GPIO198_MC4_DAT2, |
| @@ -50,6 +64,55 @@ static pin_cfg_t mop500_sdi2_pins[] = { | |||
| 50 | }; | 64 | }; |
| 51 | 65 | ||
| 52 | /* | 66 | /* |
| 67 | * SDI 0 (MicroSD slot) | ||
| 68 | */ | ||
| 69 | |||
| 70 | /* MMCIPOWER bits */ | ||
| 71 | #define MCI_DATA2DIREN (1 << 2) | ||
| 72 | #define MCI_CMDDIREN (1 << 3) | ||
| 73 | #define MCI_DATA0DIREN (1 << 4) | ||
| 74 | #define MCI_DATA31DIREN (1 << 5) | ||
| 75 | #define MCI_FBCLKEN (1 << 7) | ||
| 76 | |||
| 77 | static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, | ||
| 78 | unsigned char power_mode) | ||
| 79 | { | ||
| 80 | if (power_mode == MMC_POWER_UP) | ||
| 81 | gpio_set_value_cansleep(GPIO_SDMMC_EN, 1); | ||
| 82 | else if (power_mode == MMC_POWER_OFF) | ||
| 83 | gpio_set_value_cansleep(GPIO_SDMMC_EN, 0); | ||
| 84 | |||
| 85 | return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | | ||
| 86 | MCI_DATA2DIREN | MCI_DATA31DIREN; | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct mmci_platform_data mop500_sdi0_data = { | ||
| 90 | .vdd_handler = mop500_sdi0_vdd_handler, | ||
| 91 | .ocr_mask = MMC_VDD_29_30, | ||
| 92 | .f_max = 100000000, | ||
| 93 | .capabilities = MMC_CAP_4_BIT_DATA, | ||
| 94 | .gpio_cd = GPIO_SDMMC_CD, | ||
| 95 | .gpio_wp = -1, | ||
| 96 | }; | ||
| 97 | |||
| 98 | void mop500_sdi_tc35892_init(void) | ||
| 99 | { | ||
| 100 | int ret; | ||
| 101 | |||
| 102 | ret = gpio_request(GPIO_SDMMC_EN, "SDMMC_EN"); | ||
| 103 | if (!ret) | ||
| 104 | ret = gpio_request(GPIO_SDMMC_1V8_3V_SEL, | ||
| 105 | "GPIO_SDMMC_1V8_3V_SEL"); | ||
| 106 | if (ret) | ||
| 107 | return; | ||
| 108 | |||
| 109 | gpio_direction_output(GPIO_SDMMC_1V8_3V_SEL, 1); | ||
| 110 | gpio_direction_output(GPIO_SDMMC_EN, 0); | ||
| 111 | |||
| 112 | db8500_add_sdi0(&mop500_sdi0_data); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 53 | * SDI 2 (POP eMMC, not on DB8500ed) | 116 | * SDI 2 (POP eMMC, not on DB8500ed) |
| 54 | */ | 117 | */ |
| 55 | 118 | ||
| @@ -74,18 +137,24 @@ static struct mmci_platform_data mop500_sdi4_data = { | |||
| 74 | .gpio_wp = -1, | 137 | .gpio_wp = -1, |
| 75 | }; | 138 | }; |
| 76 | 139 | ||
| 77 | void mop500_sdi_init(void) | 140 | void __init mop500_sdi_init(void) |
| 78 | { | 141 | { |
| 79 | nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins)); | 142 | nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins)); |
| 80 | 143 | ||
| 81 | u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data; | 144 | /* |
| 82 | u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data; | 145 | * sdi0 will finally be added when the TC35892 initializes and calls |
| 146 | * mop500_sdi_tc35892_init() above. | ||
| 147 | */ | ||
| 83 | 148 | ||
| 149 | /* PoP:ed eMMC */ | ||
| 84 | if (!cpu_is_u8500ed()) { | 150 | if (!cpu_is_u8500ed()) { |
| 85 | nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins)); | 151 | nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins)); |
| 86 | amba_device_register(&u8500_sdi2_device, &iomem_resource); | 152 | /* POP eMMC on v1.0 has problems with high speed */ |
| 153 | if (!cpu_is_u8500v10()) | ||
| 154 | mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED; | ||
| 155 | db8500_add_sdi2(&mop500_sdi2_data); | ||
| 87 | } | 156 | } |
| 88 | 157 | ||
| 89 | /* On-board eMMC */ | 158 | /* On-board eMMC */ |
| 90 | amba_device_register(&u8500_sdi4_device, &iomem_resource); | 159 | db8500_add_sdi4(&mop500_sdi4_data); |
| 91 | } | 160 | } |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index cac83a694880..a1c9ea1a66df 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
| @@ -13,25 +13,26 @@ | |||
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 16 | #include <linux/i2c.h> | ||
| 16 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
| 17 | #include <linux/amba/bus.h> | 18 | #include <linux/amba/bus.h> |
| 18 | #include <linux/amba/pl022.h> | 19 | #include <linux/amba/pl022.h> |
| 19 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
| 20 | #include <linux/mfd/ab8500.h> | 21 | #include <linux/mfd/ab8500.h> |
| 21 | #include <linux/input/matrix_keypad.h> | 22 | #include <linux/mfd/tc3589x.h> |
| 22 | 23 | ||
| 23 | #include <asm/mach-types.h> | 24 | #include <asm/mach-types.h> |
| 24 | #include <asm/mach/arch.h> | 25 | #include <asm/mach/arch.h> |
| 25 | 26 | ||
| 26 | #include <plat/pincfg.h> | 27 | #include <plat/pincfg.h> |
| 27 | #include <plat/i2c.h> | 28 | #include <plat/i2c.h> |
| 28 | #include <plat/ske.h> | ||
| 29 | 29 | ||
| 30 | #include <mach/hardware.h> | 30 | #include <mach/hardware.h> |
| 31 | #include <mach/setup.h> | 31 | #include <mach/setup.h> |
| 32 | #include <mach/devices.h> | 32 | #include <mach/devices.h> |
| 33 | #include <mach/irqs.h> | 33 | #include <mach/irqs.h> |
| 34 | 34 | ||
| 35 | #include "devices-db8500.h" | ||
| 35 | #include "pins-db8500.h" | 36 | #include "pins-db8500.h" |
| 36 | #include "board-mop500.h" | 37 | #include "board-mop500.h" |
| 37 | 38 | ||
| @@ -69,22 +70,12 @@ static pin_cfg_t mop500_pins[] = { | |||
| 69 | GPIO166_KP_O2, | 70 | GPIO166_KP_O2, |
| 70 | GPIO167_KP_O1, | 71 | GPIO167_KP_O1, |
| 71 | GPIO168_KP_O0, | 72 | GPIO168_KP_O0, |
| 72 | }; | ||
| 73 | 73 | ||
| 74 | static void ab4500_spi_cs_control(u32 command) | 74 | /* GPIO_EXP_INT */ |
| 75 | { | 75 | GPIO217_GPIO, |
| 76 | /* set the FRM signal, which is CS - TODO */ | ||
| 77 | } | ||
| 78 | 76 | ||
| 79 | struct pl022_config_chip ab4500_chip_info = { | 77 | /* STMPE1601 IRQ */ |
| 80 | .com_mode = INTERRUPT_TRANSFER, | 78 | GPIO218_GPIO | PIN_INPUT_PULLUP, |
| 81 | .iface = SSP_INTERFACE_MOTOROLA_SPI, | ||
| 82 | /* we can act as master only */ | ||
| 83 | .hierarchy = SSP_MASTER, | ||
| 84 | .slave_tx_disable = 0, | ||
| 85 | .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, | ||
| 86 | .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, | ||
| 87 | .cs_control = ab4500_spi_cs_control, | ||
| 88 | }; | 79 | }; |
| 89 | 80 | ||
| 90 | static struct ab8500_platform_data ab8500_platdata = { | 81 | static struct ab8500_platform_data ab8500_platdata = { |
| @@ -93,9 +84,9 @@ static struct ab8500_platform_data ab8500_platdata = { | |||
| 93 | 84 | ||
| 94 | static struct resource ab8500_resources[] = { | 85 | static struct resource ab8500_resources[] = { |
| 95 | [0] = { | 86 | [0] = { |
| 96 | .start = IRQ_AB8500, | 87 | .start = IRQ_DB8500_AB8500, |
| 97 | .end = IRQ_AB8500, | 88 | .end = IRQ_DB8500_AB8500, |
| 98 | .flags = IORESOURCE_IRQ | 89 | .flags = IORESOURCE_IRQ |
| 99 | } | 90 | } |
| 100 | }; | 91 | }; |
| 101 | 92 | ||
| @@ -109,19 +100,6 @@ struct platform_device ab8500_device = { | |||
| 109 | .resource = ab8500_resources, | 100 | .resource = ab8500_resources, |
| 110 | }; | 101 | }; |
| 111 | 102 | ||
| 112 | static struct spi_board_info ab8500_spi_devices[] = { | ||
| 113 | { | ||
| 114 | .modalias = "ab8500-spi", | ||
| 115 | .controller_data = &ab4500_chip_info, | ||
| 116 | .platform_data = &ab8500_platdata, | ||
| 117 | .max_speed_hz = 12000000, | ||
| 118 | .bus_num = 0, | ||
| 119 | .chip_select = 0, | ||
| 120 | .mode = SPI_MODE_3, | ||
| 121 | .irq = IRQ_DB8500_AB8500, | ||
| 122 | }, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct pl022_ssp_controller ssp0_platform_data = { | 103 | static struct pl022_ssp_controller ssp0_platform_data = { |
| 126 | .bus_id = 0, | 104 | .bus_id = 0, |
| 127 | /* pl022 not yet supports dma */ | 105 | /* pl022 not yet supports dma */ |
| @@ -132,6 +110,34 @@ static struct pl022_ssp_controller ssp0_platform_data = { | |||
| 132 | .num_chipselect = 5, | 110 | .num_chipselect = 5, |
| 133 | }; | 111 | }; |
| 134 | 112 | ||
| 113 | /* | ||
| 114 | * TC35892 | ||
| 115 | */ | ||
| 116 | |||
| 117 | static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base) | ||
| 118 | { | ||
| 119 | mop500_sdi_tc35892_init(); | ||
| 120 | } | ||
| 121 | |||
| 122 | static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = { | ||
| 123 | .gpio_base = MOP500_EGPIO(0), | ||
| 124 | .setup = mop500_tc35892_init, | ||
| 125 | }; | ||
| 126 | |||
| 127 | static struct tc3589x_platform_data mop500_tc35892_data = { | ||
| 128 | .block = TC3589x_BLOCK_GPIO, | ||
| 129 | .gpio = &mop500_tc35892_gpio_data, | ||
| 130 | .irq_base = MOP500_EGPIO_IRQ_BASE, | ||
| 131 | }; | ||
| 132 | |||
| 133 | static struct i2c_board_info mop500_i2c0_devices[] = { | ||
| 134 | { | ||
| 135 | I2C_BOARD_INFO("tc3589x", 0x42), | ||
| 136 | .irq = NOMADIK_GPIO_TO_IRQ(217), | ||
| 137 | .platform_data = &mop500_tc35892_data, | ||
| 138 | }, | ||
| 139 | }; | ||
| 140 | |||
| 135 | #define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ | 141 | #define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ |
| 136 | static struct nmk_i2c_controller u8500_i2c##id##_data = { \ | 142 | static struct nmk_i2c_controller u8500_i2c##id##_data = { \ |
| 137 | /* \ | 143 | /* \ |
| @@ -161,159 +167,49 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); | |||
| 161 | U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); | 167 | U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); |
| 162 | U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); | 168 | U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); |
| 163 | 169 | ||
| 164 | static struct amba_device *amba_devs[] __initdata = { | 170 | static void __init mop500_i2c_init(void) |
| 165 | &ux500_uart0_device, | 171 | { |
| 166 | &ux500_uart1_device, | 172 | db8500_add_i2c0(&u8500_i2c0_data); |
| 167 | &ux500_uart2_device, | 173 | db8500_add_i2c1(&u8500_i2c1_data); |
| 168 | &u8500_ssp0_device, | 174 | db8500_add_i2c2(&u8500_i2c2_data); |
| 169 | }; | 175 | db8500_add_i2c3(&u8500_i2c3_data); |
| 170 | 176 | } | |
| 171 | static const unsigned int ux500_keymap[] = { | ||
| 172 | KEY(2, 5, KEY_END), | ||
| 173 | KEY(4, 1, KEY_POWER), | ||
| 174 | KEY(3, 5, KEY_VOLUMEDOWN), | ||
| 175 | KEY(1, 3, KEY_3), | ||
| 176 | KEY(5, 2, KEY_RIGHT), | ||
| 177 | KEY(5, 0, KEY_9), | ||
| 178 | |||
| 179 | KEY(0, 5, KEY_MENU), | ||
| 180 | KEY(7, 6, KEY_ENTER), | ||
| 181 | KEY(4, 5, KEY_0), | ||
| 182 | KEY(6, 7, KEY_2), | ||
| 183 | KEY(3, 4, KEY_UP), | ||
| 184 | KEY(3, 3, KEY_DOWN), | ||
| 185 | |||
| 186 | KEY(6, 4, KEY_SEND), | ||
| 187 | KEY(6, 2, KEY_BACK), | ||
| 188 | KEY(4, 2, KEY_VOLUMEUP), | ||
| 189 | KEY(5, 5, KEY_1), | ||
| 190 | KEY(4, 3, KEY_LEFT), | ||
| 191 | KEY(3, 2, KEY_7), | ||
| 192 | }; | ||
| 193 | |||
| 194 | static const struct matrix_keymap_data ux500_keymap_data = { | ||
| 195 | .keymap = ux500_keymap, | ||
| 196 | .keymap_size = ARRAY_SIZE(ux500_keymap), | ||
| 197 | }; | ||
| 198 | 177 | ||
| 199 | /* | 178 | /* add any platform devices here - TODO */ |
| 200 | * Nomadik SKE keypad | 179 | static struct platform_device *platform_devs[] __initdata = { |
| 201 | */ | ||
| 202 | #define ROW_PIN_I0 164 | ||
| 203 | #define ROW_PIN_I1 163 | ||
| 204 | #define ROW_PIN_I2 162 | ||
| 205 | #define ROW_PIN_I3 161 | ||
| 206 | #define ROW_PIN_I4 156 | ||
| 207 | #define ROW_PIN_I5 155 | ||
| 208 | #define ROW_PIN_I6 154 | ||
| 209 | #define ROW_PIN_I7 153 | ||
| 210 | #define COL_PIN_O0 168 | ||
| 211 | #define COL_PIN_O1 167 | ||
| 212 | #define COL_PIN_O2 166 | ||
| 213 | #define COL_PIN_O3 165 | ||
| 214 | #define COL_PIN_O4 160 | ||
| 215 | #define COL_PIN_O5 159 | ||
| 216 | #define COL_PIN_O6 158 | ||
| 217 | #define COL_PIN_O7 157 | ||
| 218 | |||
| 219 | #define SKE_KPD_MAX_ROWS 8 | ||
| 220 | #define SKE_KPD_MAX_COLS 8 | ||
| 221 | |||
| 222 | static int ske_kp_rows[] = { | ||
| 223 | ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3, | ||
| 224 | ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7, | ||
| 225 | }; | 180 | }; |
| 226 | 181 | ||
| 227 | /* | 182 | static void __init mop500_spi_init(void) |
| 228 | * ske_set_gpio_row: request and set gpio rows | ||
| 229 | */ | ||
| 230 | static int ske_set_gpio_row(int gpio) | ||
| 231 | { | 183 | { |
| 232 | int ret; | 184 | db8500_add_ssp0(&ssp0_platform_data); |
| 233 | |||
| 234 | ret = gpio_request(gpio, "ske-kp"); | ||
| 235 | if (ret < 0) { | ||
| 236 | pr_err("ske_set_gpio_row: gpio request failed\n"); | ||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | |||
| 240 | ret = gpio_direction_output(gpio, 1); | ||
| 241 | if (ret < 0) { | ||
| 242 | pr_err("ske_set_gpio_row: gpio direction failed\n"); | ||
| 243 | gpio_free(gpio); | ||
| 244 | } | ||
| 245 | |||
| 246 | return ret; | ||
| 247 | } | 185 | } |
| 248 | 186 | ||
| 249 | /* | 187 | static void __init mop500_uart_init(void) |
| 250 | * ske_kp_init - enable the gpio configuration | ||
| 251 | */ | ||
| 252 | static int ske_kp_init(void) | ||
| 253 | { | 188 | { |
| 254 | int ret, i; | 189 | db8500_add_uart0(); |
| 255 | 190 | db8500_add_uart1(); | |
| 256 | for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { | 191 | db8500_add_uart2(); |
| 257 | ret = ske_set_gpio_row(ske_kp_rows[i]); | ||
| 258 | if (ret < 0) { | ||
| 259 | pr_err("ske_kp_init: failed init\n"); | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | 192 | } |
| 266 | 193 | ||
| 267 | static struct ske_keypad_platform_data ske_keypad_board = { | ||
| 268 | .init = ske_kp_init, | ||
| 269 | .keymap_data = &ux500_keymap_data, | ||
| 270 | .no_autorepeat = true, | ||
| 271 | .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */ | ||
| 272 | .kcol = SKE_KPD_MAX_COLS, | ||
| 273 | .debounce_ms = 40, /* in millsecs */ | ||
| 274 | }; | ||
| 275 | |||
| 276 | |||
| 277 | |||
| 278 | /* add any platform devices here - TODO */ | ||
| 279 | static struct platform_device *platform_devs[] __initdata = { | ||
| 280 | &u8500_i2c0_device, | ||
| 281 | &ux500_i2c1_device, | ||
| 282 | &ux500_i2c2_device, | ||
| 283 | &ux500_i2c3_device, | ||
| 284 | &ux500_ske_keypad_device, | ||
| 285 | }; | ||
| 286 | |||
| 287 | static void __init u8500_init_machine(void) | 194 | static void __init u8500_init_machine(void) |
| 288 | { | 195 | { |
| 289 | int i; | ||
| 290 | |||
| 291 | u8500_init_devices(); | 196 | u8500_init_devices(); |
| 292 | 197 | ||
| 293 | nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins)); | 198 | nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins)); |
| 294 | 199 | ||
| 295 | u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data; | ||
| 296 | ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data; | ||
| 297 | ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data; | ||
| 298 | ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data; | ||
| 299 | ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board; | ||
| 300 | |||
| 301 | u8500_ssp0_device.dev.platform_data = &ssp0_platform_data; | ||
| 302 | |||
| 303 | /* Register the active AMBA devices on this board */ | ||
| 304 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) | ||
| 305 | amba_device_register(amba_devs[i], &iomem_resource); | ||
| 306 | |||
| 307 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); | 200 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); |
| 308 | 201 | ||
| 202 | mop500_i2c_init(); | ||
| 309 | mop500_sdi_init(); | 203 | mop500_sdi_init(); |
| 204 | mop500_spi_init(); | ||
| 205 | mop500_uart_init(); | ||
| 206 | |||
| 207 | mop500_keypad_init(); | ||
| 208 | |||
| 209 | platform_device_register(&ab8500_device); | ||
| 310 | 210 | ||
| 311 | /* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */ | 211 | i2c_register_board_info(0, mop500_i2c0_devices, |
| 312 | if (cpu_is_u8500ed() || cpu_is_u8500v10()) | 212 | ARRAY_SIZE(mop500_i2c0_devices)); |
| 313 | spi_register_board_info(ab8500_spi_devices, | ||
| 314 | ARRAY_SIZE(ab8500_spi_devices)); | ||
| 315 | else /* If HW is v.1.1 or later use I2C to access AB8500 */ | ||
| 316 | platform_device_register(&ab8500_device); | ||
| 317 | } | 213 | } |
| 318 | 214 | ||
| 319 | MACHINE_START(U8500, "ST-Ericsson MOP500 platform") | 215 | MACHINE_START(U8500, "ST-Ericsson MOP500 platform") |
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 2d240322fa6f..3104ae2a02c2 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h | |||
| @@ -7,6 +7,15 @@ | |||
| 7 | #ifndef __BOARD_MOP500_H | 7 | #ifndef __BOARD_MOP500_H |
| 8 | #define __BOARD_MOP500_H | 8 | #define __BOARD_MOP500_H |
| 9 | 9 | ||
| 10 | #define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x)) | ||
| 11 | |||
| 12 | /* GPIOs on the TC35892 expander */ | ||
| 13 | #define GPIO_SDMMC_CD MOP500_EGPIO(3) | ||
| 14 | #define GPIO_SDMMC_EN MOP500_EGPIO(17) | ||
| 15 | #define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18) | ||
| 16 | |||
| 10 | extern void mop500_sdi_init(void); | 17 | extern void mop500_sdi_init(void); |
| 18 | extern void mop500_sdi_tc35892_init(void); | ||
| 19 | extern void mop500_keypad_init(void); | ||
| 11 | 20 | ||
| 12 | #endif | 21 | #endif |
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c new file mode 100644 index 000000000000..54712acc0394 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-sdi.c | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Hanumath Prasad <ulf.hansson@stericsson.com> | ||
| 5 | * License terms: GNU General Public License (GPL) version 2 | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/amba/mmci.h> | ||
| 9 | #include <linux/mmc/host.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | |||
| 12 | #include <plat/pincfg.h> | ||
| 13 | #include <mach/db5500-regs.h> | ||
| 14 | #include <plat/ste_dma40.h> | ||
| 15 | |||
| 16 | #include "pins-db5500.h" | ||
| 17 | #include "devices-db5500.h" | ||
| 18 | #include "ste-dma40-db5500.h" | ||
| 19 | |||
| 20 | static pin_cfg_t u5500_sdi_pins[] = { | ||
| 21 | /* SDI0 (POP eMMC) */ | ||
| 22 | GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 23 | GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 24 | GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 25 | GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 26 | GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 27 | GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 28 | GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 29 | GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 30 | GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP, | ||
| 31 | GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW, | ||
| 32 | }; | ||
| 33 | |||
| 34 | static struct mmci_platform_data u5500_sdi0_data = { | ||
| 35 | .ocr_mask = MMC_VDD_165_195, | ||
| 36 | .f_max = 50000000, | ||
| 37 | .capabilities = MMC_CAP_4_BIT_DATA | | ||
| 38 | MMC_CAP_8_BIT_DATA | | ||
| 39 | MMC_CAP_MMC_HIGHSPEED, | ||
| 40 | .gpio_cd = -1, | ||
| 41 | .gpio_wp = -1, | ||
| 42 | }; | ||
| 43 | |||
| 44 | void __init u5500_sdi_init(void) | ||
| 45 | { | ||
| 46 | nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins)); | ||
| 47 | |||
| 48 | db5500_add_sdi0(&u5500_sdi0_data); | ||
| 49 | } | ||
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 1ca094a45e71..39d370c1f3b4 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/amba/bus.h> | 10 | #include <linux/amba/bus.h> |
| 11 | #include <linux/gpio.h> | 11 | #include <linux/gpio.h> |
| 12 | #include <linux/irq.h> | ||
| 12 | 13 | ||
| 13 | #include <asm/mach/arch.h> | 14 | #include <asm/mach/arch.h> |
| 14 | #include <asm/mach-types.h> | 15 | #include <asm/mach-types.h> |
| @@ -17,20 +18,24 @@ | |||
| 17 | #include <mach/devices.h> | 18 | #include <mach/devices.h> |
| 18 | #include <mach/setup.h> | 19 | #include <mach/setup.h> |
| 19 | 20 | ||
| 20 | static struct amba_device *amba_board_devs[] __initdata = { | 21 | #include "devices-db5500.h" |
| 21 | &ux500_uart0_device, | 22 | |
| 22 | &ux500_uart1_device, | 23 | static void __init u5500_uart_init(void) |
| 23 | &ux500_uart2_device, | 24 | { |
| 24 | }; | 25 | db5500_add_uart0(); |
| 26 | db5500_add_uart1(); | ||
| 27 | db5500_add_uart2(); | ||
| 28 | } | ||
| 25 | 29 | ||
| 26 | static void __init u5500_init_machine(void) | 30 | static void __init u5500_init_machine(void) |
| 27 | { | 31 | { |
| 28 | u5500_init_devices(); | 32 | u5500_init_devices(); |
| 29 | 33 | ||
| 30 | amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs)); | 34 | u5500_sdi_init(); |
| 35 | u5500_uart_init(); | ||
| 31 | } | 36 | } |
| 32 | 37 | ||
| 33 | MACHINE_START(U8500, "ST-Ericsson U5500 Platform") | 38 | MACHINE_START(U5500, "ST-Ericsson U5500 Platform") |
| 34 | .boot_params = 0x00000100, | 39 | .boot_params = 0x00000100, |
| 35 | .map_io = u5500_map_io, | 40 | .map_io = u5500_map_io, |
| 36 | .init_irq = ux500_init_irq, | 41 | .init_irq = ux500_init_irq, |
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 1675047daf20..912d1cc18c57 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c | |||
| @@ -20,6 +20,12 @@ | |||
| 20 | #include <mach/hardware.h> | 20 | #include <mach/hardware.h> |
| 21 | #include "clock.h" | 21 | #include "clock.h" |
| 22 | 22 | ||
| 23 | #ifdef CONFIG_DEBUG_FS | ||
| 24 | #include <linux/debugfs.h> | ||
| 25 | #include <linux/uaccess.h> /* for copy_from_user */ | ||
| 26 | static LIST_HEAD(clk_list); | ||
| 27 | #endif | ||
| 28 | |||
| 23 | #define PRCC_PCKEN 0x00 | 29 | #define PRCC_PCKEN 0x00 |
| 24 | #define PRCC_PCKDIS 0x04 | 30 | #define PRCC_PCKDIS 0x04 |
| 25 | #define PRCC_KCKEN 0x08 | 31 | #define PRCC_KCKEN 0x08 |
| @@ -133,7 +139,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) | |||
| 133 | { | 139 | { |
| 134 | void __iomem *addr = __io_address(UX500_PRCMU_BASE) | 140 | void __iomem *addr = __io_address(UX500_PRCMU_BASE) |
| 135 | + PRCM_TCR; | 141 | + PRCM_TCR; |
| 136 | u32 tcr = readl(addr); | 142 | u32 tcr; |
| 137 | int mtu = (int) clk->data; | 143 | int mtu = (int) clk->data; |
| 138 | /* | 144 | /* |
| 139 | * One of these is selected eventually | 145 | * One of these is selected eventually |
| @@ -144,6 +150,14 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) | |||
| 144 | unsigned long mturate; | 150 | unsigned long mturate; |
| 145 | unsigned long retclk; | 151 | unsigned long retclk; |
| 146 | 152 | ||
| 153 | /* | ||
| 154 | * On a startup, always conifgure the TCR to the doze mode; | ||
| 155 | * bootloaders do it for us. Do this in the kernel too. | ||
| 156 | */ | ||
| 157 | writel(PRCM_TCR_DOZE_MODE, addr); | ||
| 158 | |||
| 159 | tcr = readl(addr); | ||
| 160 | |||
| 147 | /* Get the rate from the parent as a default */ | 161 | /* Get the rate from the parent as a default */ |
| 148 | if (clk->parent_periph) | 162 | if (clk->parent_periph) |
| 149 | mturate = clk_get_rate(clk->parent_periph); | 163 | mturate = clk_get_rate(clk->parent_periph); |
| @@ -153,45 +167,6 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) | |||
| 153 | /* We need to be connected SOMEWHERE */ | 167 | /* We need to be connected SOMEWHERE */ |
| 154 | BUG(); | 168 | BUG(); |
| 155 | 169 | ||
| 156 | /* | ||
| 157 | * Are we in doze mode? | ||
| 158 | * In this mode the parent peripheral or the fixed 32768 Hz | ||
| 159 | * clock is fed into the block. | ||
| 160 | */ | ||
| 161 | if (!(tcr & PRCM_TCR_DOZE_MODE)) { | ||
| 162 | /* | ||
| 163 | * Here we're using the clock input from the APE ULP | ||
| 164 | * clock domain. But first: are the timers stopped? | ||
| 165 | */ | ||
| 166 | if (tcr & PRCM_TCR_STOPPED) { | ||
| 167 | clk32k = 0; | ||
| 168 | mturate = 0; | ||
| 169 | } else { | ||
| 170 | /* Else default mode: 0 and 2.4 MHz */ | ||
| 171 | clk32k = 0; | ||
| 172 | if (cpu_is_u5500()) | ||
| 173 | /* DB5500 divides by 8 */ | ||
| 174 | mturate /= 8; | ||
| 175 | else if (cpu_is_u8500ed()) { | ||
| 176 | /* | ||
| 177 | * This clocking setting must not be used | ||
| 178 | * in the ED chip, it is simply not | ||
| 179 | * connected anywhere! | ||
| 180 | */ | ||
| 181 | mturate = 0; | ||
| 182 | BUG(); | ||
| 183 | } else | ||
| 184 | /* | ||
| 185 | * In this mode the ulp38m4 clock is divided | ||
| 186 | * by a factor 16, on the DB8500 typically | ||
| 187 | * 38400000 / 16 ~ 2.4 MHz. | ||
| 188 | * TODO: Replace the constant with a reference | ||
| 189 | * to the ULP source once this is modeled. | ||
| 190 | */ | ||
| 191 | mturate = 38400000 / 16; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Return the clock selected for this MTU */ | 170 | /* Return the clock selected for this MTU */ |
| 196 | if (tcr & (1 << mtu)) | 171 | if (tcr & (1 << mtu)) |
| 197 | retclk = clk32k; | 172 | retclk = clk32k; |
| @@ -317,6 +292,7 @@ static struct clkops clk_prcc_ops = { | |||
| 317 | }; | 292 | }; |
| 318 | 293 | ||
| 319 | static struct clk clk_32khz = { | 294 | static struct clk clk_32khz = { |
| 295 | .name = "clk_32khz", | ||
| 320 | .rate = 32000, | 296 | .rate = 32000, |
| 321 | }; | 297 | }; |
| 322 | 298 | ||
| @@ -366,94 +342,96 @@ static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */ | |||
| 366 | */ | 342 | */ |
| 367 | 343 | ||
| 368 | /* Peripheral Cluster #1 */ | 344 | /* Peripheral Cluster #1 */ |
| 369 | static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); | 345 | static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk); |
| 370 | static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); | 346 | static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL); |
| 371 | static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); | 347 | static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk); |
| 372 | static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); | 348 | static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL); |
| 373 | static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); | 349 | static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL); |
| 374 | static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); | 350 | static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk); |
| 375 | static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); | 351 | static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk); |
| 376 | static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); | 352 | static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk); |
| 377 | static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); | 353 | static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk); |
| 378 | static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); | 354 | static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk); |
| 379 | static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); | 355 | static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk); |
| 380 | static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); | 356 | static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk); |
| 381 | static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); | 357 | static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk); |
| 382 | 358 | ||
| 383 | /* Peripheral Cluster #2 */ | 359 | /* Peripheral Cluster #2 */ |
| 384 | 360 | ||
| 385 | static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL); | 361 | static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL); |
| 386 | static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); | 362 | static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL); |
| 387 | static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); | 363 | static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL); |
| 388 | static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); | 364 | static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL); |
| 389 | static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); | 365 | static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk); |
| 390 | static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); | 366 | static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk); |
| 391 | static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); | 367 | static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk); |
| 392 | static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); | 368 | static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk); |
| 393 | static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL); | 369 | static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL); |
| 394 | static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); | 370 | static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL); |
| 395 | static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); | 371 | static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL); |
| 396 | static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); | 372 | static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk); |
| 397 | 373 | ||
| 398 | static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL); | 374 | static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL); |
| 399 | static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); | 375 | static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL); |
| 400 | static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); | 376 | static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL); |
| 401 | static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); | 377 | static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL); |
| 402 | static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); | 378 | static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk); |
| 403 | static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); | 379 | static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk); |
| 404 | static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); | 380 | static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk); |
| 405 | static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); | 381 | static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk); |
| 406 | static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL); | 382 | static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL); |
| 407 | static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); | 383 | static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL); |
| 408 | static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); | 384 | static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL); |
| 409 | static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); | 385 | static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk); |
| 410 | 386 | ||
| 411 | /* Peripheral Cluster #3 */ | 387 | /* Peripheral Cluster #3 */ |
| 412 | static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); | 388 | static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL); |
| 413 | static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); | 389 | static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk); |
| 414 | static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); | 390 | static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk); |
| 415 | static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); | 391 | static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz); |
| 416 | static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); | 392 | static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk); |
| 417 | static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); | 393 | static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk); |
| 418 | static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); | 394 | static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk); |
| 419 | static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); | 395 | static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk); |
| 420 | static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); | 396 | static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk); |
| 421 | static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); | 397 | static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk); |
| 422 | static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); | 398 | static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL); |
| 423 | 399 | ||
| 424 | /* Peripheral Cluster #4 is in the always on domain */ | 400 | /* Peripheral Cluster #4 is in the always on domain */ |
| 425 | 401 | ||
| 426 | /* Peripheral Cluster #5 */ | 402 | /* Peripheral Cluster #5 */ |
| 427 | static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); | 403 | static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL); |
| 428 | static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); | 404 | static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk); |
| 429 | static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); | 405 | static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); |
| 430 | 406 | ||
| 431 | /* Peripheral Cluster #6 */ | 407 | /* Peripheral Cluster #6 */ |
| 432 | 408 | ||
| 433 | /* MTU ID in data */ | 409 | /* MTU ID in data */ |
| 434 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); | 410 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); |
| 435 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); | 411 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); |
| 436 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); | 412 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); |
| 437 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); | 413 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); |
| 438 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); | 414 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); |
| 439 | static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); | 415 | static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk); |
| 440 | static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); | 416 | static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL); |
| 441 | static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); | 417 | static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL); |
| 442 | static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); | 418 | static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL); |
| 443 | static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); | 419 | static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL); |
| 444 | static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); | 420 | static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk); |
| 445 | static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); | 421 | static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); |
| 446 | 422 | ||
| 447 | /* Peripheral Cluster #7 */ | 423 | /* Peripheral Cluster #7 */ |
| 448 | 424 | ||
| 449 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); | 425 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); |
| 450 | /* MTU ID in data */ | 426 | /* MTU ID in data */ |
| 451 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); | 427 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); |
| 452 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); | 428 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); |
| 453 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); | 429 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); |
| 454 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); | 430 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); |
| 455 | 431 | ||
| 456 | static struct clk clk_dummy_apb_pclk; | 432 | static struct clk clk_dummy_apb_pclk = { |
| 433 | .name = "apb_pclk", | ||
| 434 | }; | ||
| 457 | 435 | ||
| 458 | static struct clk_lookup u8500_common_clks[] = { | 436 | static struct clk_lookup u8500_common_clks[] = { |
| 459 | CLK(dummy_apb_pclk, NULL, "apb_pclk"), | 437 | CLK(dummy_apb_pclk, NULL, "apb_pclk"), |
| @@ -554,7 +532,7 @@ static struct clk_lookup u8500_ed_clks[] = { | |||
| 554 | 532 | ||
| 555 | static struct clk_lookup u8500_v1_clks[] = { | 533 | static struct clk_lookup u8500_v1_clks[] = { |
| 556 | /* Peripheral Cluster #1 */ | 534 | /* Peripheral Cluster #1 */ |
| 557 | CLK(i2c4, "nmk-i2c.4", NULL), | 535 | CLK(i2c4, "nmk-i2c.4", NULL), |
| 558 | CLK(spi3_v1, "spi3", NULL), | 536 | CLK(spi3_v1, "spi3", NULL), |
| 559 | CLK(msp1_v1, "msp1", NULL), | 537 | CLK(msp1_v1, "msp1", NULL), |
| 560 | 538 | ||
| @@ -599,6 +577,183 @@ static struct clk_lookup u8500_v1_clks[] = { | |||
| 599 | CLK(uiccclk, "uicc", NULL), | 577 | CLK(uiccclk, "uicc", NULL), |
| 600 | }; | 578 | }; |
| 601 | 579 | ||
| 580 | #ifdef CONFIG_DEBUG_FS | ||
| 581 | /* | ||
| 582 | * debugfs support to trace clock tree hierarchy and attributes with | ||
| 583 | * powerdebug | ||
| 584 | */ | ||
| 585 | static struct dentry *clk_debugfs_root; | ||
| 586 | |||
| 587 | void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num) | ||
| 588 | { | ||
| 589 | while (num--) { | ||
| 590 | /* Check that the clock has not been already registered */ | ||
| 591 | if (!(cl->clk->list.prev != cl->clk->list.next)) | ||
| 592 | list_add_tail(&cl->clk->list, &clk_list); | ||
| 593 | |||
| 594 | cl++; | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | static ssize_t usecount_dbg_read(struct file *file, char __user *buf, | ||
| 599 | size_t size, loff_t *off) | ||
| 600 | { | ||
| 601 | struct clk *clk = file->f_dentry->d_inode->i_private; | ||
| 602 | char cusecount[128]; | ||
| 603 | unsigned int len; | ||
| 604 | |||
| 605 | len = sprintf(cusecount, "%u\n", clk->enabled); | ||
| 606 | return simple_read_from_buffer(buf, size, off, cusecount, len); | ||
| 607 | } | ||
| 608 | |||
| 609 | static ssize_t rate_dbg_read(struct file *file, char __user *buf, | ||
| 610 | size_t size, loff_t *off) | ||
| 611 | { | ||
| 612 | struct clk *clk = file->f_dentry->d_inode->i_private; | ||
| 613 | char crate[128]; | ||
| 614 | unsigned int rate; | ||
| 615 | unsigned int len; | ||
| 616 | |||
| 617 | rate = clk_get_rate(clk); | ||
| 618 | len = sprintf(crate, "%u\n", rate); | ||
| 619 | return simple_read_from_buffer(buf, size, off, crate, len); | ||
| 620 | } | ||
| 621 | |||
| 622 | static const struct file_operations usecount_fops = { | ||
| 623 | .read = usecount_dbg_read, | ||
| 624 | }; | ||
| 625 | |||
| 626 | static const struct file_operations set_rate_fops = { | ||
| 627 | .read = rate_dbg_read, | ||
| 628 | }; | ||
| 629 | |||
| 630 | static struct dentry *clk_debugfs_register_dir(struct clk *c, | ||
| 631 | struct dentry *p_dentry) | ||
| 632 | { | ||
| 633 | struct dentry *d, *clk_d, *child, *child_tmp; | ||
| 634 | char s[255]; | ||
| 635 | char *p = s; | ||
| 636 | |||
| 637 | if (c->name == NULL) | ||
| 638 | p += sprintf(p, "BUG"); | ||
| 639 | else | ||
| 640 | p += sprintf(p, "%s", c->name); | ||
| 641 | |||
| 642 | clk_d = debugfs_create_dir(s, p_dentry); | ||
| 643 | if (!clk_d) | ||
| 644 | return NULL; | ||
| 645 | |||
| 646 | d = debugfs_create_file("usecount", S_IRUGO, | ||
| 647 | clk_d, c, &usecount_fops); | ||
| 648 | if (!d) | ||
| 649 | goto err_out; | ||
| 650 | d = debugfs_create_file("rate", S_IRUGO, | ||
| 651 | clk_d, c, &set_rate_fops); | ||
| 652 | if (!d) | ||
| 653 | goto err_out; | ||
| 654 | /* | ||
| 655 | * TODO : not currently available in ux500 | ||
| 656 | * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags); | ||
| 657 | * if (!d) | ||
| 658 | * goto err_out; | ||
| 659 | */ | ||
| 660 | |||
| 661 | return clk_d; | ||
| 662 | |||
| 663 | err_out: | ||
| 664 | d = clk_d; | ||
| 665 | list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) | ||
| 666 | debugfs_remove(child); | ||
| 667 | debugfs_remove(clk_d); | ||
| 668 | return NULL; | ||
| 669 | } | ||
| 670 | |||
| 671 | static void clk_debugfs_remove_dir(struct dentry *cdentry) | ||
| 672 | { | ||
| 673 | struct dentry *d, *child, *child_tmp; | ||
| 674 | |||
| 675 | d = cdentry; | ||
| 676 | list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) | ||
| 677 | debugfs_remove(child); | ||
| 678 | debugfs_remove(cdentry); | ||
| 679 | return ; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int clk_debugfs_register_one(struct clk *c) | ||
| 683 | { | ||
| 684 | struct clk *pa = c->parent_periph; | ||
| 685 | struct clk *bpa = c->parent_cluster; | ||
| 686 | |||
| 687 | if (!(bpa && !pa)) { | ||
| 688 | c->dent = clk_debugfs_register_dir(c, | ||
| 689 | pa ? pa->dent : clk_debugfs_root); | ||
| 690 | if (!c->dent) | ||
| 691 | return -ENOMEM; | ||
| 692 | } | ||
| 693 | |||
| 694 | if (bpa) { | ||
| 695 | c->dent_bus = clk_debugfs_register_dir(c, | ||
| 696 | bpa->dent_bus ? bpa->dent_bus : bpa->dent); | ||
| 697 | if ((!c->dent_bus) && (c->dent)) { | ||
| 698 | clk_debugfs_remove_dir(c->dent); | ||
| 699 | c->dent = NULL; | ||
| 700 | return -ENOMEM; | ||
| 701 | } | ||
| 702 | } | ||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | static int clk_debugfs_register(struct clk *c) | ||
| 707 | { | ||
| 708 | int err; | ||
| 709 | struct clk *pa = c->parent_periph; | ||
| 710 | struct clk *bpa = c->parent_cluster; | ||
| 711 | |||
| 712 | if (pa && (!pa->dent && !pa->dent_bus)) { | ||
| 713 | err = clk_debugfs_register(pa); | ||
| 714 | if (err) | ||
| 715 | return err; | ||
| 716 | } | ||
| 717 | |||
| 718 | if (bpa && (!bpa->dent && !bpa->dent_bus)) { | ||
| 719 | err = clk_debugfs_register(bpa); | ||
| 720 | if (err) | ||
| 721 | return err; | ||
| 722 | } | ||
| 723 | |||
| 724 | if ((!c->dent) && (!c->dent_bus)) { | ||
| 725 | err = clk_debugfs_register_one(c); | ||
| 726 | if (err) | ||
| 727 | return err; | ||
| 728 | } | ||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | |||
| 732 | static int __init clk_debugfs_init(void) | ||
| 733 | { | ||
| 734 | struct clk *c; | ||
| 735 | struct dentry *d; | ||
| 736 | int err; | ||
| 737 | |||
| 738 | d = debugfs_create_dir("clock", NULL); | ||
| 739 | if (!d) | ||
| 740 | return -ENOMEM; | ||
| 741 | clk_debugfs_root = d; | ||
| 742 | |||
| 743 | list_for_each_entry(c, &clk_list, list) { | ||
| 744 | err = clk_debugfs_register(c); | ||
| 745 | if (err) | ||
| 746 | goto err_out; | ||
| 747 | } | ||
| 748 | return 0; | ||
| 749 | err_out: | ||
| 750 | debugfs_remove_recursive(clk_debugfs_root); | ||
| 751 | return err; | ||
| 752 | } | ||
| 753 | |||
| 754 | late_initcall(clk_debugfs_init); | ||
| 755 | #endif /* defined(CONFIG_DEBUG_FS) */ | ||
| 756 | |||
| 602 | int __init clk_init(void) | 757 | int __init clk_init(void) |
| 603 | { | 758 | { |
| 604 | if (cpu_is_u8500ed()) { | 759 | if (cpu_is_u8500ed()) { |
| @@ -609,7 +764,8 @@ int __init clk_init(void) | |||
| 609 | /* Clock tree for U5500 not implemented yet */ | 764 | /* Clock tree for U5500 not implemented yet */ |
| 610 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; | 765 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; |
| 611 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; | 766 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; |
| 612 | clk_per6clk.rate = 26000000; | 767 | clk_uartclk.rate = 36360000; |
| 768 | clk_sdmmcclk.rate = 99900000; | ||
| 613 | } | 769 | } |
| 614 | 770 | ||
| 615 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); | 771 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); |
| @@ -618,5 +774,12 @@ int __init clk_init(void) | |||
| 618 | else | 774 | else |
| 619 | clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); | 775 | clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); |
| 620 | 776 | ||
| 777 | #ifdef CONFIG_DEBUG_FS | ||
| 778 | clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); | ||
| 779 | if (cpu_is_u8500ed()) | ||
| 780 | clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks)); | ||
| 781 | else | ||
| 782 | clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); | ||
| 783 | #endif | ||
| 621 | return 0; | 784 | return 0; |
| 622 | } | 785 | } |
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index a05802501527..074490705229 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h | |||
| @@ -90,6 +90,10 @@ struct clk { | |||
| 90 | 90 | ||
| 91 | struct clk *parent_cluster; | 91 | struct clk *parent_cluster; |
| 92 | struct clk *parent_periph; | 92 | struct clk *parent_periph; |
| 93 | #if defined(CONFIG_DEBUG_FS) | ||
| 94 | struct dentry *dent; /* For visible tree hierarchy */ | ||
| 95 | struct dentry *dent_bus; /* For visible tree hierarchy */ | ||
| 96 | #endif | ||
| 93 | }; | 97 | }; |
| 94 | 98 | ||
| 95 | #define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ | 99 | #define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ |
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c index 2f87075e9d6f..acc841e48de4 100644 --- a/arch/arm/mach-ux500/cpu-db5500.c +++ b/arch/arm/mach-ux500/cpu-db5500.c | |||
| @@ -8,14 +8,19 @@ | |||
| 8 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
| 9 | #include <linux/amba/bus.h> | 9 | #include <linux/amba/bus.h> |
| 10 | #include <linux/io.h> | 10 | #include <linux/io.h> |
| 11 | #include <linux/irq.h> | ||
| 11 | 12 | ||
| 12 | #include <asm/mach/map.h> | 13 | #include <asm/mach/map.h> |
| 13 | 14 | ||
| 15 | #include <plat/gpio.h> | ||
| 16 | |||
| 14 | #include <mach/hardware.h> | 17 | #include <mach/hardware.h> |
| 15 | #include <mach/devices.h> | 18 | #include <mach/devices.h> |
| 16 | #include <mach/setup.h> | 19 | #include <mach/setup.h> |
| 17 | #include <mach/irqs.h> | 20 | #include <mach/irqs.h> |
| 18 | 21 | ||
| 22 | #include "devices-db5500.h" | ||
| 23 | |||
| 19 | static struct map_desc u5500_io_desc[] __initdata = { | 24 | static struct map_desc u5500_io_desc[] __initdata = { |
| 20 | __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K), | 25 | __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K), |
| 21 | __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K), | 26 | __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K), |
| @@ -110,19 +115,32 @@ static struct platform_device mbox2_device = { | |||
| 110 | }; | 115 | }; |
| 111 | 116 | ||
| 112 | static struct platform_device *u5500_platform_devs[] __initdata = { | 117 | static struct platform_device *u5500_platform_devs[] __initdata = { |
| 113 | &u5500_gpio_devs[0], | ||
| 114 | &u5500_gpio_devs[1], | ||
| 115 | &u5500_gpio_devs[2], | ||
| 116 | &u5500_gpio_devs[3], | ||
| 117 | &u5500_gpio_devs[4], | ||
| 118 | &u5500_gpio_devs[5], | ||
| 119 | &u5500_gpio_devs[6], | ||
| 120 | &u5500_gpio_devs[7], | ||
| 121 | &mbox0_device, | 118 | &mbox0_device, |
| 122 | &mbox1_device, | 119 | &mbox1_device, |
| 123 | &mbox2_device, | 120 | &mbox2_device, |
| 124 | }; | 121 | }; |
| 125 | 122 | ||
| 123 | static resource_size_t __initdata db5500_gpio_base[] = { | ||
| 124 | U5500_GPIOBANK0_BASE, | ||
| 125 | U5500_GPIOBANK1_BASE, | ||
| 126 | U5500_GPIOBANK2_BASE, | ||
| 127 | U5500_GPIOBANK3_BASE, | ||
| 128 | U5500_GPIOBANK4_BASE, | ||
| 129 | U5500_GPIOBANK5_BASE, | ||
| 130 | U5500_GPIOBANK6_BASE, | ||
| 131 | U5500_GPIOBANK7_BASE, | ||
| 132 | }; | ||
| 133 | |||
| 134 | static void __init db5500_add_gpios(void) | ||
| 135 | { | ||
| 136 | struct nmk_gpio_platform_data pdata = { | ||
| 137 | /* No custom data yet */ | ||
| 138 | }; | ||
| 139 | |||
| 140 | dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base), | ||
| 141 | IRQ_DB5500_GPIO0, &pdata); | ||
| 142 | } | ||
| 143 | |||
| 126 | void __init u5500_map_io(void) | 144 | void __init u5500_map_io(void) |
| 127 | { | 145 | { |
| 128 | ux500_map_io(); | 146 | ux500_map_io(); |
| @@ -132,7 +150,9 @@ void __init u5500_map_io(void) | |||
| 132 | 150 | ||
| 133 | void __init u5500_init_devices(void) | 151 | void __init u5500_init_devices(void) |
| 134 | { | 152 | { |
| 135 | ux500_init_devices(); | 153 | db5500_add_gpios(); |
| 154 | db5500_dma_init(); | ||
| 155 | db5500_add_rtc(); | ||
| 136 | 156 | ||
| 137 | platform_add_devices(u5500_platform_devs, | 157 | platform_add_devices(u5500_platform_devs, |
| 138 | ARRAY_SIZE(u5500_platform_devs)); | 158 | ARRAY_SIZE(u5500_platform_devs)); |
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 4acab7544b3c..c0f34a404c53 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c | |||
| @@ -22,23 +22,15 @@ | |||
| 22 | #include <mach/setup.h> | 22 | #include <mach/setup.h> |
| 23 | #include <mach/devices.h> | 23 | #include <mach/devices.h> |
| 24 | 24 | ||
| 25 | #include "devices-db8500.h" | ||
| 26 | |||
| 25 | static struct platform_device *platform_devs[] __initdata = { | 27 | static struct platform_device *platform_devs[] __initdata = { |
| 26 | &u8500_gpio_devs[0], | ||
| 27 | &u8500_gpio_devs[1], | ||
| 28 | &u8500_gpio_devs[2], | ||
| 29 | &u8500_gpio_devs[3], | ||
| 30 | &u8500_gpio_devs[4], | ||
| 31 | &u8500_gpio_devs[5], | ||
| 32 | &u8500_gpio_devs[6], | ||
| 33 | &u8500_gpio_devs[7], | ||
| 34 | &u8500_gpio_devs[8], | ||
| 35 | &u8500_dma40_device, | 28 | &u8500_dma40_device, |
| 36 | }; | 29 | }; |
| 37 | 30 | ||
| 38 | /* minimum static i/o mapping required to boot U8500 platforms */ | 31 | /* minimum static i/o mapping required to boot U8500 platforms */ |
| 39 | static struct map_desc u8500_io_desc[] __initdata = { | 32 | static struct map_desc u8500_io_desc[] __initdata = { |
| 40 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), | 33 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), |
| 41 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), | ||
| 42 | __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), | 34 | __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), |
| 43 | __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), | 35 | __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), |
| 44 | __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), | 36 | __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), |
| @@ -46,13 +38,18 @@ static struct map_desc u8500_io_desc[] __initdata = { | |||
| 46 | __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M), | 38 | __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M), |
| 47 | }; | 39 | }; |
| 48 | 40 | ||
| 49 | static struct map_desc u8500ed_io_desc[] __initdata = { | 41 | static struct map_desc u8500_ed_io_desc[] __initdata = { |
| 50 | __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), | 42 | __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), |
| 51 | __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), | 43 | __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), |
| 52 | }; | 44 | }; |
| 53 | 45 | ||
| 54 | static struct map_desc u8500v1_io_desc[] __initdata = { | 46 | static struct map_desc u8500_v1_io_desc[] __initdata = { |
| 55 | __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), | 47 | __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), |
| 48 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE_V1, SZ_4K), | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct map_desc u8500_v2_io_desc[] __initdata = { | ||
| 52 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), | ||
| 56 | }; | 53 | }; |
| 57 | 54 | ||
| 58 | /* | 55 | /* |
| @@ -125,14 +122,38 @@ void __init u8500_map_io(void) | |||
| 125 | iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); | 122 | iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); |
| 126 | 123 | ||
| 127 | if (cpu_is_u8500ed()) | 124 | if (cpu_is_u8500ed()) |
| 128 | iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc)); | 125 | iotable_init(u8500_ed_io_desc, ARRAY_SIZE(u8500_ed_io_desc)); |
| 129 | else | 126 | else if (cpu_is_u8500v1()) |
| 130 | iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc)); | 127 | iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc)); |
| 128 | else if (cpu_is_u8500v2()) | ||
| 129 | iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc)); | ||
| 131 | 130 | ||
| 132 | /* Read out the ASIC ID as early as we can */ | 131 | /* Read out the ASIC ID as early as we can */ |
| 133 | get_db8500_asic_id(); | 132 | get_db8500_asic_id(); |
| 134 | } | 133 | } |
| 135 | 134 | ||
| 135 | static resource_size_t __initdata db8500_gpio_base[] = { | ||
| 136 | U8500_GPIOBANK0_BASE, | ||
| 137 | U8500_GPIOBANK1_BASE, | ||
| 138 | U8500_GPIOBANK2_BASE, | ||
| 139 | U8500_GPIOBANK3_BASE, | ||
| 140 | U8500_GPIOBANK4_BASE, | ||
| 141 | U8500_GPIOBANK5_BASE, | ||
| 142 | U8500_GPIOBANK6_BASE, | ||
| 143 | U8500_GPIOBANK7_BASE, | ||
| 144 | U8500_GPIOBANK8_BASE, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static void __init db8500_add_gpios(void) | ||
| 148 | { | ||
| 149 | struct nmk_gpio_platform_data pdata = { | ||
| 150 | /* No custom data yet */ | ||
| 151 | }; | ||
| 152 | |||
| 153 | dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base), | ||
| 154 | IRQ_DB8500_GPIO0, &pdata); | ||
| 155 | } | ||
| 156 | |||
| 136 | /* | 157 | /* |
| 137 | * This function is called from the board init | 158 | * This function is called from the board init |
| 138 | */ | 159 | */ |
| @@ -152,12 +173,13 @@ void __init u8500_init_devices(void) | |||
| 152 | else | 173 | else |
| 153 | pr_warning("ASIC: UNKNOWN SILICON VERSION!\n"); | 174 | pr_warning("ASIC: UNKNOWN SILICON VERSION!\n"); |
| 154 | 175 | ||
| 155 | ux500_init_devices(); | ||
| 156 | |||
| 157 | if (cpu_is_u8500ed()) | 176 | if (cpu_is_u8500ed()) |
| 158 | dma40_u8500ed_fixup(); | 177 | dma40_u8500ed_fixup(); |
| 159 | 178 | ||
| 160 | /* Register the platform devices */ | 179 | db8500_add_rtc(); |
| 180 | db8500_add_gpios(); | ||
| 181 | |||
| 182 | platform_device_register_simple("cpufreq-u8500", -1, NULL, 0); | ||
| 161 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); | 183 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); |
| 162 | 184 | ||
| 163 | return ; | 185 | return ; |
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 608a1372b172..a3700bc374d3 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
| 9 | #include <linux/amba/bus.h> | ||
| 10 | #include <linux/io.h> | 9 | #include <linux/io.h> |
| 11 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| 12 | 11 | ||
| @@ -20,6 +19,7 @@ | |||
| 20 | #include <mach/hardware.h> | 19 | #include <mach/hardware.h> |
| 21 | #include <mach/setup.h> | 20 | #include <mach/setup.h> |
| 22 | #include <mach/devices.h> | 21 | #include <mach/devices.h> |
| 22 | #include <mach/prcmu.h> | ||
| 23 | 23 | ||
| 24 | #include "clock.h" | 24 | #include "clock.h" |
| 25 | 25 | ||
| @@ -45,20 +45,11 @@ static struct map_desc ux500_io_desc[] __initdata = { | |||
| 45 | __IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K), | 45 | __IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K), |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | static struct amba_device *ux500_amba_devs[] __initdata = { | ||
| 49 | &ux500_pl031_device, | ||
| 50 | }; | ||
| 51 | |||
| 52 | void __init ux500_map_io(void) | 48 | void __init ux500_map_io(void) |
| 53 | { | 49 | { |
| 54 | iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc)); | 50 | iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc)); |
| 55 | } | 51 | } |
| 56 | 52 | ||
| 57 | void __init ux500_init_devices(void) | ||
| 58 | { | ||
| 59 | amba_add_devices(ux500_amba_devs, ARRAY_SIZE(ux500_amba_devs)); | ||
| 60 | } | ||
| 61 | |||
| 62 | void __init ux500_init_irq(void) | 53 | void __init ux500_init_irq(void) |
| 63 | { | 54 | { |
| 64 | gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); | 55 | gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); |
| @@ -68,6 +59,8 @@ void __init ux500_init_irq(void) | |||
| 68 | * Init clocks here so that they are available for system timer | 59 | * Init clocks here so that they are available for system timer |
| 69 | * initialization. | 60 | * initialization. |
| 70 | */ | 61 | */ |
| 62 | if (cpu_is_u8500()) | ||
| 63 | prcmu_early_init(); | ||
| 71 | clk_init(); | 64 | clk_init(); |
| 72 | } | 65 | } |
| 73 | 66 | ||
diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c new file mode 100644 index 000000000000..5c5b747f134d --- /dev/null +++ b/arch/arm/mach-ux500/cpufreq.c | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | /* | ||
| 2 | * CPU frequency scaling for u8500 | ||
| 3 | * Inspired by linux/arch/arm/mach-davinci/cpufreq.c | ||
| 4 | * | ||
| 5 | * Copyright (C) STMicroelectronics 2009 | ||
| 6 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 7 | * | ||
| 8 | * License Terms: GNU General Public License v2 | ||
| 9 | * | ||
| 10 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 11 | * Author: Martin Persson <martin.persson@stericsson.com> | ||
| 12 | * Author: Jonas Aaberg <jonas.aberg@stericsson.com> | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/cpufreq.h> | ||
| 19 | #include <linux/delay.h> | ||
| 20 | |||
| 21 | #include <mach/hardware.h> | ||
| 22 | #include <mach/prcmu.h> | ||
| 23 | #include <mach/prcmu-defs.h> | ||
| 24 | |||
| 25 | #define DRIVER_NAME "cpufreq-u8500" | ||
| 26 | #define CPUFREQ_NAME "u8500" | ||
| 27 | |||
| 28 | static struct device *dev; | ||
| 29 | |||
| 30 | static struct cpufreq_frequency_table freq_table[] = { | ||
| 31 | [0] = { | ||
| 32 | .index = 0, | ||
| 33 | .frequency = 200000, | ||
| 34 | }, | ||
| 35 | [1] = { | ||
| 36 | .index = 1, | ||
| 37 | .frequency = 300000, | ||
| 38 | }, | ||
| 39 | [2] = { | ||
| 40 | .index = 2, | ||
| 41 | .frequency = 600000, | ||
| 42 | }, | ||
| 43 | [3] = { | ||
| 44 | /* Used for CPU_OPP_MAX, if available */ | ||
| 45 | .index = 3, | ||
| 46 | .frequency = CPUFREQ_TABLE_END, | ||
| 47 | }, | ||
| 48 | [4] = { | ||
| 49 | .index = 4, | ||
| 50 | .frequency = CPUFREQ_TABLE_END, | ||
| 51 | }, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static enum prcmu_cpu_opp index2opp[] = { | ||
| 55 | CPU_OPP_EXT_CLK, | ||
| 56 | CPU_OPP_50, | ||
| 57 | CPU_OPP_100, | ||
| 58 | CPU_OPP_MAX | ||
| 59 | }; | ||
| 60 | |||
| 61 | static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy) | ||
| 62 | { | ||
| 63 | return cpufreq_frequency_table_verify(policy, freq_table); | ||
| 64 | } | ||
| 65 | |||
| 66 | static int u8500_cpufreq_target(struct cpufreq_policy *policy, | ||
| 67 | unsigned int target_freq, | ||
| 68 | unsigned int relation) | ||
| 69 | { | ||
| 70 | struct cpufreq_freqs freqs; | ||
| 71 | unsigned int index; | ||
| 72 | int ret = 0; | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Ensure desired rate is within allowed range. Some govenors | ||
| 76 | * (ondemand) will just pass target_freq=0 to get the minimum. | ||
| 77 | */ | ||
| 78 | if (target_freq < policy->cpuinfo.min_freq) | ||
| 79 | target_freq = policy->cpuinfo.min_freq; | ||
| 80 | if (target_freq > policy->cpuinfo.max_freq) | ||
| 81 | target_freq = policy->cpuinfo.max_freq; | ||
| 82 | |||
| 83 | ret = cpufreq_frequency_table_target(policy, freq_table, | ||
| 84 | target_freq, relation, &index); | ||
| 85 | if (ret < 0) { | ||
| 86 | dev_err(dev, "Could not look up next frequency\n"); | ||
| 87 | return ret; | ||
| 88 | } | ||
| 89 | |||
| 90 | freqs.old = policy->cur; | ||
| 91 | freqs.new = freq_table[index].frequency; | ||
| 92 | freqs.cpu = policy->cpu; | ||
| 93 | |||
| 94 | if (freqs.old == freqs.new) { | ||
| 95 | dev_dbg(dev, "Current and target frequencies are equal\n"); | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new); | ||
| 100 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
| 101 | |||
| 102 | ret = prcmu_set_cpu_opp(index2opp[index]); | ||
| 103 | if (ret < 0) { | ||
| 104 | dev_err(dev, "Failed to set OPP level\n"); | ||
| 105 | return ret; | ||
| 106 | } | ||
| 107 | |||
| 108 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
| 109 | |||
| 110 | return ret; | ||
| 111 | } | ||
| 112 | |||
| 113 | static unsigned int u8500_cpufreq_getspeed(unsigned int cpu) | ||
| 114 | { | ||
| 115 | int i; | ||
| 116 | |||
| 117 | for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++) | ||
| 118 | ; | ||
| 119 | return freq_table[i].frequency; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy) | ||
| 123 | { | ||
| 124 | int res; | ||
| 125 | |||
| 126 | BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table)); | ||
| 127 | |||
| 128 | if (cpu_is_u8500v2()) { | ||
| 129 | freq_table[1].frequency = 400000; | ||
| 130 | freq_table[2].frequency = 800000; | ||
| 131 | if (prcmu_has_arm_maxopp()) | ||
| 132 | freq_table[3].frequency = 1000000; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* get policy fields based on the table */ | ||
| 136 | res = cpufreq_frequency_table_cpuinfo(policy, freq_table); | ||
| 137 | if (!res) | ||
| 138 | cpufreq_frequency_table_get_attr(freq_table, policy->cpu); | ||
| 139 | else { | ||
| 140 | dev_err(dev, "u8500-cpufreq : Failed to read policy table\n"); | ||
| 141 | return res; | ||
| 142 | } | ||
| 143 | |||
| 144 | policy->min = policy->cpuinfo.min_freq; | ||
| 145 | policy->max = policy->cpuinfo.max_freq; | ||
| 146 | policy->cur = u8500_cpufreq_getspeed(policy->cpu); | ||
| 147 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
| 148 | |||
| 149 | /* | ||
| 150 | * FIXME : Need to take time measurement across the target() | ||
| 151 | * function with no/some/all drivers in the notification | ||
| 152 | * list. | ||
| 153 | */ | ||
| 154 | policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */ | ||
| 155 | |||
| 156 | /* policy sharing between dual CPUs */ | ||
| 157 | cpumask_copy(policy->cpus, &cpu_present_map); | ||
| 158 | |||
| 159 | policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; | ||
| 160 | |||
| 161 | return res; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct freq_attr *u8500_cpufreq_attr[] = { | ||
| 165 | &cpufreq_freq_attr_scaling_available_freqs, | ||
| 166 | NULL, | ||
| 167 | }; | ||
| 168 | static int u8500_cpu_exit(struct cpufreq_policy *policy) | ||
| 169 | { | ||
| 170 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static struct cpufreq_driver u8500_driver = { | ||
| 175 | .owner = THIS_MODULE, | ||
| 176 | .flags = CPUFREQ_STICKY, | ||
| 177 | .verify = u8500_cpufreq_verify_speed, | ||
| 178 | .target = u8500_cpufreq_target, | ||
| 179 | .get = u8500_cpufreq_getspeed, | ||
| 180 | .init = u8500_cpu_init, | ||
| 181 | .exit = u8500_cpu_exit, | ||
| 182 | .name = CPUFREQ_NAME, | ||
| 183 | .attr = u8500_cpufreq_attr, | ||
| 184 | }; | ||
| 185 | |||
| 186 | static int __init u8500_cpufreq_probe(struct platform_device *pdev) | ||
| 187 | { | ||
| 188 | dev = &pdev->dev; | ||
| 189 | return cpufreq_register_driver(&u8500_driver); | ||
| 190 | } | ||
| 191 | |||
| 192 | static int __exit u8500_cpufreq_remove(struct platform_device *pdev) | ||
| 193 | { | ||
| 194 | return cpufreq_unregister_driver(&u8500_driver); | ||
| 195 | } | ||
| 196 | |||
| 197 | static struct platform_driver u8500_cpufreq_driver = { | ||
| 198 | .driver = { | ||
| 199 | .name = DRIVER_NAME, | ||
| 200 | .owner = THIS_MODULE, | ||
| 201 | }, | ||
| 202 | .remove = __exit_p(u8500_cpufreq_remove), | ||
| 203 | }; | ||
| 204 | |||
| 205 | static int __init u8500_cpufreq_init(void) | ||
| 206 | { | ||
| 207 | return platform_driver_probe(&u8500_cpufreq_driver, | ||
| 208 | &u8500_cpufreq_probe); | ||
| 209 | } | ||
| 210 | |||
| 211 | device_initcall(u8500_cpufreq_init); | ||
diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c new file mode 100644 index 000000000000..fe69f5fac1bb --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 5 | * License terms: GNU General Public License (GPL), version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/dma-mapping.h> | ||
| 10 | #include <linux/err.h> | ||
| 11 | #include <linux/irq.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/amba/bus.h> | ||
| 15 | |||
| 16 | #include <plat/gpio.h> | ||
| 17 | |||
| 18 | #include <mach/hardware.h> | ||
| 19 | |||
| 20 | #include "devices-common.h" | ||
| 21 | |||
| 22 | struct amba_device * | ||
| 23 | dbx500_add_amba_device(const char *name, resource_size_t base, | ||
| 24 | int irq, void *pdata, unsigned int periphid) | ||
| 25 | { | ||
| 26 | struct amba_device *dev; | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | dev = kzalloc(sizeof *dev, GFP_KERNEL); | ||
| 30 | if (!dev) | ||
| 31 | return ERR_PTR(-ENOMEM); | ||
| 32 | |||
| 33 | dev->dev.init_name = name; | ||
| 34 | |||
| 35 | dev->res.start = base; | ||
| 36 | dev->res.end = base + SZ_4K - 1; | ||
| 37 | dev->res.flags = IORESOURCE_MEM; | ||
| 38 | |||
| 39 | dev->dma_mask = DMA_BIT_MASK(32); | ||
| 40 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
| 41 | |||
| 42 | dev->irq[0] = irq; | ||
| 43 | dev->irq[1] = NO_IRQ; | ||
| 44 | |||
| 45 | dev->periphid = periphid; | ||
| 46 | |||
| 47 | dev->dev.platform_data = pdata; | ||
| 48 | |||
| 49 | ret = amba_device_register(dev, &iomem_resource); | ||
| 50 | if (ret) { | ||
| 51 | kfree(dev); | ||
| 52 | return ERR_PTR(ret); | ||
| 53 | } | ||
| 54 | |||
| 55 | return dev; | ||
| 56 | } | ||
| 57 | |||
| 58 | static struct platform_device * | ||
| 59 | dbx500_add_platform_device(const char *name, int id, void *pdata, | ||
| 60 | struct resource *res, int resnum) | ||
| 61 | { | ||
| 62 | struct platform_device *dev; | ||
| 63 | int ret; | ||
| 64 | |||
| 65 | dev = platform_device_alloc(name, id); | ||
| 66 | if (!dev) | ||
| 67 | return ERR_PTR(-ENOMEM); | ||
| 68 | |||
| 69 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
| 70 | dev->dev.dma_mask = &dev->dev.coherent_dma_mask; | ||
| 71 | |||
| 72 | ret = platform_device_add_resources(dev, res, resnum); | ||
| 73 | if (ret) | ||
| 74 | goto out_free; | ||
| 75 | |||
| 76 | dev->dev.platform_data = pdata; | ||
| 77 | |||
| 78 | ret = platform_device_add(dev); | ||
| 79 | if (ret) | ||
| 80 | goto out_free; | ||
| 81 | |||
| 82 | return dev; | ||
| 83 | |||
| 84 | out_free: | ||
| 85 | platform_device_put(dev); | ||
| 86 | return ERR_PTR(ret); | ||
| 87 | } | ||
| 88 | |||
| 89 | struct platform_device * | ||
| 90 | dbx500_add_platform_device_4k1irq(const char *name, int id, | ||
| 91 | resource_size_t base, | ||
| 92 | int irq, void *pdata) | ||
| 93 | { | ||
| 94 | struct resource resources[] = { | ||
| 95 | [0] = { | ||
| 96 | .start = base, | ||
| 97 | .end = base + SZ_4K - 1, | ||
| 98 | .flags = IORESOURCE_MEM, | ||
| 99 | }, | ||
| 100 | [1] = { | ||
| 101 | .start = irq, | ||
| 102 | .end = irq, | ||
| 103 | .flags = IORESOURCE_IRQ, | ||
| 104 | } | ||
| 105 | }; | ||
| 106 | |||
| 107 | return dbx500_add_platform_device(name, id, pdata, resources, | ||
| 108 | ARRAY_SIZE(resources)); | ||
| 109 | } | ||
| 110 | |||
| 111 | static struct platform_device * | ||
| 112 | dbx500_add_gpio(int id, resource_size_t addr, int irq, | ||
| 113 | struct nmk_gpio_platform_data *pdata) | ||
| 114 | { | ||
| 115 | struct resource resources[] = { | ||
| 116 | { | ||
| 117 | .start = addr, | ||
| 118 | .end = addr + 127, | ||
| 119 | .flags = IORESOURCE_MEM, | ||
| 120 | }, | ||
| 121 | { | ||
| 122 | .start = irq, | ||
| 123 | .end = irq, | ||
| 124 | .flags = IORESOURCE_IRQ, | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | |||
| 128 | return platform_device_register_resndata(NULL, "gpio", id, | ||
| 129 | resources, ARRAY_SIZE(resources), | ||
| 130 | pdata, sizeof(*pdata)); | ||
| 131 | } | ||
| 132 | |||
| 133 | void dbx500_add_gpios(resource_size_t *base, int num, int irq, | ||
| 134 | struct nmk_gpio_platform_data *pdata) | ||
| 135 | { | ||
| 136 | int first = 0; | ||
| 137 | int i; | ||
| 138 | |||
| 139 | for (i = 0; i < num; i++, first += 32, irq++) { | ||
| 140 | pdata->first_gpio = first; | ||
| 141 | pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first); | ||
| 142 | |||
| 143 | dbx500_add_gpio(i, base[i], irq, pdata); | ||
| 144 | } | ||
| 145 | } | ||
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h new file mode 100644 index 000000000000..cbadc117d2db --- /dev/null +++ b/arch/arm/mach-ux500/devices-common.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 5 | * License terms: GNU General Public License (GPL), version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef __DEVICES_COMMON_H | ||
| 9 | #define __DEVICES_COMMON_H | ||
| 10 | |||
| 11 | extern struct amba_device * | ||
| 12 | dbx500_add_amba_device(const char *name, resource_size_t base, | ||
| 13 | int irq, void *pdata, unsigned int periphid); | ||
| 14 | |||
| 15 | extern struct platform_device * | ||
| 16 | dbx500_add_platform_device_4k1irq(const char *name, int id, | ||
| 17 | resource_size_t base, | ||
| 18 | int irq, void *pdata); | ||
| 19 | |||
| 20 | struct spi_master_cntlr; | ||
| 21 | |||
| 22 | static inline struct amba_device * | ||
| 23 | dbx500_add_msp_spi(const char *name, resource_size_t base, int irq, | ||
| 24 | struct spi_master_cntlr *pdata) | ||
| 25 | { | ||
| 26 | return dbx500_add_amba_device(name, base, irq, pdata, 0); | ||
| 27 | } | ||
| 28 | |||
| 29 | static inline struct amba_device * | ||
| 30 | dbx500_add_spi(const char *name, resource_size_t base, int irq, | ||
| 31 | struct spi_master_cntlr *pdata) | ||
| 32 | { | ||
| 33 | return dbx500_add_amba_device(name, base, irq, pdata, 0); | ||
| 34 | } | ||
| 35 | |||
| 36 | struct mmci_platform_data; | ||
| 37 | |||
| 38 | static inline struct amba_device * | ||
| 39 | dbx500_add_sdi(const char *name, resource_size_t base, int irq, | ||
| 40 | struct mmci_platform_data *pdata) | ||
| 41 | { | ||
| 42 | return dbx500_add_amba_device(name, base, irq, pdata, 0); | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline struct amba_device * | ||
| 46 | dbx500_add_uart(const char *name, resource_size_t base, int irq) | ||
| 47 | { | ||
| 48 | return dbx500_add_amba_device(name, base, irq, NULL, 0); | ||
| 49 | } | ||
| 50 | |||
| 51 | struct nmk_i2c_controller; | ||
| 52 | |||
| 53 | static inline struct platform_device * | ||
| 54 | dbx500_add_i2c(int id, resource_size_t base, int irq, | ||
| 55 | struct nmk_i2c_controller *pdata) | ||
| 56 | { | ||
| 57 | return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq, | ||
| 58 | pdata); | ||
| 59 | } | ||
| 60 | |||
| 61 | struct msp_i2s_platform_data; | ||
| 62 | |||
| 63 | static inline struct platform_device * | ||
| 64 | dbx500_add_msp_i2s(int id, resource_size_t base, int irq, | ||
| 65 | struct msp_i2s_platform_data *pdata) | ||
| 66 | { | ||
| 67 | return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq, | ||
| 68 | pdata); | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline struct amba_device * | ||
| 72 | dbx500_add_rtc(resource_size_t base, int irq) | ||
| 73 | { | ||
| 74 | return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0); | ||
| 75 | } | ||
| 76 | |||
| 77 | struct nmk_gpio_platform_data; | ||
| 78 | |||
| 79 | void dbx500_add_gpios(resource_size_t *base, int num, int irq, | ||
| 80 | struct nmk_gpio_platform_data *pdata); | ||
| 81 | |||
| 82 | #endif | ||
diff --git a/arch/arm/mach-ux500/devices-db5500.c b/arch/arm/mach-ux500/devices-db5500.c deleted file mode 100644 index 33e5b56bebb6..000000000000 --- a/arch/arm/mach-ux500/devices-db5500.c +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 5 | * License terms: GNU General Public License (GPL) version 2 | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/platform_device.h> | ||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | |||
| 12 | #include <mach/hardware.h> | ||
| 13 | #include <mach/devices.h> | ||
| 14 | |||
| 15 | static struct nmk_gpio_platform_data u5500_gpio_data[] = { | ||
| 16 | GPIO_DATA("GPIO-0-31", 0), | ||
| 17 | GPIO_DATA("GPIO-32-63", 32), /* 36..63 not routed to pin */ | ||
| 18 | GPIO_DATA("GPIO-64-95", 64), /* 83..95 not routed to pin */ | ||
| 19 | GPIO_DATA("GPIO-96-127", 96), /* 102..127 not routed to pin */ | ||
| 20 | GPIO_DATA("GPIO-128-159", 128), /* 149..159 not routed to pin */ | ||
| 21 | GPIO_DATA("GPIO-160-191", 160), | ||
| 22 | GPIO_DATA("GPIO-192-223", 192), | ||
| 23 | GPIO_DATA("GPIO-224-255", 224), /* 228..255 not routed to pin */ | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct resource u5500_gpio_resources[] = { | ||
| 27 | GPIO_RESOURCE(0), | ||
| 28 | GPIO_RESOURCE(1), | ||
| 29 | GPIO_RESOURCE(2), | ||
| 30 | GPIO_RESOURCE(3), | ||
| 31 | GPIO_RESOURCE(4), | ||
| 32 | GPIO_RESOURCE(5), | ||
| 33 | GPIO_RESOURCE(6), | ||
| 34 | GPIO_RESOURCE(7), | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct platform_device u5500_gpio_devs[] = { | ||
| 38 | GPIO_DEVICE(0), | ||
| 39 | GPIO_DEVICE(1), | ||
| 40 | GPIO_DEVICE(2), | ||
| 41 | GPIO_DEVICE(3), | ||
| 42 | GPIO_DEVICE(4), | ||
| 43 | GPIO_DEVICE(5), | ||
| 44 | GPIO_DEVICE(6), | ||
| 45 | GPIO_DEVICE(7), | ||
| 46 | }; | ||
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h new file mode 100644 index 000000000000..c8d7901c1f2d --- /dev/null +++ b/arch/arm/mach-ux500/devices-db5500.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 5 | * License terms: GNU General Public License (GPL), version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef __DEVICES_DB5500_H | ||
| 9 | #define __DEVICES_DB5500_H | ||
| 10 | |||
| 11 | #include "devices-common.h" | ||
| 12 | |||
| 13 | #define db5500_add_i2c1(pdata) \ | ||
| 14 | dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata) | ||
| 15 | #define db5500_add_i2c2(pdata) \ | ||
| 16 | dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata) | ||
| 17 | #define db5500_add_i2c3(pdata) \ | ||
| 18 | dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata) | ||
| 19 | |||
| 20 | #define db5500_add_msp0_i2s(pdata) \ | ||
| 21 | dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) | ||
| 22 | #define db5500_add_msp1_i2s(pdata) \ | ||
| 23 | dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) | ||
| 24 | #define db5500_add_msp2_i2s(pdata) \ | ||
| 25 | dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) | ||
| 26 | |||
| 27 | #define db5500_add_msp0_spi(pdata) \ | ||
| 28 | dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata) | ||
| 29 | #define db5500_add_msp1_spi(pdata) \ | ||
| 30 | dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata) | ||
| 31 | #define db5500_add_msp2_spi(pdata) \ | ||
| 32 | dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata) | ||
| 33 | |||
| 34 | #define db5500_add_rtc() \ | ||
| 35 | dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC); | ||
| 36 | |||
| 37 | #define db5500_add_sdi0(pdata) \ | ||
| 38 | dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata) | ||
| 39 | #define db5500_add_sdi1(pdata) \ | ||
| 40 | dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata) | ||
| 41 | #define db5500_add_sdi2(pdata) \ | ||
| 42 | dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata) | ||
| 43 | #define db5500_add_sdi3(pdata) \ | ||
| 44 | dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata) | ||
| 45 | #define db5500_add_sdi4(pdata) \ | ||
| 46 | dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata) | ||
| 47 | |||
| 48 | #define db5500_add_spi0(pdata) \ | ||
| 49 | dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata) | ||
| 50 | #define db5500_add_spi1(pdata) \ | ||
| 51 | dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata) | ||
| 52 | #define db5500_add_spi2(pdata) \ | ||
| 53 | dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata) | ||
| 54 | #define db5500_add_spi3(pdata) \ | ||
| 55 | dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata) | ||
| 56 | |||
| 57 | #define db5500_add_uart0() \ | ||
| 58 | dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0) | ||
| 59 | #define db5500_add_uart1() \ | ||
| 60 | dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1) | ||
| 61 | #define db5500_add_uart2() \ | ||
| 62 | dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2) | ||
| 63 | #define db5500_add_uart3() \ | ||
| 64 | dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3) | ||
| 65 | |||
| 66 | #endif | ||
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c index 4a94be3304b9..23c695d54977 100644 --- a/arch/arm/mach-ux500/devices-db8500.c +++ b/arch/arm/mach-ux500/devices-db8500.c | |||
| @@ -19,173 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | #include "ste-dma40-db8500.h" | 20 | #include "ste-dma40-db8500.h" |
| 21 | 21 | ||
| 22 | static struct nmk_gpio_platform_data u8500_gpio_data[] = { | ||
| 23 | GPIO_DATA("GPIO-0-31", 0), | ||
| 24 | GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */ | ||
| 25 | GPIO_DATA("GPIO-64-95", 64), | ||
| 26 | GPIO_DATA("GPIO-96-127", 96), /* 98..127 not routed to pin */ | ||
| 27 | GPIO_DATA("GPIO-128-159", 128), | ||
| 28 | GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */ | ||
| 29 | GPIO_DATA("GPIO-192-223", 192), | ||
| 30 | GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */ | ||
| 31 | GPIO_DATA("GPIO-256-288", 256), /* 268..288 not routed to pin */ | ||
| 32 | }; | ||
| 33 | |||
| 34 | static struct resource u8500_gpio_resources[] = { | ||
| 35 | GPIO_RESOURCE(0), | ||
| 36 | GPIO_RESOURCE(1), | ||
| 37 | GPIO_RESOURCE(2), | ||
| 38 | GPIO_RESOURCE(3), | ||
| 39 | GPIO_RESOURCE(4), | ||
| 40 | GPIO_RESOURCE(5), | ||
| 41 | GPIO_RESOURCE(6), | ||
| 42 | GPIO_RESOURCE(7), | ||
| 43 | GPIO_RESOURCE(8), | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct platform_device u8500_gpio_devs[] = { | ||
| 47 | GPIO_DEVICE(0), | ||
| 48 | GPIO_DEVICE(1), | ||
| 49 | GPIO_DEVICE(2), | ||
| 50 | GPIO_DEVICE(3), | ||
| 51 | GPIO_DEVICE(4), | ||
| 52 | GPIO_DEVICE(5), | ||
| 53 | GPIO_DEVICE(6), | ||
| 54 | GPIO_DEVICE(7), | ||
| 55 | GPIO_DEVICE(8), | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct amba_device u8500_ssp0_device = { | ||
| 59 | .dev = { | ||
| 60 | .coherent_dma_mask = ~0, | ||
| 61 | .init_name = "ssp0", | ||
| 62 | }, | ||
| 63 | .res = { | ||
| 64 | .start = U8500_SSP0_BASE, | ||
| 65 | .end = U8500_SSP0_BASE + SZ_4K - 1, | ||
| 66 | .flags = IORESOURCE_MEM, | ||
| 67 | }, | ||
| 68 | .irq = {IRQ_DB8500_SSP0, NO_IRQ }, | ||
| 69 | /* ST-Ericsson modified id */ | ||
| 70 | .periphid = SSP_PER_ID, | ||
| 71 | }; | ||
| 72 | |||
| 73 | static struct resource u8500_i2c0_resources[] = { | ||
| 74 | [0] = { | ||
| 75 | .start = U8500_I2C0_BASE, | ||
| 76 | .end = U8500_I2C0_BASE + SZ_4K - 1, | ||
| 77 | .flags = IORESOURCE_MEM, | ||
| 78 | }, | ||
| 79 | [1] = { | ||
| 80 | .start = IRQ_DB8500_I2C0, | ||
| 81 | .end = IRQ_DB8500_I2C0, | ||
| 82 | .flags = IORESOURCE_IRQ, | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct platform_device u8500_i2c0_device = { | ||
| 87 | .name = "nmk-i2c", | ||
| 88 | .id = 0, | ||
| 89 | .resource = u8500_i2c0_resources, | ||
| 90 | .num_resources = ARRAY_SIZE(u8500_i2c0_resources), | ||
| 91 | }; | ||
| 92 | |||
| 93 | static struct resource u8500_i2c4_resources[] = { | ||
| 94 | [0] = { | ||
| 95 | .start = U8500_I2C4_BASE, | ||
| 96 | .end = U8500_I2C4_BASE + SZ_4K - 1, | ||
| 97 | .flags = IORESOURCE_MEM, | ||
| 98 | }, | ||
| 99 | [1] = { | ||
| 100 | .start = IRQ_DB8500_I2C4, | ||
| 101 | .end = IRQ_DB8500_I2C4, | ||
| 102 | .flags = IORESOURCE_IRQ, | ||
| 103 | } | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct platform_device u8500_i2c4_device = { | ||
| 107 | .name = "nmk-i2c", | ||
| 108 | .id = 4, | ||
| 109 | .resource = u8500_i2c4_resources, | ||
| 110 | .num_resources = ARRAY_SIZE(u8500_i2c4_resources), | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * SD/MMC | ||
| 115 | */ | ||
| 116 | |||
| 117 | struct amba_device u8500_sdi0_device = { | ||
| 118 | .dev = { | ||
| 119 | .init_name = "sdi0", | ||
| 120 | }, | ||
| 121 | .res = { | ||
| 122 | .start = U8500_SDI0_BASE, | ||
| 123 | .end = U8500_SDI0_BASE + SZ_4K - 1, | ||
| 124 | .flags = IORESOURCE_MEM, | ||
| 125 | }, | ||
| 126 | .irq = {IRQ_DB8500_SDMMC0, NO_IRQ}, | ||
| 127 | }; | ||
| 128 | |||
| 129 | struct amba_device u8500_sdi1_device = { | ||
| 130 | .dev = { | ||
| 131 | .init_name = "sdi1", | ||
| 132 | }, | ||
| 133 | .res = { | ||
| 134 | .start = U8500_SDI1_BASE, | ||
| 135 | .end = U8500_SDI1_BASE + SZ_4K - 1, | ||
| 136 | .flags = IORESOURCE_MEM, | ||
| 137 | }, | ||
| 138 | .irq = {IRQ_DB8500_SDMMC1, NO_IRQ}, | ||
| 139 | }; | ||
| 140 | |||
| 141 | struct amba_device u8500_sdi2_device = { | ||
| 142 | .dev = { | ||
| 143 | .init_name = "sdi2", | ||
| 144 | }, | ||
| 145 | .res = { | ||
| 146 | .start = U8500_SDI2_BASE, | ||
| 147 | .end = U8500_SDI2_BASE + SZ_4K - 1, | ||
| 148 | .flags = IORESOURCE_MEM, | ||
| 149 | }, | ||
| 150 | .irq = {IRQ_DB8500_SDMMC2, NO_IRQ}, | ||
| 151 | }; | ||
| 152 | |||
| 153 | struct amba_device u8500_sdi3_device = { | ||
| 154 | .dev = { | ||
| 155 | .init_name = "sdi3", | ||
| 156 | }, | ||
| 157 | .res = { | ||
| 158 | .start = U8500_SDI3_BASE, | ||
| 159 | .end = U8500_SDI3_BASE + SZ_4K - 1, | ||
| 160 | .flags = IORESOURCE_MEM, | ||
| 161 | }, | ||
| 162 | .irq = {IRQ_DB8500_SDMMC3, NO_IRQ}, | ||
| 163 | }; | ||
| 164 | |||
| 165 | struct amba_device u8500_sdi4_device = { | ||
| 166 | .dev = { | ||
| 167 | .init_name = "sdi4", | ||
| 168 | }, | ||
| 169 | .res = { | ||
| 170 | .start = U8500_SDI4_BASE, | ||
| 171 | .end = U8500_SDI4_BASE + SZ_4K - 1, | ||
| 172 | .flags = IORESOURCE_MEM, | ||
| 173 | }, | ||
| 174 | .irq = {IRQ_DB8500_SDMMC4, NO_IRQ}, | ||
| 175 | }; | ||
| 176 | |||
| 177 | struct amba_device u8500_sdi5_device = { | ||
| 178 | .dev = { | ||
| 179 | .init_name = "sdi5", | ||
| 180 | }, | ||
| 181 | .res = { | ||
| 182 | .start = U8500_SDI5_BASE, | ||
| 183 | .end = U8500_SDI5_BASE + SZ_4K - 1, | ||
| 184 | .flags = IORESOURCE_MEM, | ||
| 185 | }, | ||
| 186 | .irq = {IRQ_DB8500_SDMMC5, NO_IRQ}, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static struct resource dma40_resources[] = { | 22 | static struct resource dma40_resources[] = { |
| 190 | [0] = { | 23 | [0] = { |
| 191 | .start = U8500_DMA_BASE, | 24 | .start = U8500_DMA_BASE, |
| @@ -295,7 +128,7 @@ struct resource keypad_resources[] = { | |||
| 295 | }, | 128 | }, |
| 296 | }; | 129 | }; |
| 297 | 130 | ||
| 298 | struct platform_device ux500_ske_keypad_device = { | 131 | struct platform_device u8500_ske_keypad_device = { |
| 299 | .name = "nmk-ske-keypad", | 132 | .name = "nmk-ske-keypad", |
| 300 | .id = -1, | 133 | .id = -1, |
| 301 | .num_resources = ARRAY_SIZE(keypad_resources), | 134 | .num_resources = ARRAY_SIZE(keypad_resources), |
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h new file mode 100644 index 000000000000..3a770c756979 --- /dev/null +++ b/arch/arm/mach-ux500/devices-db8500.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 5 | * License terms: GNU General Public License (GPL), version 2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef __DEVICES_DB8500_H | ||
| 9 | #define __DEVICES_DB8500_H | ||
| 10 | |||
| 11 | #include "devices-common.h" | ||
| 12 | |||
| 13 | struct ske_keypad_platform_data; | ||
| 14 | struct pl022_ssp_controller; | ||
| 15 | |||
| 16 | static inline struct platform_device * | ||
| 17 | db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata) | ||
| 18 | { | ||
| 19 | return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1, | ||
| 20 | U8500_SKE_BASE, | ||
| 21 | IRQ_DB8500_KB, pdata); | ||
| 22 | } | ||
| 23 | |||
| 24 | static inline struct amba_device * | ||
| 25 | db8500_add_ssp(const char *name, resource_size_t base, int irq, | ||
| 26 | struct pl022_ssp_controller *pdata) | ||
| 27 | { | ||
| 28 | return dbx500_add_amba_device(name, base, irq, pdata, SSP_PER_ID); | ||
| 29 | } | ||
| 30 | |||
| 31 | |||
| 32 | #define db8500_add_i2c0(pdata) \ | ||
| 33 | dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata) | ||
| 34 | #define db8500_add_i2c1(pdata) \ | ||
| 35 | dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata) | ||
| 36 | #define db8500_add_i2c2(pdata) \ | ||
| 37 | dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata) | ||
| 38 | #define db8500_add_i2c3(pdata) \ | ||
| 39 | dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata) | ||
| 40 | #define db8500_add_i2c4(pdata) \ | ||
| 41 | dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata) | ||
| 42 | |||
| 43 | #define db8500_add_msp0_i2s(pdata) \ | ||
| 44 | dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) | ||
| 45 | #define db8500_add_msp1_i2s(pdata) \ | ||
| 46 | dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) | ||
| 47 | #define db8500_add_msp2_i2s(pdata) \ | ||
| 48 | dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) | ||
| 49 | #define db8500_add_msp3_i2s(pdata) \ | ||
| 50 | dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) | ||
| 51 | |||
| 52 | #define db8500_add_msp0_spi(pdata) \ | ||
| 53 | dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata) | ||
| 54 | #define db8500_add_msp1_spi(pdata) \ | ||
| 55 | dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata) | ||
| 56 | #define db8500_add_msp2_spi(pdata) \ | ||
| 57 | dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata) | ||
| 58 | #define db8500_add_msp3_spi(pdata) \ | ||
| 59 | dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata) | ||
| 60 | |||
| 61 | #define db8500_add_rtc() \ | ||
| 62 | dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC); | ||
| 63 | |||
| 64 | #define db8500_add_sdi0(pdata) \ | ||
| 65 | dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata) | ||
| 66 | #define db8500_add_sdi1(pdata) \ | ||
| 67 | dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata) | ||
| 68 | #define db8500_add_sdi2(pdata) \ | ||
| 69 | dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata) | ||
| 70 | #define db8500_add_sdi3(pdata) \ | ||
| 71 | dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata) | ||
| 72 | #define db8500_add_sdi4(pdata) \ | ||
| 73 | dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata) | ||
| 74 | #define db8500_add_sdi5(pdata) \ | ||
| 75 | dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata) | ||
| 76 | |||
| 77 | #define db8500_add_ssp0(pdata) \ | ||
| 78 | db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata) | ||
| 79 | #define db8500_add_ssp1(pdata) \ | ||
| 80 | db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata) | ||
| 81 | |||
| 82 | #define db8500_add_spi0(pdata) \ | ||
| 83 | dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata) | ||
| 84 | #define db8500_add_spi1(pdata) \ | ||
| 85 | dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata) | ||
| 86 | #define db8500_add_spi2(pdata) \ | ||
| 87 | dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata) | ||
| 88 | #define db8500_add_spi3(pdata) \ | ||
| 89 | dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata) | ||
| 90 | |||
| 91 | #define db8500_add_uart0() \ | ||
| 92 | dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0) | ||
| 93 | #define db8500_add_uart1() \ | ||
| 94 | dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1) | ||
| 95 | #define db8500_add_uart2() \ | ||
| 96 | dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2) | ||
| 97 | |||
| 98 | #endif | ||
diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c index 8a268893cb7f..ea0a2f92ca70 100644 --- a/arch/arm/mach-ux500/devices.c +++ b/arch/arm/mach-ux500/devices.c | |||
| @@ -14,69 +14,6 @@ | |||
| 14 | #include <mach/hardware.h> | 14 | #include <mach/hardware.h> |
| 15 | #include <mach/setup.h> | 15 | #include <mach/setup.h> |
| 16 | 16 | ||
| 17 | #define __MEM_4K_RESOURCE(x) \ | ||
| 18 | .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM} | ||
| 19 | |||
| 20 | struct amba_device ux500_pl031_device = { | ||
| 21 | .dev = { | ||
| 22 | .init_name = "pl031", | ||
| 23 | }, | ||
| 24 | .res = { | ||
| 25 | .start = UX500_RTC_BASE, | ||
| 26 | .end = UX500_RTC_BASE + SZ_4K - 1, | ||
| 27 | .flags = IORESOURCE_MEM, | ||
| 28 | }, | ||
| 29 | .irq = {IRQ_RTC_RTT, NO_IRQ}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct amba_device ux500_uart0_device = { | ||
| 33 | .dev = { .init_name = "uart0" }, | ||
| 34 | __MEM_4K_RESOURCE(UX500_UART0_BASE), | ||
| 35 | .irq = {IRQ_UART0, NO_IRQ}, | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct amba_device ux500_uart1_device = { | ||
| 39 | .dev = { .init_name = "uart1" }, | ||
| 40 | __MEM_4K_RESOURCE(UX500_UART1_BASE), | ||
| 41 | .irq = {IRQ_UART1, NO_IRQ}, | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct amba_device ux500_uart2_device = { | ||
| 45 | .dev = { .init_name = "uart2" }, | ||
| 46 | __MEM_4K_RESOURCE(UX500_UART2_BASE), | ||
| 47 | .irq = {IRQ_UART2, NO_IRQ}, | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define UX500_I2C_RESOURCES(id, size) \ | ||
| 51 | static struct resource ux500_i2c##id##_resources[] = { \ | ||
| 52 | [0] = { \ | ||
| 53 | .start = UX500_I2C##id##_BASE, \ | ||
| 54 | .end = UX500_I2C##id##_BASE + size - 1, \ | ||
| 55 | .flags = IORESOURCE_MEM, \ | ||
| 56 | }, \ | ||
| 57 | [1] = { \ | ||
| 58 | .start = IRQ_I2C##id, \ | ||
| 59 | .end = IRQ_I2C##id, \ | ||
| 60 | .flags = IORESOURCE_IRQ \ | ||
| 61 | } \ | ||
| 62 | } | ||
| 63 | |||
| 64 | UX500_I2C_RESOURCES(1, SZ_4K); | ||
| 65 | UX500_I2C_RESOURCES(2, SZ_4K); | ||
| 66 | UX500_I2C_RESOURCES(3, SZ_4K); | ||
| 67 | |||
| 68 | #define UX500_I2C_PDEVICE(cid) \ | ||
| 69 | struct platform_device ux500_i2c##cid##_device = { \ | ||
| 70 | .name = "nmk-i2c", \ | ||
| 71 | .id = cid, \ | ||
| 72 | .num_resources = 2, \ | ||
| 73 | .resource = ux500_i2c##cid##_resources, \ | ||
| 74 | } | ||
| 75 | |||
| 76 | UX500_I2C_PDEVICE(1); | ||
| 77 | UX500_I2C_PDEVICE(2); | ||
| 78 | UX500_I2C_PDEVICE(3); | ||
| 79 | |||
| 80 | void __init amba_add_devices(struct amba_device *devs[], int num) | 17 | void __init amba_add_devices(struct amba_device *devs[], int num) |
| 81 | { | 18 | { |
| 82 | int i; | 19 | int i; |
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c new file mode 100644 index 000000000000..32a061f8a95b --- /dev/null +++ b/arch/arm/mach-ux500/dma-db5500.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson | ||
| 5 | * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson | ||
| 7 | * | ||
| 8 | * License terms: GNU General Public License (GPL), version 2 | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | |||
| 14 | #include <plat/ste_dma40.h> | ||
| 15 | #include <mach/setup.h> | ||
| 16 | #include <mach/hardware.h> | ||
| 17 | |||
| 18 | #include "ste-dma40-db5500.h" | ||
| 19 | |||
| 20 | static struct resource dma40_resources[] = { | ||
| 21 | [0] = { | ||
| 22 | .start = U5500_DMA_BASE, | ||
| 23 | .end = U5500_DMA_BASE + SZ_4K - 1, | ||
| 24 | .flags = IORESOURCE_MEM, | ||
| 25 | .name = "base", | ||
| 26 | }, | ||
| 27 | [1] = { | ||
| 28 | .start = U5500_DMA_LCPA_BASE, | ||
| 29 | .end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1, | ||
| 30 | .flags = IORESOURCE_MEM, | ||
| 31 | .name = "lcpa", | ||
| 32 | }, | ||
| 33 | [2] = { | ||
| 34 | .start = IRQ_DB5500_DMA, | ||
| 35 | .end = IRQ_DB5500_DMA, | ||
| 36 | .flags = IORESOURCE_IRQ | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 40 | /* Default configuration for physical memcpy */ | ||
| 41 | static struct stedma40_chan_cfg dma40_memcpy_conf_phy = { | ||
| 42 | .mode = STEDMA40_MODE_PHYSICAL, | ||
| 43 | .dir = STEDMA40_MEM_TO_MEM, | ||
| 44 | |||
| 45 | .src_info.data_width = STEDMA40_BYTE_WIDTH, | ||
| 46 | .src_info.psize = STEDMA40_PSIZE_PHY_1, | ||
| 47 | .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, | ||
| 48 | |||
| 49 | .dst_info.data_width = STEDMA40_BYTE_WIDTH, | ||
| 50 | .dst_info.psize = STEDMA40_PSIZE_PHY_1, | ||
| 51 | .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* Default configuration for logical memcpy */ | ||
| 55 | static struct stedma40_chan_cfg dma40_memcpy_conf_log = { | ||
| 56 | .dir = STEDMA40_MEM_TO_MEM, | ||
| 57 | |||
| 58 | .src_info.data_width = STEDMA40_BYTE_WIDTH, | ||
| 59 | .src_info.psize = STEDMA40_PSIZE_LOG_1, | ||
| 60 | .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, | ||
| 61 | |||
| 62 | .dst_info.data_width = STEDMA40_BYTE_WIDTH, | ||
| 63 | .dst_info.psize = STEDMA40_PSIZE_LOG_1, | ||
| 64 | .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL, | ||
| 65 | }; | ||
| 66 | |||
| 67 | /* | ||
| 68 | * Mapping between soruce event lines and physical device address This was | ||
| 69 | * created assuming that the event line is tied to a device and therefore the | ||
| 70 | * address is constant, however this is not true for at least USB, and the | ||
| 71 | * values are just placeholders for USB. This table is preserved and used for | ||
| 72 | * now. | ||
| 73 | */ | ||
| 74 | static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = { | ||
| 75 | [DB5500_DMA_DEV24_SDMMC0_RX] = -1, | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* Mapping between destination event lines and physical device address */ | ||
| 79 | static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = { | ||
| 80 | [DB5500_DMA_DEV24_SDMMC0_TX] = -1, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static int dma40_memcpy_event[] = { | ||
| 84 | DB5500_DMA_MEMCPY_TX_1, | ||
| 85 | DB5500_DMA_MEMCPY_TX_2, | ||
| 86 | DB5500_DMA_MEMCPY_TX_3, | ||
| 87 | DB5500_DMA_MEMCPY_TX_4, | ||
| 88 | DB5500_DMA_MEMCPY_TX_5, | ||
| 89 | }; | ||
| 90 | |||
| 91 | static struct stedma40_platform_data dma40_plat_data = { | ||
| 92 | .dev_len = ARRAY_SIZE(dma40_rx_map), | ||
| 93 | .dev_rx = dma40_rx_map, | ||
| 94 | .dev_tx = dma40_tx_map, | ||
| 95 | .memcpy = dma40_memcpy_event, | ||
| 96 | .memcpy_len = ARRAY_SIZE(dma40_memcpy_event), | ||
| 97 | .memcpy_conf_phy = &dma40_memcpy_conf_phy, | ||
| 98 | .memcpy_conf_log = &dma40_memcpy_conf_log, | ||
| 99 | .disabled_channels = {-1}, | ||
| 100 | }; | ||
| 101 | |||
| 102 | static struct platform_device dma40_device = { | ||
| 103 | .dev = { | ||
| 104 | .platform_data = &dma40_plat_data, | ||
| 105 | }, | ||
| 106 | .name = "dma40", | ||
| 107 | .id = 0, | ||
| 108 | .num_resources = ARRAY_SIZE(dma40_resources), | ||
| 109 | .resource = dma40_resources | ||
| 110 | }; | ||
| 111 | |||
| 112 | void __init db5500_dma_init(void) | ||
| 113 | { | ||
| 114 | int ret; | ||
| 115 | |||
| 116 | ret = platform_device_register(&dma40_device); | ||
| 117 | if (ret) | ||
| 118 | dev_err(&dma40_device.dev, "unable to register device: %d\n", ret); | ||
| 119 | |||
| 120 | } | ||
diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h index 3eafc0e24ba5..bd88c1e74060 100644 --- a/arch/arm/mach-ux500/include/mach/db5500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db5500-regs.h | |||
| @@ -114,4 +114,8 @@ | |||
| 114 | #define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20) | 114 | #define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20) |
| 115 | #define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F) | 115 | #define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F) |
| 116 | 116 | ||
| 117 | #define U5500_ESRAM_BASE 0x40000000 | ||
| 118 | #define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000 | ||
| 119 | #define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET) | ||
| 120 | |||
| 117 | #endif | 121 | #endif |
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h index f07d0986409d..0fefb34c11e4 100644 --- a/arch/arm/mach-ux500/include/mach/db8500-regs.h +++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h | |||
| @@ -92,7 +92,8 @@ | |||
| 92 | #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) | 92 | #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) |
| 93 | #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) | 93 | #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) |
| 94 | #define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) | 94 | #define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) |
| 95 | #define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x0f000) | 95 | #define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000) |
| 96 | #define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000) | ||
| 96 | 97 | ||
| 97 | /* per3 base addresses */ | 98 | /* per3 base addresses */ |
| 98 | #define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000) | 99 | #define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000) |
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index b91a4d1211a2..020b6369a30a 100644 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h | |||
| @@ -14,27 +14,10 @@ extern struct platform_device u5500_gpio_devs[]; | |||
| 14 | extern struct platform_device u8500_gpio_devs[]; | 14 | extern struct platform_device u8500_gpio_devs[]; |
| 15 | 15 | ||
| 16 | extern struct amba_device ux500_pl031_device; | 16 | extern struct amba_device ux500_pl031_device; |
| 17 | extern struct amba_device u8500_ssp0_device; | ||
| 18 | extern struct amba_device ux500_uart0_device; | ||
| 19 | extern struct amba_device ux500_uart1_device; | ||
| 20 | extern struct amba_device ux500_uart2_device; | ||
| 21 | 17 | ||
| 22 | extern struct platform_device ux500_i2c1_device; | ||
| 23 | extern struct platform_device ux500_i2c2_device; | ||
| 24 | extern struct platform_device ux500_i2c3_device; | ||
| 25 | |||
| 26 | extern struct platform_device u8500_i2c0_device; | ||
| 27 | extern struct platform_device u8500_i2c4_device; | ||
| 28 | extern struct platform_device u8500_dma40_device; | 18 | extern struct platform_device u8500_dma40_device; |
| 29 | extern struct platform_device ux500_ske_keypad_device; | 19 | extern struct platform_device ux500_ske_keypad_device; |
| 30 | 20 | ||
| 31 | extern struct amba_device u8500_sdi0_device; | ||
| 32 | extern struct amba_device u8500_sdi1_device; | ||
| 33 | extern struct amba_device u8500_sdi2_device; | ||
| 34 | extern struct amba_device u8500_sdi3_device; | ||
| 35 | extern struct amba_device u8500_sdi4_device; | ||
| 36 | extern struct amba_device u8500_sdi5_device; | ||
| 37 | |||
| 38 | void dma40_u8500ed_fixup(void); | 21 | void dma40_u8500ed_fixup(void); |
| 39 | 22 | ||
| 40 | #endif | 23 | #endif |
diff --git a/arch/arm/mach-ux500/include/mach/gpio.h b/arch/arm/mach-ux500/include/mach/gpio.h index d548a622e7d2..3c4cd31ad9f7 100644 --- a/arch/arm/mach-ux500/include/mach/gpio.h +++ b/arch/arm/mach-ux500/include/mach/gpio.h | |||
| @@ -9,42 +9,4 @@ | |||
| 9 | 9 | ||
| 10 | #include <plat/gpio.h> | 10 | #include <plat/gpio.h> |
| 11 | 11 | ||
| 12 | #define __GPIO_RESOURCE(soc, block) \ | ||
| 13 | { \ | ||
| 14 | .start = soc##_GPIOBANK##block##_BASE, \ | ||
| 15 | .end = soc##_GPIOBANK##block##_BASE + 127, \ | ||
| 16 | .flags = IORESOURCE_MEM, \ | ||
| 17 | }, \ | ||
| 18 | { \ | ||
| 19 | .start = IRQ_GPIO##block, \ | ||
| 20 | .end = IRQ_GPIO##block, \ | ||
| 21 | .flags = IORESOURCE_IRQ, \ | ||
| 22 | } | ||
| 23 | |||
| 24 | #define __GPIO_DEVICE(soc, block) \ | ||
| 25 | { \ | ||
| 26 | .name = "gpio", \ | ||
| 27 | .id = block, \ | ||
| 28 | .num_resources = 2, \ | ||
| 29 | .resource = &soc##_gpio_resources[block * 2], \ | ||
| 30 | .dev = { \ | ||
| 31 | .platform_data = &soc##_gpio_data[block], \ | ||
| 32 | }, \ | ||
| 33 | } | ||
| 34 | |||
| 35 | #define GPIO_DATA(_name, first) \ | ||
| 36 | { \ | ||
| 37 | .name = _name, \ | ||
| 38 | .first_gpio = first, \ | ||
| 39 | .first_irq = NOMADIK_GPIO_TO_IRQ(first), \ | ||
| 40 | } | ||
| 41 | |||
| 42 | #ifdef CONFIG_UX500_SOC_DB8500 | ||
| 43 | #define GPIO_RESOURCE(block) __GPIO_RESOURCE(U8500, block) | ||
| 44 | #define GPIO_DEVICE(block) __GPIO_DEVICE(u8500, block) | ||
| 45 | #elif defined(CONFIG_UX500_SOC_DB5500) | ||
| 46 | #define GPIO_RESOURCE(block) __GPIO_RESOURCE(U5500, block) | ||
| 47 | #define GPIO_DEVICE(block) __GPIO_DEVICE(u5500, block) | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #endif /* __ASM_ARCH_GPIO_H */ | 12 | #endif /* __ASM_ARCH_GPIO_H */ |
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h index 32e883a8f2a2..6295cc581355 100644 --- a/arch/arm/mach-ux500/include/mach/hardware.h +++ b/arch/arm/mach-ux500/include/mach/hardware.h | |||
| @@ -142,6 +142,8 @@ static inline bool cpu_is_u5500(void) | |||
| 142 | #endif | 142 | #endif |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | ||
| 146 | |||
| 145 | #endif | 147 | #endif |
| 146 | 148 | ||
| 147 | #endif /* __MACH_HARDWARE_H */ | 149 | #endif /* __MACH_HARDWARE_H */ |
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h index cca4f705601e..7cdeb2af0ebb 100644 --- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h +++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h | |||
| @@ -8,12 +8,36 @@ | |||
| 8 | #ifndef __MACH_IRQS_BOARD_MOP500_H | 8 | #ifndef __MACH_IRQS_BOARD_MOP500_H |
| 9 | #define __MACH_IRQS_BOARD_MOP500_H | 9 | #define __MACH_IRQS_BOARD_MOP500_H |
| 10 | 10 | ||
| 11 | #define AB8500_NR_IRQS 104 | 11 | /* Number of AB8500 irqs is taken from header file */ |
| 12 | #include <linux/mfd/ab8500.h> | ||
| 12 | 13 | ||
| 13 | #define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START | 14 | #define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START |
| 14 | #define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ | 15 | #define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ |
| 15 | + AB8500_NR_IRQS) | 16 | + AB8500_NR_IRQS) |
| 16 | #define MOP500_IRQ_END MOP500_AB8500_IRQ_END | 17 | |
| 18 | /* TC35892 */ | ||
| 19 | #define TC35892_NR_INTERNAL_IRQS 8 | ||
| 20 | #define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x)) | ||
| 21 | #define TC35892_NR_GPIOS 24 | ||
| 22 | #define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS) | ||
| 23 | |||
| 24 | #define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS | ||
| 25 | |||
| 26 | #define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END | ||
| 27 | #define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \ | ||
| 28 | + MOP500_EGPIO_NR_IRQS) | ||
| 29 | /* STMPE1601 irqs */ | ||
| 30 | #define STMPE_NR_INTERNAL_IRQS 9 | ||
| 31 | #define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x)) | ||
| 32 | #define STMPE_NR_GPIOS 24 | ||
| 33 | #define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS) | ||
| 34 | |||
| 35 | #define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END | ||
| 36 | #define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) | ||
| 37 | |||
| 38 | #define MOP500_NR_IRQS MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) | ||
| 39 | |||
| 40 | #define MOP500_IRQ_END MOP500_NR_IRQS | ||
| 17 | 41 | ||
| 18 | #if MOP500_IRQ_END > IRQ_BOARD_END | 42 | #if MOP500_IRQ_END > IRQ_BOARD_END |
| 19 | #undef IRQ_BOARD_END | 43 | #undef IRQ_BOARD_END |
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h index 693aa57de88d..880ae45bc235 100644 --- a/arch/arm/mach-ux500/include/mach/irqs.h +++ b/arch/arm/mach-ux500/include/mach/irqs.h | |||
| @@ -21,50 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | /* Interrupt numbers generic for shared peripheral */ | 22 | /* Interrupt numbers generic for shared peripheral */ |
| 23 | #define IRQ_MTU0 (IRQ_SHPI_START + 4) | 23 | #define IRQ_MTU0 (IRQ_SHPI_START + 4) |
| 24 | #define IRQ_SPI2 (IRQ_SHPI_START + 6) | ||
| 25 | #define IRQ_SPI0 (IRQ_SHPI_START + 8) | ||
| 26 | #define IRQ_UART0 (IRQ_SHPI_START + 11) | ||
| 27 | #define IRQ_I2C3 (IRQ_SHPI_START + 12) | ||
| 28 | #define IRQ_SSP0 (IRQ_SHPI_START + 14) | ||
| 29 | #define IRQ_MTU1 (IRQ_SHPI_START + 17) | ||
| 30 | #define IRQ_RTC_RTT (IRQ_SHPI_START + 18) | ||
| 31 | #define IRQ_UART1 (IRQ_SHPI_START + 19) | ||
| 32 | #define IRQ_I2C0 (IRQ_SHPI_START + 21) | ||
| 33 | #define IRQ_I2C1 (IRQ_SHPI_START + 22) | ||
| 34 | #define IRQ_USBOTG (IRQ_SHPI_START + 23) | ||
| 35 | #define IRQ_DMA (IRQ_SHPI_START + 25) | ||
| 36 | #define IRQ_UART2 (IRQ_SHPI_START + 26) | ||
| 37 | #define IRQ_HSIR_EXCEP (IRQ_SHPI_START + 29) | ||
| 38 | #define IRQ_MSP0 (IRQ_SHPI_START + 31) | ||
| 39 | #define IRQ_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32) | ||
| 40 | #define IRQ_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33) | ||
| 41 | #define IRQ_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34) | ||
| 42 | #define IRQ_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35) | ||
| 43 | #define IRQ_AB8500 (IRQ_SHPI_START + 40) | ||
| 44 | #define IRQ_PRCMU (IRQ_SHPI_START + 47) | ||
| 45 | #define IRQ_DISP (IRQ_SHPI_START + 48) | ||
| 46 | #define IRQ_SiPI3 (IRQ_SHPI_START + 49) | ||
| 47 | #define IRQ_I2C4 (IRQ_SHPI_START + 51) | ||
| 48 | #define IRQ_SSP1 (IRQ_SHPI_START + 52) | ||
| 49 | #define IRQ_I2C2 (IRQ_SHPI_START + 55) | ||
| 50 | #define IRQ_SDMMC0 (IRQ_SHPI_START + 60) | ||
| 51 | #define IRQ_MSP1 (IRQ_SHPI_START + 62) | ||
| 52 | #define IRQ_SPI1 (IRQ_SHPI_START + 96) | ||
| 53 | #define IRQ_MSP2 (IRQ_SHPI_START + 98) | ||
| 54 | #define IRQ_SDMMC4 (IRQ_SHPI_START + 99) | ||
| 55 | #define IRQ_HSIRD0 (IRQ_SHPI_START + 104) | ||
| 56 | #define IRQ_HSIRD1 (IRQ_SHPI_START + 105) | ||
| 57 | #define IRQ_HSITD0 (IRQ_SHPI_START + 106) | ||
| 58 | #define IRQ_HSITD1 (IRQ_SHPI_START + 107) | ||
| 59 | #define IRQ_GPIO0 (IRQ_SHPI_START + 119) | ||
| 60 | #define IRQ_GPIO1 (IRQ_SHPI_START + 120) | ||
| 61 | #define IRQ_GPIO2 (IRQ_SHPI_START + 121) | ||
| 62 | #define IRQ_GPIO3 (IRQ_SHPI_START + 122) | ||
| 63 | #define IRQ_GPIO4 (IRQ_SHPI_START + 123) | ||
| 64 | #define IRQ_GPIO5 (IRQ_SHPI_START + 124) | ||
| 65 | #define IRQ_GPIO6 (IRQ_SHPI_START + 125) | ||
| 66 | #define IRQ_GPIO7 (IRQ_SHPI_START + 126) | ||
| 67 | #define IRQ_GPIO8 (IRQ_SHPI_START + 127) | ||
| 68 | 24 | ||
| 69 | /* There are 128 shared peripheral interrupts assigned to | 25 | /* There are 128 shared peripheral interrupts assigned to |
| 70 | * INTID[160:32]. The first 32 interrupts are reserved. | 26 | * INTID[160:32]. The first 32 interrupts are reserved. |
diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h index 7f9da4d2fbda..7f9da4d2fbda 100644 --- a/arch/arm/mach-ux500/include/mach/mbox.h +++ b/arch/arm/mach-ux500/include/mach/mbox-db5500.h | |||
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-defs.h b/arch/arm/mach-ux500/include/mach/prcmu-defs.h new file mode 100644 index 000000000000..848ba64b561f --- /dev/null +++ b/arch/arm/mach-ux500/include/mach/prcmu-defs.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) STMicroelectronics 2009 | ||
| 3 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 4 | * | ||
| 5 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 6 | * Author: Martin Persson <martin.persson@stericsson.com> | ||
| 7 | * | ||
| 8 | * License Terms: GNU General Public License v2 | ||
| 9 | * | ||
| 10 | * PRCM Unit definitions | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef __MACH_PRCMU_DEFS_H | ||
| 14 | #define __MACH_PRCMU_DEFS_H | ||
| 15 | |||
| 16 | enum prcmu_cpu_opp { | ||
| 17 | CPU_OPP_INIT = 0x00, | ||
| 18 | CPU_OPP_NO_CHANGE = 0x01, | ||
| 19 | CPU_OPP_100 = 0x02, | ||
| 20 | CPU_OPP_50 = 0x03, | ||
| 21 | CPU_OPP_MAX = 0x04, | ||
| 22 | CPU_OPP_EXT_CLK = 0x07 | ||
| 23 | }; | ||
| 24 | enum prcmu_ape_opp { | ||
| 25 | APE_OPP_NO_CHANGE = 0x00, | ||
| 26 | APE_OPP_100 = 0x02, | ||
| 27 | APE_OPP_50 = 0x03, | ||
| 28 | }; | ||
| 29 | |||
| 30 | #endif /* __MACH_PRCMU_DEFS_H */ | ||
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h index 8885f39a6421..455467e88791 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu-regs.h +++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h | |||
| @@ -1,10 +1,15 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2009 ST-Ericsson SA | 2 | * Copyright (C) STMicroelectronics 2009 |
| 3 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | 4 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 5 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> |
| 5 | * it under the terms of the GNU General Public License version 2 | 6 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> |
| 6 | * as published by the Free Software Foundation. | 7 | * |
| 8 | * License Terms: GNU General Public License v2 | ||
| 9 | * | ||
| 10 | * PRCM Unit registers | ||
| 7 | */ | 11 | */ |
| 12 | |||
| 8 | #ifndef __MACH_PRCMU_REGS_H | 13 | #ifndef __MACH_PRCMU_REGS_H |
| 9 | #define __MACH_PRCMU_REGS_H | 14 | #define __MACH_PRCMU_REGS_H |
| 10 | 15 | ||
| @@ -88,4 +93,4 @@ | |||
| 88 | /* Miscellaneous unit registers */ | 93 | /* Miscellaneous unit registers */ |
| 89 | #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) | 94 | #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) |
| 90 | 95 | ||
| 91 | #endif /* __MACH_PRCMU__REGS_H */ | 96 | #endif /* __MACH_PRCMU_REGS_H */ |
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h index 549843ff6dbe..c49e456162ef 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu.h +++ b/arch/arm/mach-ux500/include/mach/prcmu.h | |||
| @@ -2,14 +2,27 @@ | |||
| 2 | * Copyright (C) STMicroelectronics 2009 | 2 | * Copyright (C) STMicroelectronics 2009 |
| 3 | * Copyright (C) ST-Ericsson SA 2010 | 3 | * Copyright (C) ST-Ericsson SA 2010 |
| 4 | * | 4 | * |
| 5 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> | ||
| 6 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 7 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | ||
| 8 | * | ||
| 5 | * License Terms: GNU General Public License v2 | 9 | * License Terms: GNU General Public License v2 |
| 6 | * | 10 | * |
| 7 | * PRCMU f/w APIs | 11 | * PRCM Unit f/w API |
| 8 | */ | 12 | */ |
| 9 | #ifndef __MACH_PRCMU_H | 13 | #ifndef __MACH_PRCMU_H |
| 10 | #define __MACH_PRCMU_H | 14 | #define __MACH_PRCMU_H |
| 15 | #include <mach/prcmu-defs.h> | ||
| 11 | 16 | ||
| 17 | void __init prcmu_early_init(void); | ||
| 12 | int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); | 18 | int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); |
| 13 | int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); | 19 | int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); |
| 20 | int prcmu_set_ape_opp(enum prcmu_ape_opp opp); | ||
| 21 | int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp); | ||
| 22 | int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp, | ||
| 23 | enum prcmu_cpu_opp cpu_opp); | ||
| 24 | int prcmu_get_ape_opp(void); | ||
| 25 | int prcmu_get_cpu_opp(void); | ||
| 26 | bool prcmu_has_arm_maxopp(void); | ||
| 14 | 27 | ||
| 15 | #endif /* __MACH_PRCMU_H */ | 28 | #endif /* __MACH_PRCMU_H */ |
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index 54bbe648bf58..469877e0de90 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h | |||
| @@ -18,14 +18,19 @@ extern void __init ux500_map_io(void); | |||
| 18 | extern void __init u5500_map_io(void); | 18 | extern void __init u5500_map_io(void); |
| 19 | extern void __init u8500_map_io(void); | 19 | extern void __init u8500_map_io(void); |
| 20 | 20 | ||
| 21 | extern void __init ux500_init_devices(void); | ||
| 22 | extern void __init u5500_init_devices(void); | 21 | extern void __init u5500_init_devices(void); |
| 23 | extern void __init u8500_init_devices(void); | 22 | extern void __init u8500_init_devices(void); |
| 24 | 23 | ||
| 25 | extern void __init ux500_init_irq(void); | 24 | extern void __init ux500_init_irq(void); |
| 25 | |||
| 26 | extern void __init u5500_sdi_init(void); | ||
| 27 | |||
| 28 | extern void __init db5500_dma_init(void); | ||
| 29 | |||
| 26 | /* We re-use nomadik_timer for this platform */ | 30 | /* We re-use nomadik_timer for this platform */ |
| 27 | extern void nmdk_timer_init(void); | 31 | extern void nmdk_timer_init(void); |
| 28 | 32 | ||
| 33 | struct amba_device; | ||
| 29 | extern void __init amba_add_devices(struct amba_device *devs[], int num); | 34 | extern void __init amba_add_devices(struct amba_device *devs[], int num); |
| 30 | 35 | ||
| 31 | struct sys_timer; | 36 | struct sys_timer; |
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h index 0271ca0a83df..9a6614c6808e 100644 --- a/arch/arm/mach-ux500/include/mach/uncompress.h +++ b/arch/arm/mach-ux500/include/mach/uncompress.h | |||
| @@ -19,38 +19,43 @@ | |||
| 19 | #define __ASM_ARCH_UNCOMPRESS_H | 19 | #define __ASM_ARCH_UNCOMPRESS_H |
| 20 | 20 | ||
| 21 | #include <asm/setup.h> | 21 | #include <asm/setup.h> |
| 22 | #include <asm/mach-types.h> | ||
| 22 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <linux/amba/serial.h> | ||
| 23 | #include <mach/hardware.h> | 25 | #include <mach/hardware.h> |
| 24 | 26 | ||
| 25 | #define U8500_UART_DR 0x80007000 | 27 | static u32 ux500_uart_base; |
| 26 | #define U8500_UART_LCRH 0x8000702c | ||
| 27 | #define U8500_UART_CR 0x80007030 | ||
| 28 | #define U8500_UART_FR 0x80007018 | ||
| 29 | 28 | ||
| 30 | static void putc(const char c) | 29 | static void putc(const char c) |
| 31 | { | 30 | { |
| 32 | /* Do nothing if the UART is not enabled. */ | 31 | /* Do nothing if the UART is not enabled. */ |
| 33 | if (!(__raw_readb(U8500_UART_CR) & 0x1)) | 32 | if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) |
| 34 | return; | 33 | return; |
| 35 | 34 | ||
| 36 | if (c == '\n') | 35 | if (c == '\n') |
| 37 | putc('\r'); | 36 | putc('\r'); |
| 38 | 37 | ||
| 39 | while (__raw_readb(U8500_UART_FR) & (1 << 5)) | 38 | while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 5)) |
| 40 | barrier(); | 39 | barrier(); |
| 41 | __raw_writeb(c, U8500_UART_DR); | 40 | __raw_writeb(c, ux500_uart_base + UART01x_DR); |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | static void flush(void) | 43 | static void flush(void) |
| 45 | { | 44 | { |
| 46 | if (!(__raw_readb(U8500_UART_CR) & 0x1)) | 45 | if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1)) |
| 47 | return; | 46 | return; |
| 48 | while (__raw_readb(U8500_UART_FR) & (1 << 3)) | 47 | while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 3)) |
| 49 | barrier(); | 48 | barrier(); |
| 50 | } | 49 | } |
| 51 | 50 | ||
| 52 | static inline void arch_decomp_setup(void) | 51 | static inline void arch_decomp_setup(void) |
| 53 | { | 52 | { |
| 53 | if (machine_is_u8500()) | ||
| 54 | ux500_uart_base = U8500_UART2_BASE; | ||
| 55 | else if (machine_is_u5500()) | ||
| 56 | ux500_uart_base = U5500_UART0_BASE; | ||
| 57 | else /* not much can be done to help here */ | ||
| 58 | ux500_uart_base = U8500_UART2_BASE; | ||
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | #define arch_decomp_wdog() /* nothing to do here */ | 61 | #define arch_decomp_wdog() /* nothing to do here */ |
diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox-db5500.c index 63435389c544..cbf15718fc3c 100644 --- a/arch/arm/mach-ux500/mbox.c +++ b/arch/arm/mach-ux500/mbox-db5500.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
| 39 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
| 40 | #include <linux/completion.h> | 40 | #include <linux/completion.h> |
| 41 | #include <mach/mbox.h> | 41 | #include <mach/mbox-db5500.h> |
| 42 | 42 | ||
| 43 | #define MBOX_NAME "mbox" | 43 | #define MBOX_NAME "mbox" |
| 44 | 44 | ||
diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem-irq-db5500.c index 3187f8871169..3187f8871169 100644 --- a/arch/arm/mach-ux500/modem_irq.c +++ b/arch/arm/mach-ux500/modem-irq-db5500.c | |||
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de785..ade2e17f253c 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | * control for which core is the next to come out of the secondary | 26 | * control for which core is the next to come out of the secondary |
| 27 | * boot "holding pen" | 27 | * boot "holding pen" |
| 28 | */ | 28 | */ |
| 29 | volatile int __cpuinitdata pen_release = -1; | 29 | volatile int pen_release = -1; |
| 30 | 30 | ||
| 31 | static unsigned int __init get_core_count(void) | 31 | static unsigned int __init get_core_count(void) |
| 32 | { | 32 | { |
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c index 293274d1342a..c522d26ef348 100644 --- a/arch/arm/mach-ux500/prcmu.c +++ b/arch/arm/mach-ux500/prcmu.c | |||
| @@ -1,10 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) ST Ericsson SA 2010 | 2 | * Copyright (C) STMicroelectronics 2009 |
| 3 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | 4 | * |
| 4 | * License Terms: GNU General Public License v2 | 5 | * License Terms: GNU General Public License v2 |
| 6 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> | ||
| 7 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 5 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | 8 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> |
| 6 | * | 9 | * |
| 7 | * U8500 PRCMU driver. | 10 | * U8500 PRCM Unit interface driver |
| 11 | * | ||
| 8 | */ | 12 | */ |
| 9 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 10 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| @@ -19,11 +23,26 @@ | |||
| 19 | 23 | ||
| 20 | #include <mach/hardware.h> | 24 | #include <mach/hardware.h> |
| 21 | #include <mach/prcmu-regs.h> | 25 | #include <mach/prcmu-regs.h> |
| 26 | #include <mach/prcmu-defs.h> | ||
| 27 | |||
| 28 | /* Global var to runtime determine TCDM base for v2 or v1 */ | ||
| 29 | static __iomem void *tcdm_base; | ||
| 30 | |||
| 31 | #define _MBOX_HEADER (tcdm_base + 0xFE8) | ||
| 32 | #define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0) | ||
| 33 | |||
| 34 | #define REQ_MB1 (tcdm_base + 0xFD0) | ||
| 35 | #define REQ_MB5 (tcdm_base + 0xE44) | ||
| 22 | 36 | ||
| 23 | #define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE) | 37 | #define REQ_MB1_ARMOPP (REQ_MB1 + 0x0) |
| 38 | #define REQ_MB1_APEOPP (REQ_MB1 + 0x1) | ||
| 39 | #define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2) | ||
| 24 | 40 | ||
| 25 | #define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44) | 41 | #define ACK_MB1 (tcdm_base + 0xE04) |
| 26 | #define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4) | 42 | #define ACK_MB5 (tcdm_base + 0xDF4) |
| 43 | |||
| 44 | #define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0) | ||
| 45 | #define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1) | ||
| 27 | 46 | ||
| 28 | #define REQ_MB5_I2C_SLAVE_OP (REQ_MB5) | 47 | #define REQ_MB5_I2C_SLAVE_OP (REQ_MB5) |
| 29 | #define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1) | 48 | #define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1) |
| @@ -33,10 +52,33 @@ | |||
| 33 | #define ACK_MB5_I2C_STATUS (ACK_MB5 + 1) | 52 | #define ACK_MB5_I2C_STATUS (ACK_MB5 + 1) |
| 34 | #define ACK_MB5_I2C_VAL (ACK_MB5 + 3) | 53 | #define ACK_MB5_I2C_VAL (ACK_MB5 + 3) |
| 35 | 54 | ||
| 36 | #define I2C_WRITE(slave) ((slave) << 1) | 55 | #define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4) |
| 37 | #define I2C_READ(slave) (((slave) << 1) | BIT(0)) | 56 | #define PRCM_AVS_ISMODEENABLE 7 |
| 57 | #define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE) | ||
| 58 | |||
| 59 | #define I2C_WRITE(slave) \ | ||
| 60 | (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) | ||
| 61 | #define I2C_READ(slave) \ | ||
| 62 | (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0)) | ||
| 38 | #define I2C_STOP_EN BIT(3) | 63 | #define I2C_STOP_EN BIT(3) |
| 39 | 64 | ||
| 65 | enum mb1_h { | ||
| 66 | MB1H_ARM_OPP = 1, | ||
| 67 | MB1H_APE_OPP, | ||
| 68 | MB1H_ARM_APE_OPP, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static struct { | ||
| 72 | struct mutex lock; | ||
| 73 | struct completion work; | ||
| 74 | struct { | ||
| 75 | u8 arm_opp; | ||
| 76 | u8 ape_opp; | ||
| 77 | u8 arm_status; | ||
| 78 | u8 ape_status; | ||
| 79 | } ack; | ||
| 80 | } mb1_transfer; | ||
| 81 | |||
| 40 | enum ack_mb5_status { | 82 | enum ack_mb5_status { |
| 41 | I2C_WR_OK = 0x01, | 83 | I2C_WR_OK = 0x01, |
| 42 | I2C_RD_OK = 0x02, | 84 | I2C_RD_OK = 0x02, |
| @@ -145,6 +187,104 @@ unlock_and_return: | |||
| 145 | } | 187 | } |
| 146 | EXPORT_SYMBOL(prcmu_abb_write); | 188 | EXPORT_SYMBOL(prcmu_abb_write); |
| 147 | 189 | ||
| 190 | static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp, | ||
| 191 | enum prcmu_cpu_opp cpu_opp) | ||
| 192 | { | ||
| 193 | bool do_ape; | ||
| 194 | bool do_arm; | ||
| 195 | int err = 0; | ||
| 196 | |||
| 197 | do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP)); | ||
| 198 | do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP)); | ||
| 199 | |||
| 200 | mutex_lock(&mb1_transfer.lock); | ||
| 201 | |||
| 202 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) | ||
| 203 | cpu_relax(); | ||
| 204 | |||
| 205 | writeb(0, MBOX_HEADER_REQ_MB0); | ||
| 206 | writeb(cpu_opp, REQ_MB1_ARMOPP); | ||
| 207 | writeb(ape_opp, REQ_MB1_APEOPP); | ||
| 208 | writeb(0, REQ_MB1_BOOSTOPP); | ||
| 209 | writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET); | ||
| 210 | wait_for_completion(&mb1_transfer.work); | ||
| 211 | if ((do_ape) && (mb1_transfer.ack.ape_status != 0)) | ||
| 212 | err = -EIO; | ||
| 213 | if ((do_arm) && (mb1_transfer.ack.arm_status != 0)) | ||
| 214 | err = -EIO; | ||
| 215 | |||
| 216 | mutex_unlock(&mb1_transfer.lock); | ||
| 217 | |||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | /** | ||
| 222 | * prcmu_set_ape_opp() - Set the OPP of the APE. | ||
| 223 | * @opp: The OPP to set. | ||
| 224 | * | ||
| 225 | * This function sets the OPP of the APE. | ||
| 226 | */ | ||
| 227 | int prcmu_set_ape_opp(enum prcmu_ape_opp opp) | ||
| 228 | { | ||
| 229 | return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE); | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL(prcmu_set_ape_opp); | ||
| 232 | |||
| 233 | /** | ||
| 234 | * prcmu_set_cpu_opp() - Set the OPP of the CPU. | ||
| 235 | * @opp: The OPP to set. | ||
| 236 | * | ||
| 237 | * This function sets the OPP of the CPU. | ||
| 238 | */ | ||
| 239 | int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp) | ||
| 240 | { | ||
| 241 | return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp); | ||
| 242 | } | ||
| 243 | EXPORT_SYMBOL(prcmu_set_cpu_opp); | ||
| 244 | |||
| 245 | /** | ||
| 246 | * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU. | ||
| 247 | * @ape_opp: The APE OPP to set. | ||
| 248 | * @cpu_opp: The CPU OPP to set. | ||
| 249 | * | ||
| 250 | * This function sets the OPPs of the APE and the CPU. | ||
| 251 | */ | ||
| 252 | int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp, | ||
| 253 | enum prcmu_cpu_opp cpu_opp) | ||
| 254 | { | ||
| 255 | return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp); | ||
| 256 | } | ||
| 257 | EXPORT_SYMBOL(prcmu_set_ape_cpu_opps); | ||
| 258 | |||
| 259 | /** | ||
| 260 | * prcmu_get_ape_opp() - Get the OPP of the APE. | ||
| 261 | * | ||
| 262 | * This function gets the OPP of the APE. | ||
| 263 | */ | ||
| 264 | enum prcmu_ape_opp prcmu_get_ape_opp(void) | ||
| 265 | { | ||
| 266 | return readb(ACK_MB1_CURR_APEOPP); | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(prcmu_get_ape_opp); | ||
| 269 | |||
| 270 | /** | ||
| 271 | * prcmu_get_cpu_opp() - Get the OPP of the CPU. | ||
| 272 | * | ||
| 273 | * This function gets the OPP of the CPU. The OPP is specified in %%. | ||
| 274 | * PRCMU_OPP_EXT is a special OPP value, not specified in %%. | ||
| 275 | */ | ||
| 276 | int prcmu_get_cpu_opp(void) | ||
| 277 | { | ||
| 278 | return readb(ACK_MB1_CURR_ARMOPP); | ||
| 279 | } | ||
| 280 | EXPORT_SYMBOL(prcmu_get_cpu_opp); | ||
| 281 | |||
| 282 | bool prcmu_has_arm_maxopp(void) | ||
| 283 | { | ||
| 284 | return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK) | ||
| 285 | == PRCM_AVS_ISMODEENABLE_MASK; | ||
| 286 | } | ||
| 287 | |||
| 148 | static void read_mailbox_0(void) | 288 | static void read_mailbox_0(void) |
| 149 | { | 289 | { |
| 150 | writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); | 290 | writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); |
| @@ -152,6 +292,9 @@ static void read_mailbox_0(void) | |||
| 152 | 292 | ||
| 153 | static void read_mailbox_1(void) | 293 | static void read_mailbox_1(void) |
| 154 | { | 294 | { |
| 295 | mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP); | ||
| 296 | mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP); | ||
| 297 | complete(&mb1_transfer.work); | ||
| 155 | writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); | 298 | writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); |
| 156 | } | 299 | } |
| 157 | 300 | ||
| @@ -217,15 +360,35 @@ static irqreturn_t prcmu_irq_handler(int irq, void *data) | |||
| 217 | return IRQ_HANDLED; | 360 | return IRQ_HANDLED; |
| 218 | } | 361 | } |
| 219 | 362 | ||
| 363 | void __init prcmu_early_init(void) | ||
| 364 | { | ||
| 365 | if (cpu_is_u8500v11() || cpu_is_u8500ed()) { | ||
| 366 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1); | ||
| 367 | } else if (cpu_is_u8500v2()) { | ||
| 368 | tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); | ||
| 369 | } else { | ||
| 370 | pr_err("prcmu: Unsupported chip version\n"); | ||
| 371 | BUG(); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 220 | static int __init prcmu_init(void) | 375 | static int __init prcmu_init(void) |
| 221 | { | 376 | { |
| 377 | if (cpu_is_u8500ed()) { | ||
| 378 | pr_err("prcmu: Unsupported chip version\n"); | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | mutex_init(&mb1_transfer.lock); | ||
| 383 | init_completion(&mb1_transfer.work); | ||
| 222 | mutex_init(&mb5_transfer.lock); | 384 | mutex_init(&mb5_transfer.lock); |
| 223 | init_completion(&mb5_transfer.work); | 385 | init_completion(&mb5_transfer.work); |
| 224 | 386 | ||
| 225 | /* Clean up the mailbox interrupts after pre-kernel code. */ | 387 | /* Clean up the mailbox interrupts after pre-kernel code. */ |
| 226 | writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR); | 388 | writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR); |
| 227 | 389 | ||
| 228 | return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL); | 390 | return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0, |
| 391 | "prcmu", NULL); | ||
| 229 | } | 392 | } |
| 230 | 393 | ||
| 231 | arch_initcall(prcmu_init); | 394 | arch_initcall(prcmu_init); |
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c index 85e6fd212a41..eda4e3a11a3d 100644 --- a/arch/arm/plat-nomadik/gpio.c +++ b/arch/arm/plat-nomadik/gpio.c | |||
| @@ -119,7 +119,7 @@ static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, | |||
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | 121 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, |
| 122 | pin_cfg_t cfg) | 122 | pin_cfg_t cfg, bool sleep) |
| 123 | { | 123 | { |
| 124 | static const char *afnames[] = { | 124 | static const char *afnames[] = { |
| 125 | [NMK_GPIO_ALT_GPIO] = "GPIO", | 125 | [NMK_GPIO_ALT_GPIO] = "GPIO", |
| @@ -145,11 +145,34 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | |||
| 145 | int output = PIN_DIR(cfg); | 145 | int output = PIN_DIR(cfg); |
| 146 | int val = PIN_VAL(cfg); | 146 | int val = PIN_VAL(cfg); |
| 147 | 147 | ||
| 148 | dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n", | 148 | dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n", |
| 149 | pin, afnames[af], pullnames[pull], slpmnames[slpm], | 149 | pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm], |
| 150 | output ? "output " : "input", | 150 | output ? "output " : "input", |
| 151 | output ? (val ? "high" : "low") : ""); | 151 | output ? (val ? "high" : "low") : ""); |
| 152 | 152 | ||
| 153 | if (sleep) { | ||
| 154 | int slpm_pull = PIN_SLPM_PULL(cfg); | ||
| 155 | int slpm_output = PIN_SLPM_DIR(cfg); | ||
| 156 | int slpm_val = PIN_SLPM_VAL(cfg); | ||
| 157 | |||
| 158 | /* | ||
| 159 | * The SLPM_* values are normal values + 1 to allow zero to | ||
| 160 | * mean "same as normal". | ||
| 161 | */ | ||
| 162 | if (slpm_pull) | ||
| 163 | pull = slpm_pull - 1; | ||
| 164 | if (slpm_output) | ||
| 165 | output = slpm_output - 1; | ||
| 166 | if (slpm_val) | ||
| 167 | val = slpm_val - 1; | ||
| 168 | |||
| 169 | dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", | ||
| 170 | pin, | ||
| 171 | slpm_pull ? pullnames[pull] : "same", | ||
| 172 | slpm_output ? (output ? "output" : "input") : "same", | ||
| 173 | slpm_val ? (val ? "high" : "low") : "same"); | ||
| 174 | } | ||
| 175 | |||
| 153 | if (output) | 176 | if (output) |
| 154 | __nmk_gpio_make_output(nmk_chip, offset, val); | 177 | __nmk_gpio_make_output(nmk_chip, offset, val); |
| 155 | else { | 178 | else { |
| @@ -175,7 +198,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | |||
| 175 | * side-effects. The gpio can be manipulated later using standard GPIO API | 198 | * side-effects. The gpio can be manipulated later using standard GPIO API |
| 176 | * calls. | 199 | * calls. |
| 177 | */ | 200 | */ |
| 178 | int nmk_config_pin(pin_cfg_t cfg) | 201 | int nmk_config_pin(pin_cfg_t cfg, bool sleep) |
| 179 | { | 202 | { |
| 180 | struct nmk_gpio_chip *nmk_chip; | 203 | struct nmk_gpio_chip *nmk_chip; |
| 181 | int gpio = PIN_NUM(cfg); | 204 | int gpio = PIN_NUM(cfg); |
| @@ -186,7 +209,7 @@ int nmk_config_pin(pin_cfg_t cfg) | |||
| 186 | return -EINVAL; | 209 | return -EINVAL; |
| 187 | 210 | ||
| 188 | spin_lock_irqsave(&nmk_chip->lock, flags); | 211 | spin_lock_irqsave(&nmk_chip->lock, flags); |
| 189 | __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg); | 212 | __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep); |
| 190 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | 213 | spin_unlock_irqrestore(&nmk_chip->lock, flags); |
| 191 | 214 | ||
| 192 | return 0; | 215 | return 0; |
| @@ -207,7 +230,7 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num) | |||
| 207 | int i; | 230 | int i; |
| 208 | 231 | ||
| 209 | for (i = 0; i < num; i++) { | 232 | for (i = 0; i < num; i++) { |
| 210 | int ret = nmk_config_pin(cfgs[i]); | 233 | ret = nmk_config_pin(cfgs[i], false); |
| 211 | if (ret) | 234 | if (ret) |
| 212 | break; | 235 | break; |
| 213 | } | 236 | } |
| @@ -216,6 +239,21 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num) | |||
| 216 | } | 239 | } |
| 217 | EXPORT_SYMBOL(nmk_config_pins); | 240 | EXPORT_SYMBOL(nmk_config_pins); |
| 218 | 241 | ||
| 242 | int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num) | ||
| 243 | { | ||
| 244 | int ret = 0; | ||
| 245 | int i; | ||
| 246 | |||
| 247 | for (i = 0; i < num; i++) { | ||
| 248 | ret = nmk_config_pin(cfgs[i], true); | ||
| 249 | if (ret) | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | |||
| 253 | return ret; | ||
| 254 | } | ||
| 255 | EXPORT_SYMBOL(nmk_config_pins_sleep); | ||
| 256 | |||
| 219 | /** | 257 | /** |
| 220 | * nmk_gpio_set_slpm() - configure the sleep mode of a pin | 258 | * nmk_gpio_set_slpm() - configure the sleep mode of a pin |
| 221 | * @gpio: pin number | 259 | * @gpio: pin number |
| @@ -634,7 +672,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) | |||
| 634 | 672 | ||
| 635 | chip = &nmk_chip->chip; | 673 | chip = &nmk_chip->chip; |
| 636 | chip->base = pdata->first_gpio; | 674 | chip->base = pdata->first_gpio; |
| 637 | chip->label = pdata->name; | 675 | chip->label = pdata->name ?: dev_name(&dev->dev); |
| 638 | chip->dev = &dev->dev; | 676 | chip->dev = &dev->dev; |
| 639 | chip->owner = THIS_MODULE; | 677 | chip->owner = THIS_MODULE; |
| 640 | 678 | ||
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h index 8c5ae3f2acf8..05a3936ae6d1 100644 --- a/arch/arm/plat-nomadik/include/plat/pincfg.h +++ b/arch/arm/plat-nomadik/include/plat/pincfg.h | |||
| @@ -19,16 +19,22 @@ | |||
| 19 | * bit 9..10 - Alternate Function Selection | 19 | * bit 9..10 - Alternate Function Selection |
| 20 | * bit 11..12 - Pull up/down state | 20 | * bit 11..12 - Pull up/down state |
| 21 | * bit 13 - Sleep mode behaviour | 21 | * bit 13 - Sleep mode behaviour |
| 22 | * bit 14 - (sleep mode) Direction | 22 | * bit 14 - Direction |
| 23 | * bit 15 - (sleep mode) Value (if output) | 23 | * bit 15 - Value (if output) |
| 24 | * bit 16..18 - SLPM pull up/down state | ||
| 25 | * bit 19..20 - SLPM direction | ||
| 26 | * bit 21..22 - SLPM Value (if output) | ||
| 24 | * | 27 | * |
| 25 | * to facilitate the definition, the following macros are provided | 28 | * to facilitate the definition, the following macros are provided |
| 26 | * | 29 | * |
| 27 | * PIN_CFG_DEFAULT - default config (0): | 30 | * PIN_CFG_DEFAULT - default config (0): |
| 28 | * pull up/down = disabled | 31 | * pull up/down = disabled |
| 29 | * sleep mode = input/wakeup | 32 | * sleep mode = input/wakeup |
| 30 | * (sleep mode) direction = input | 33 | * direction = input |
| 31 | * (sleep mode) value = low | 34 | * value = low |
| 35 | * SLPM direction = same as normal | ||
| 36 | * SLPM pull = same as normal | ||
| 37 | * SLPM value = same as normal | ||
| 32 | * | 38 | * |
| 33 | * PIN_CFG - default config with alternate function | 39 | * PIN_CFG - default config with alternate function |
| 34 | * PIN_CFG_PULL - default config with alternate function and pull up/down | 40 | * PIN_CFG_PULL - default config with alternate function and pull up/down |
| @@ -75,30 +81,64 @@ typedef unsigned long pin_cfg_t; | |||
| 75 | #define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) | 81 | #define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) |
| 76 | #define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) | 82 | #define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) |
| 77 | 83 | ||
| 78 | /* Shortcuts. Use these instead of separate DIR and VAL. */ | 84 | #define PIN_SLPM_PULL_SHIFT 16 |
| 79 | #define PIN_INPUT PIN_DIR_INPUT | 85 | #define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) |
| 86 | #define PIN_SLPM_PULL(x) \ | ||
| 87 | (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) | ||
| 88 | #define PIN_SLPM_PULL_NONE \ | ||
| 89 | ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) | ||
| 90 | #define PIN_SLPM_PULL_UP \ | ||
| 91 | ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) | ||
| 92 | #define PIN_SLPM_PULL_DOWN \ | ||
| 93 | ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) | ||
| 94 | |||
| 95 | #define PIN_SLPM_DIR_SHIFT 19 | ||
| 96 | #define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) | ||
| 97 | #define PIN_SLPM_DIR(x) \ | ||
| 98 | (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) | ||
| 99 | #define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) | ||
| 100 | #define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) | ||
| 101 | |||
| 102 | #define PIN_SLPM_VAL_SHIFT 21 | ||
| 103 | #define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) | ||
| 104 | #define PIN_SLPM_VAL(x) \ | ||
| 105 | (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) | ||
| 106 | #define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) | ||
| 107 | #define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) | ||
| 108 | |||
| 109 | /* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ | ||
| 110 | #define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) | ||
| 111 | #define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) | ||
| 112 | #define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) | ||
| 80 | #define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) | 113 | #define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) |
| 81 | #define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) | 114 | #define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) |
| 82 | 115 | ||
| 83 | /* | 116 | #define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) |
| 84 | * These are the same as the ones above, but should make more sense to the | 117 | #define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) |
| 85 | * reader when seen along with a setting a pin to AF mode. | 118 | #define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) |
| 86 | */ | 119 | #define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) |
| 87 | #define PIN_SLPM_INPUT PIN_INPUT | 120 | #define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) |
| 88 | #define PIN_SLPM_OUTPUT_LOW PIN_OUTPUT_LOW | ||
| 89 | #define PIN_SLPM_OUTPUT_HIGH PIN_OUTPUT_HIGH | ||
| 90 | 121 | ||
| 91 | #define PIN_CFG_DEFAULT (PIN_PULL_NONE | PIN_SLPM_INPUT) | 122 | #define PIN_CFG_DEFAULT (0) |
| 92 | 123 | ||
| 93 | #define PIN_CFG(num, alt) \ | 124 | #define PIN_CFG(num, alt) \ |
| 94 | (PIN_CFG_DEFAULT |\ | 125 | (PIN_CFG_DEFAULT |\ |
| 95 | (PIN_NUM(num) | PIN_##alt)) | 126 | (PIN_NUM(num) | PIN_##alt)) |
| 96 | 127 | ||
| 128 | #define PIN_CFG_INPUT(num, alt, pull) \ | ||
| 129 | (PIN_CFG_DEFAULT |\ | ||
| 130 | (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) | ||
| 131 | |||
| 132 | #define PIN_CFG_OUTPUT(num, alt, val) \ | ||
| 133 | (PIN_CFG_DEFAULT |\ | ||
| 134 | (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) | ||
| 135 | |||
| 97 | #define PIN_CFG_PULL(num, alt, pull) \ | 136 | #define PIN_CFG_PULL(num, alt, pull) \ |
| 98 | ((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\ | 137 | ((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\ |
| 99 | (PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull)) | 138 | (PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull)) |
| 100 | 139 | ||
| 101 | extern int nmk_config_pin(pin_cfg_t cfg); | 140 | extern int nmk_config_pin(pin_cfg_t cfg, bool sleep); |
| 102 | extern int nmk_config_pins(pin_cfg_t *cfgs, int num); | 141 | extern int nmk_config_pins(pin_cfg_t *cfgs, int num); |
| 142 | extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num); | ||
| 103 | 143 | ||
| 104 | #endif | 144 | #endif |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3143ac795eb0..082495bb08a7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
| @@ -230,11 +230,11 @@ config GPIO_STMPE | |||
| 230 | This enables support for the GPIOs found on the STMPE I/O | 230 | This enables support for the GPIOs found on the STMPE I/O |
| 231 | Expanders. | 231 | Expanders. |
| 232 | 232 | ||
| 233 | config GPIO_TC35892 | 233 | config GPIO_TC3589X |
| 234 | bool "TC35892 GPIOs" | 234 | bool "TC3589X GPIOs" |
| 235 | depends on MFD_TC35892 | 235 | depends on MFD_TC3589X |
| 236 | help | 236 | help |
| 237 | This enables support for the GPIOs found on the TC35892 | 237 | This enables support for the GPIOs found on the TC3589X |
| 238 | I/O Expander. | 238 | I/O Expander. |
| 239 | 239 | ||
| 240 | config GPIO_TWL4030 | 240 | config GPIO_TWL4030 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bdf3ddec0652..39bfd7a37650 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
| @@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o | |||
| 24 | obj-$(CONFIG_GPIO_PCH) += pch_gpio.o | 24 | obj-$(CONFIG_GPIO_PCH) += pch_gpio.o |
| 25 | obj-$(CONFIG_GPIO_PL061) += pl061.o | 25 | obj-$(CONFIG_GPIO_PL061) += pl061.o |
| 26 | obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o | 26 | obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o |
| 27 | obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o | 27 | obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o |
| 28 | obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o | 28 | obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o |
| 29 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o | 29 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o |
| 30 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o | 30 | obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o |
diff --git a/drivers/gpio/tc35892-gpio.c b/drivers/gpio/tc35892-gpio.c deleted file mode 100644 index 7e10c935a047..000000000000 --- a/drivers/gpio/tc35892-gpio.c +++ /dev/null | |||
| @@ -1,389 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/gpio.h> | ||
| 14 | #include <linux/irq.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/mfd/tc35892.h> | ||
| 17 | |||
| 18 | /* | ||
| 19 | * These registers are modified under the irq bus lock and cached to avoid | ||
| 20 | * unnecessary writes in bus_sync_unlock. | ||
| 21 | */ | ||
| 22 | enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; | ||
| 23 | |||
| 24 | #define CACHE_NR_REGS 4 | ||
| 25 | #define CACHE_NR_BANKS 3 | ||
| 26 | |||
| 27 | struct tc35892_gpio { | ||
| 28 | struct gpio_chip chip; | ||
| 29 | struct tc35892 *tc35892; | ||
| 30 | struct device *dev; | ||
| 31 | struct mutex irq_lock; | ||
| 32 | |||
| 33 | int irq_base; | ||
| 34 | |||
| 35 | /* Caches of interrupt control registers for bus_lock */ | ||
| 36 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
| 37 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip) | ||
| 41 | { | ||
| 42 | return container_of(chip, struct tc35892_gpio, chip); | ||
| 43 | } | ||
| 44 | |||
| 45 | static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
| 46 | { | ||
| 47 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
| 48 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 49 | u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; | ||
| 50 | u8 mask = 1 << (offset % 8); | ||
| 51 | int ret; | ||
| 52 | |||
| 53 | ret = tc35892_reg_read(tc35892, reg); | ||
| 54 | if (ret < 0) | ||
| 55 | return ret; | ||
| 56 | |||
| 57 | return ret & mask; | ||
| 58 | } | ||
| 59 | |||
| 60 | static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
| 61 | { | ||
| 62 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
| 63 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 64 | u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; | ||
| 65 | unsigned pos = offset % 8; | ||
| 66 | u8 data[] = {!!val << pos, 1 << pos}; | ||
| 67 | |||
| 68 | tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data); | ||
| 69 | } | ||
| 70 | |||
| 71 | static int tc35892_gpio_direction_output(struct gpio_chip *chip, | ||
| 72 | unsigned offset, int val) | ||
| 73 | { | ||
| 74 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
| 75 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 76 | u8 reg = TC35892_GPIODIR0 + offset / 8; | ||
| 77 | unsigned pos = offset % 8; | ||
| 78 | |||
| 79 | tc35892_gpio_set(chip, offset, val); | ||
| 80 | |||
| 81 | return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int tc35892_gpio_direction_input(struct gpio_chip *chip, | ||
| 85 | unsigned offset) | ||
| 86 | { | ||
| 87 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
| 88 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 89 | u8 reg = TC35892_GPIODIR0 + offset / 8; | ||
| 90 | unsigned pos = offset % 8; | ||
| 91 | |||
| 92 | return tc35892_set_bits(tc35892, reg, 1 << pos, 0); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 96 | { | ||
| 97 | struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); | ||
| 98 | |||
| 99 | return tc35892_gpio->irq_base + offset; | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct gpio_chip template_chip = { | ||
| 103 | .label = "tc35892", | ||
| 104 | .owner = THIS_MODULE, | ||
| 105 | .direction_input = tc35892_gpio_direction_input, | ||
| 106 | .get = tc35892_gpio_get, | ||
| 107 | .direction_output = tc35892_gpio_direction_output, | ||
| 108 | .set = tc35892_gpio_set, | ||
| 109 | .to_irq = tc35892_gpio_to_irq, | ||
| 110 | .can_sleep = 1, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
| 114 | { | ||
| 115 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
| 116 | int offset = irq - tc35892_gpio->irq_base; | ||
| 117 | int regoffset = offset / 8; | ||
| 118 | int mask = 1 << (offset % 8); | ||
| 119 | |||
| 120 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
| 121 | tc35892_gpio->regs[REG_IBE][regoffset] |= mask; | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask; | ||
| 126 | |||
| 127 | if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) | ||
| 128 | tc35892_gpio->regs[REG_IS][regoffset] |= mask; | ||
| 129 | else | ||
| 130 | tc35892_gpio->regs[REG_IS][regoffset] &= ~mask; | ||
| 131 | |||
| 132 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) | ||
| 133 | tc35892_gpio->regs[REG_IEV][regoffset] |= mask; | ||
| 134 | else | ||
| 135 | tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask; | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static void tc35892_gpio_irq_lock(unsigned int irq) | ||
| 141 | { | ||
| 142 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
| 143 | |||
| 144 | mutex_lock(&tc35892_gpio->irq_lock); | ||
| 145 | } | ||
| 146 | |||
| 147 | static void tc35892_gpio_irq_sync_unlock(unsigned int irq) | ||
| 148 | { | ||
| 149 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
| 150 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 151 | static const u8 regmap[] = { | ||
| 152 | [REG_IBE] = TC35892_GPIOIBE0, | ||
| 153 | [REG_IEV] = TC35892_GPIOIEV0, | ||
| 154 | [REG_IS] = TC35892_GPIOIS0, | ||
| 155 | [REG_IE] = TC35892_GPIOIE0, | ||
| 156 | }; | ||
| 157 | int i, j; | ||
| 158 | |||
| 159 | for (i = 0; i < CACHE_NR_REGS; i++) { | ||
| 160 | for (j = 0; j < CACHE_NR_BANKS; j++) { | ||
| 161 | u8 old = tc35892_gpio->oldregs[i][j]; | ||
| 162 | u8 new = tc35892_gpio->regs[i][j]; | ||
| 163 | |||
| 164 | if (new == old) | ||
| 165 | continue; | ||
| 166 | |||
| 167 | tc35892_gpio->oldregs[i][j] = new; | ||
| 168 | tc35892_reg_write(tc35892, regmap[i] + j * 8, new); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | mutex_unlock(&tc35892_gpio->irq_lock); | ||
| 173 | } | ||
| 174 | |||
| 175 | static void tc35892_gpio_irq_mask(unsigned int irq) | ||
| 176 | { | ||
| 177 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
| 178 | int offset = irq - tc35892_gpio->irq_base; | ||
| 179 | int regoffset = offset / 8; | ||
| 180 | int mask = 1 << (offset % 8); | ||
| 181 | |||
| 182 | tc35892_gpio->regs[REG_IE][regoffset] &= ~mask; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void tc35892_gpio_irq_unmask(unsigned int irq) | ||
| 186 | { | ||
| 187 | struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); | ||
| 188 | int offset = irq - tc35892_gpio->irq_base; | ||
| 189 | int regoffset = offset / 8; | ||
| 190 | int mask = 1 << (offset % 8); | ||
| 191 | |||
| 192 | tc35892_gpio->regs[REG_IE][regoffset] |= mask; | ||
| 193 | } | ||
| 194 | |||
| 195 | static struct irq_chip tc35892_gpio_irq_chip = { | ||
| 196 | .name = "tc35892-gpio", | ||
| 197 | .bus_lock = tc35892_gpio_irq_lock, | ||
| 198 | .bus_sync_unlock = tc35892_gpio_irq_sync_unlock, | ||
| 199 | .mask = tc35892_gpio_irq_mask, | ||
| 200 | .unmask = tc35892_gpio_irq_unmask, | ||
| 201 | .set_type = tc35892_gpio_irq_set_type, | ||
| 202 | }; | ||
| 203 | |||
| 204 | static irqreturn_t tc35892_gpio_irq(int irq, void *dev) | ||
| 205 | { | ||
| 206 | struct tc35892_gpio *tc35892_gpio = dev; | ||
| 207 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 208 | u8 status[CACHE_NR_BANKS]; | ||
| 209 | int ret; | ||
| 210 | int i; | ||
| 211 | |||
| 212 | ret = tc35892_block_read(tc35892, TC35892_GPIOMIS0, | ||
| 213 | ARRAY_SIZE(status), status); | ||
| 214 | if (ret < 0) | ||
| 215 | return IRQ_NONE; | ||
| 216 | |||
| 217 | for (i = 0; i < ARRAY_SIZE(status); i++) { | ||
| 218 | unsigned int stat = status[i]; | ||
| 219 | if (!stat) | ||
| 220 | continue; | ||
| 221 | |||
| 222 | while (stat) { | ||
| 223 | int bit = __ffs(stat); | ||
| 224 | int line = i * 8 + bit; | ||
| 225 | |||
| 226 | handle_nested_irq(tc35892_gpio->irq_base + line); | ||
| 227 | stat &= ~(1 << bit); | ||
| 228 | } | ||
| 229 | |||
| 230 | tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]); | ||
| 231 | } | ||
| 232 | |||
| 233 | return IRQ_HANDLED; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio) | ||
| 237 | { | ||
| 238 | int base = tc35892_gpio->irq_base; | ||
| 239 | int irq; | ||
| 240 | |||
| 241 | for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { | ||
| 242 | set_irq_chip_data(irq, tc35892_gpio); | ||
| 243 | set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip, | ||
| 244 | handle_simple_irq); | ||
| 245 | set_irq_nested_thread(irq, 1); | ||
| 246 | #ifdef CONFIG_ARM | ||
| 247 | set_irq_flags(irq, IRQF_VALID); | ||
| 248 | #else | ||
| 249 | set_irq_noprobe(irq); | ||
| 250 | #endif | ||
| 251 | } | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void tc35892_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio) | ||
| 257 | { | ||
| 258 | int base = tc35892_gpio->irq_base; | ||
| 259 | int irq; | ||
| 260 | |||
| 261 | for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { | ||
| 262 | #ifdef CONFIG_ARM | ||
| 263 | set_irq_flags(irq, 0); | ||
| 264 | #endif | ||
| 265 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
| 266 | set_irq_chip_data(irq, NULL); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | static int __devinit tc35892_gpio_probe(struct platform_device *pdev) | ||
| 271 | { | ||
| 272 | struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent); | ||
| 273 | struct tc35892_gpio_platform_data *pdata; | ||
| 274 | struct tc35892_gpio *tc35892_gpio; | ||
| 275 | int ret; | ||
| 276 | int irq; | ||
| 277 | |||
| 278 | pdata = tc35892->pdata->gpio; | ||
| 279 | if (!pdata) | ||
| 280 | return -ENODEV; | ||
| 281 | |||
| 282 | irq = platform_get_irq(pdev, 0); | ||
| 283 | if (irq < 0) | ||
| 284 | return irq; | ||
| 285 | |||
| 286 | tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL); | ||
| 287 | if (!tc35892_gpio) | ||
| 288 | return -ENOMEM; | ||
| 289 | |||
| 290 | mutex_init(&tc35892_gpio->irq_lock); | ||
| 291 | |||
| 292 | tc35892_gpio->dev = &pdev->dev; | ||
| 293 | tc35892_gpio->tc35892 = tc35892; | ||
| 294 | |||
| 295 | tc35892_gpio->chip = template_chip; | ||
| 296 | tc35892_gpio->chip.ngpio = tc35892->num_gpio; | ||
| 297 | tc35892_gpio->chip.dev = &pdev->dev; | ||
| 298 | tc35892_gpio->chip.base = pdata->gpio_base; | ||
| 299 | |||
| 300 | tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0); | ||
| 301 | |||
| 302 | /* Bring the GPIO module out of reset */ | ||
| 303 | ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL, | ||
| 304 | TC35892_RSTCTRL_GPIRST, 0); | ||
| 305 | if (ret < 0) | ||
| 306 | goto out_free; | ||
| 307 | |||
| 308 | ret = tc35892_gpio_irq_init(tc35892_gpio); | ||
| 309 | if (ret) | ||
| 310 | goto out_free; | ||
| 311 | |||
| 312 | ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT, | ||
| 313 | "tc35892-gpio", tc35892_gpio); | ||
| 314 | if (ret) { | ||
| 315 | dev_err(&pdev->dev, "unable to get irq: %d\n", ret); | ||
| 316 | goto out_removeirq; | ||
| 317 | } | ||
| 318 | |||
| 319 | ret = gpiochip_add(&tc35892_gpio->chip); | ||
| 320 | if (ret) { | ||
| 321 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); | ||
| 322 | goto out_freeirq; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (pdata->setup) | ||
| 326 | pdata->setup(tc35892, tc35892_gpio->chip.base); | ||
| 327 | |||
| 328 | platform_set_drvdata(pdev, tc35892_gpio); | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | |||
| 332 | out_freeirq: | ||
| 333 | free_irq(irq, tc35892_gpio); | ||
| 334 | out_removeirq: | ||
| 335 | tc35892_gpio_irq_remove(tc35892_gpio); | ||
| 336 | out_free: | ||
| 337 | kfree(tc35892_gpio); | ||
| 338 | return ret; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int __devexit tc35892_gpio_remove(struct platform_device *pdev) | ||
| 342 | { | ||
| 343 | struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev); | ||
| 344 | struct tc35892 *tc35892 = tc35892_gpio->tc35892; | ||
| 345 | struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio; | ||
| 346 | int irq = platform_get_irq(pdev, 0); | ||
| 347 | int ret; | ||
| 348 | |||
| 349 | if (pdata->remove) | ||
| 350 | pdata->remove(tc35892, tc35892_gpio->chip.base); | ||
| 351 | |||
| 352 | ret = gpiochip_remove(&tc35892_gpio->chip); | ||
| 353 | if (ret < 0) { | ||
| 354 | dev_err(tc35892_gpio->dev, | ||
| 355 | "unable to remove gpiochip: %d\n", ret); | ||
| 356 | return ret; | ||
| 357 | } | ||
| 358 | |||
| 359 | free_irq(irq, tc35892_gpio); | ||
| 360 | tc35892_gpio_irq_remove(tc35892_gpio); | ||
| 361 | |||
| 362 | platform_set_drvdata(pdev, NULL); | ||
| 363 | kfree(tc35892_gpio); | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | static struct platform_driver tc35892_gpio_driver = { | ||
| 369 | .driver.name = "tc35892-gpio", | ||
| 370 | .driver.owner = THIS_MODULE, | ||
| 371 | .probe = tc35892_gpio_probe, | ||
| 372 | .remove = __devexit_p(tc35892_gpio_remove), | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int __init tc35892_gpio_init(void) | ||
| 376 | { | ||
| 377 | return platform_driver_register(&tc35892_gpio_driver); | ||
| 378 | } | ||
| 379 | subsys_initcall(tc35892_gpio_init); | ||
| 380 | |||
| 381 | static void __exit tc35892_gpio_exit(void) | ||
| 382 | { | ||
| 383 | platform_driver_unregister(&tc35892_gpio_driver); | ||
| 384 | } | ||
| 385 | module_exit(tc35892_gpio_exit); | ||
| 386 | |||
| 387 | MODULE_LICENSE("GPL v2"); | ||
| 388 | MODULE_DESCRIPTION("TC35892 GPIO driver"); | ||
| 389 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c new file mode 100644 index 000000000000..180d584454fb --- /dev/null +++ b/drivers/gpio/tc3589x-gpio.c | |||
| @@ -0,0 +1,389 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/gpio.h> | ||
| 14 | #include <linux/irq.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/mfd/tc3589x.h> | ||
| 17 | |||
| 18 | /* | ||
| 19 | * These registers are modified under the irq bus lock and cached to avoid | ||
| 20 | * unnecessary writes in bus_sync_unlock. | ||
| 21 | */ | ||
| 22 | enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; | ||
| 23 | |||
| 24 | #define CACHE_NR_REGS 4 | ||
| 25 | #define CACHE_NR_BANKS 3 | ||
| 26 | |||
| 27 | struct tc3589x_gpio { | ||
| 28 | struct gpio_chip chip; | ||
| 29 | struct tc3589x *tc3589x; | ||
| 30 | struct device *dev; | ||
| 31 | struct mutex irq_lock; | ||
| 32 | |||
| 33 | int irq_base; | ||
| 34 | |||
| 35 | /* Caches of interrupt control registers for bus_lock */ | ||
| 36 | u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
| 37 | u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip) | ||
| 41 | { | ||
| 42 | return container_of(chip, struct tc3589x_gpio, chip); | ||
| 43 | } | ||
| 44 | |||
| 45 | static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
| 46 | { | ||
| 47 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
| 48 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 49 | u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; | ||
| 50 | u8 mask = 1 << (offset % 8); | ||
| 51 | int ret; | ||
| 52 | |||
| 53 | ret = tc3589x_reg_read(tc3589x, reg); | ||
| 54 | if (ret < 0) | ||
| 55 | return ret; | ||
| 56 | |||
| 57 | return ret & mask; | ||
| 58 | } | ||
| 59 | |||
| 60 | static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
| 61 | { | ||
| 62 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
| 63 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 64 | u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; | ||
| 65 | unsigned pos = offset % 8; | ||
| 66 | u8 data[] = {!!val << pos, 1 << pos}; | ||
| 67 | |||
| 68 | tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data); | ||
| 69 | } | ||
| 70 | |||
| 71 | static int tc3589x_gpio_direction_output(struct gpio_chip *chip, | ||
| 72 | unsigned offset, int val) | ||
| 73 | { | ||
| 74 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
| 75 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 76 | u8 reg = TC3589x_GPIODIR0 + offset / 8; | ||
| 77 | unsigned pos = offset % 8; | ||
| 78 | |||
| 79 | tc3589x_gpio_set(chip, offset, val); | ||
| 80 | |||
| 81 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int tc3589x_gpio_direction_input(struct gpio_chip *chip, | ||
| 85 | unsigned offset) | ||
| 86 | { | ||
| 87 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
| 88 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 89 | u8 reg = TC3589x_GPIODIR0 + offset / 8; | ||
| 90 | unsigned pos = offset % 8; | ||
| 91 | |||
| 92 | return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 96 | { | ||
| 97 | struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); | ||
| 98 | |||
| 99 | return tc3589x_gpio->irq_base + offset; | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct gpio_chip template_chip = { | ||
| 103 | .label = "tc3589x", | ||
| 104 | .owner = THIS_MODULE, | ||
| 105 | .direction_input = tc3589x_gpio_direction_input, | ||
| 106 | .get = tc3589x_gpio_get, | ||
| 107 | .direction_output = tc3589x_gpio_direction_output, | ||
| 108 | .set = tc3589x_gpio_set, | ||
| 109 | .to_irq = tc3589x_gpio_to_irq, | ||
| 110 | .can_sleep = 1, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
| 114 | { | ||
| 115 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
| 116 | int offset = irq - tc3589x_gpio->irq_base; | ||
| 117 | int regoffset = offset / 8; | ||
| 118 | int mask = 1 << (offset % 8); | ||
| 119 | |||
| 120 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
| 121 | tc3589x_gpio->regs[REG_IBE][regoffset] |= mask; | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask; | ||
| 126 | |||
| 127 | if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) | ||
| 128 | tc3589x_gpio->regs[REG_IS][regoffset] |= mask; | ||
| 129 | else | ||
| 130 | tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask; | ||
| 131 | |||
| 132 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) | ||
| 133 | tc3589x_gpio->regs[REG_IEV][regoffset] |= mask; | ||
| 134 | else | ||
| 135 | tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask; | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static void tc3589x_gpio_irq_lock(unsigned int irq) | ||
| 141 | { | ||
| 142 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
| 143 | |||
| 144 | mutex_lock(&tc3589x_gpio->irq_lock); | ||
| 145 | } | ||
| 146 | |||
| 147 | static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) | ||
| 148 | { | ||
| 149 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
| 150 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 151 | static const u8 regmap[] = { | ||
| 152 | [REG_IBE] = TC3589x_GPIOIBE0, | ||
| 153 | [REG_IEV] = TC3589x_GPIOIEV0, | ||
| 154 | [REG_IS] = TC3589x_GPIOIS0, | ||
| 155 | [REG_IE] = TC3589x_GPIOIE0, | ||
| 156 | }; | ||
| 157 | int i, j; | ||
| 158 | |||
| 159 | for (i = 0; i < CACHE_NR_REGS; i++) { | ||
| 160 | for (j = 0; j < CACHE_NR_BANKS; j++) { | ||
| 161 | u8 old = tc3589x_gpio->oldregs[i][j]; | ||
| 162 | u8 new = tc3589x_gpio->regs[i][j]; | ||
| 163 | |||
| 164 | if (new == old) | ||
| 165 | continue; | ||
| 166 | |||
| 167 | tc3589x_gpio->oldregs[i][j] = new; | ||
| 168 | tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | mutex_unlock(&tc3589x_gpio->irq_lock); | ||
| 173 | } | ||
| 174 | |||
| 175 | static void tc3589x_gpio_irq_mask(unsigned int irq) | ||
| 176 | { | ||
| 177 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
| 178 | int offset = irq - tc3589x_gpio->irq_base; | ||
| 179 | int regoffset = offset / 8; | ||
| 180 | int mask = 1 << (offset % 8); | ||
| 181 | |||
| 182 | tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void tc3589x_gpio_irq_unmask(unsigned int irq) | ||
| 186 | { | ||
| 187 | struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); | ||
| 188 | int offset = irq - tc3589x_gpio->irq_base; | ||
| 189 | int regoffset = offset / 8; | ||
| 190 | int mask = 1 << (offset % 8); | ||
| 191 | |||
| 192 | tc3589x_gpio->regs[REG_IE][regoffset] |= mask; | ||
| 193 | } | ||
| 194 | |||
| 195 | static struct irq_chip tc3589x_gpio_irq_chip = { | ||
| 196 | .name = "tc3589x-gpio", | ||
| 197 | .bus_lock = tc3589x_gpio_irq_lock, | ||
| 198 | .bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, | ||
| 199 | .mask = tc3589x_gpio_irq_mask, | ||
| 200 | .unmask = tc3589x_gpio_irq_unmask, | ||
| 201 | .set_type = tc3589x_gpio_irq_set_type, | ||
| 202 | }; | ||
| 203 | |||
| 204 | static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) | ||
| 205 | { | ||
| 206 | struct tc3589x_gpio *tc3589x_gpio = dev; | ||
| 207 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 208 | u8 status[CACHE_NR_BANKS]; | ||
| 209 | int ret; | ||
| 210 | int i; | ||
| 211 | |||
| 212 | ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0, | ||
| 213 | ARRAY_SIZE(status), status); | ||
| 214 | if (ret < 0) | ||
| 215 | return IRQ_NONE; | ||
| 216 | |||
| 217 | for (i = 0; i < ARRAY_SIZE(status); i++) { | ||
| 218 | unsigned int stat = status[i]; | ||
| 219 | if (!stat) | ||
| 220 | continue; | ||
| 221 | |||
| 222 | while (stat) { | ||
| 223 | int bit = __ffs(stat); | ||
| 224 | int line = i * 8 + bit; | ||
| 225 | |||
| 226 | handle_nested_irq(tc3589x_gpio->irq_base + line); | ||
| 227 | stat &= ~(1 << bit); | ||
| 228 | } | ||
| 229 | |||
| 230 | tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]); | ||
| 231 | } | ||
| 232 | |||
| 233 | return IRQ_HANDLED; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) | ||
| 237 | { | ||
| 238 | int base = tc3589x_gpio->irq_base; | ||
| 239 | int irq; | ||
| 240 | |||
| 241 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { | ||
| 242 | set_irq_chip_data(irq, tc3589x_gpio); | ||
| 243 | set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip, | ||
| 244 | handle_simple_irq); | ||
| 245 | set_irq_nested_thread(irq, 1); | ||
| 246 | #ifdef CONFIG_ARM | ||
| 247 | set_irq_flags(irq, IRQF_VALID); | ||
| 248 | #else | ||
| 249 | set_irq_noprobe(irq); | ||
| 250 | #endif | ||
| 251 | } | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) | ||
| 257 | { | ||
| 258 | int base = tc3589x_gpio->irq_base; | ||
| 259 | int irq; | ||
| 260 | |||
| 261 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { | ||
| 262 | #ifdef CONFIG_ARM | ||
| 263 | set_irq_flags(irq, 0); | ||
| 264 | #endif | ||
| 265 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
| 266 | set_irq_chip_data(irq, NULL); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) | ||
| 271 | { | ||
| 272 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | ||
| 273 | struct tc3589x_gpio_platform_data *pdata; | ||
| 274 | struct tc3589x_gpio *tc3589x_gpio; | ||
| 275 | int ret; | ||
| 276 | int irq; | ||
| 277 | |||
| 278 | pdata = tc3589x->pdata->gpio; | ||
| 279 | if (!pdata) | ||
| 280 | return -ENODEV; | ||
| 281 | |||
| 282 | irq = platform_get_irq(pdev, 0); | ||
| 283 | if (irq < 0) | ||
| 284 | return irq; | ||
| 285 | |||
| 286 | tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); | ||
| 287 | if (!tc3589x_gpio) | ||
| 288 | return -ENOMEM; | ||
| 289 | |||
| 290 | mutex_init(&tc3589x_gpio->irq_lock); | ||
| 291 | |||
| 292 | tc3589x_gpio->dev = &pdev->dev; | ||
| 293 | tc3589x_gpio->tc3589x = tc3589x; | ||
| 294 | |||
| 295 | tc3589x_gpio->chip = template_chip; | ||
| 296 | tc3589x_gpio->chip.ngpio = tc3589x->num_gpio; | ||
| 297 | tc3589x_gpio->chip.dev = &pdev->dev; | ||
| 298 | tc3589x_gpio->chip.base = pdata->gpio_base; | ||
| 299 | |||
| 300 | tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); | ||
| 301 | |||
| 302 | /* Bring the GPIO module out of reset */ | ||
| 303 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, | ||
| 304 | TC3589x_RSTCTRL_GPIRST, 0); | ||
| 305 | if (ret < 0) | ||
| 306 | goto out_free; | ||
| 307 | |||
| 308 | ret = tc3589x_gpio_irq_init(tc3589x_gpio); | ||
| 309 | if (ret) | ||
| 310 | goto out_free; | ||
| 311 | |||
| 312 | ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, | ||
| 313 | "tc3589x-gpio", tc3589x_gpio); | ||
| 314 | if (ret) { | ||
| 315 | dev_err(&pdev->dev, "unable to get irq: %d\n", ret); | ||
| 316 | goto out_removeirq; | ||
| 317 | } | ||
| 318 | |||
| 319 | ret = gpiochip_add(&tc3589x_gpio->chip); | ||
| 320 | if (ret) { | ||
| 321 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); | ||
| 322 | goto out_freeirq; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (pdata->setup) | ||
| 326 | pdata->setup(tc3589x, tc3589x_gpio->chip.base); | ||
| 327 | |||
| 328 | platform_set_drvdata(pdev, tc3589x_gpio); | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | |||
| 332 | out_freeirq: | ||
| 333 | free_irq(irq, tc3589x_gpio); | ||
| 334 | out_removeirq: | ||
| 335 | tc3589x_gpio_irq_remove(tc3589x_gpio); | ||
| 336 | out_free: | ||
| 337 | kfree(tc3589x_gpio); | ||
| 338 | return ret; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) | ||
| 342 | { | ||
| 343 | struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); | ||
| 344 | struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; | ||
| 345 | struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; | ||
| 346 | int irq = platform_get_irq(pdev, 0); | ||
| 347 | int ret; | ||
| 348 | |||
| 349 | if (pdata->remove) | ||
| 350 | pdata->remove(tc3589x, tc3589x_gpio->chip.base); | ||
| 351 | |||
| 352 | ret = gpiochip_remove(&tc3589x_gpio->chip); | ||
| 353 | if (ret < 0) { | ||
| 354 | dev_err(tc3589x_gpio->dev, | ||
| 355 | "unable to remove gpiochip: %d\n", ret); | ||
| 356 | return ret; | ||
| 357 | } | ||
| 358 | |||
| 359 | free_irq(irq, tc3589x_gpio); | ||
| 360 | tc3589x_gpio_irq_remove(tc3589x_gpio); | ||
| 361 | |||
| 362 | platform_set_drvdata(pdev, NULL); | ||
| 363 | kfree(tc3589x_gpio); | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | static struct platform_driver tc3589x_gpio_driver = { | ||
| 369 | .driver.name = "tc3589x-gpio", | ||
| 370 | .driver.owner = THIS_MODULE, | ||
| 371 | .probe = tc3589x_gpio_probe, | ||
| 372 | .remove = __devexit_p(tc3589x_gpio_remove), | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int __init tc3589x_gpio_init(void) | ||
| 376 | { | ||
| 377 | return platform_driver_register(&tc3589x_gpio_driver); | ||
| 378 | } | ||
| 379 | subsys_initcall(tc3589x_gpio_init); | ||
| 380 | |||
| 381 | static void __exit tc3589x_gpio_exit(void) | ||
| 382 | { | ||
| 383 | platform_driver_unregister(&tc3589x_gpio_driver); | ||
| 384 | } | ||
| 385 | module_exit(tc3589x_gpio_exit); | ||
| 386 | |||
| 387 | MODULE_LICENSE("GPL v2"); | ||
| 388 | MODULE_DESCRIPTION("TC3589x GPIO driver"); | ||
| 389 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 3a87f3ba5f75..c76bd3183beb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -459,6 +459,16 @@ config KEYBOARD_OMAP4 | |||
| 459 | To compile this driver as a module, choose M here: the | 459 | To compile this driver as a module, choose M here: the |
| 460 | module will be called omap4-keypad. | 460 | module will be called omap4-keypad. |
| 461 | 461 | ||
| 462 | config KEYBOARD_TC3589X | ||
| 463 | tristate "TC3589X Keypad support" | ||
| 464 | depends on MFD_TC3589X | ||
| 465 | help | ||
| 466 | Say Y here if you want to use the keypad controller on | ||
| 467 | TC35892/3 I/O expander. | ||
| 468 | |||
| 469 | To compile this driver as a module, choose M here: the | ||
| 470 | module will be called tc3589x-keypad. | ||
| 471 | |||
| 462 | config KEYBOARD_TNETV107X | 472 | config KEYBOARD_TNETV107X |
| 463 | tristate "TI TNETV107X keypad support" | 473 | tristate "TI TNETV107X keypad support" |
| 464 | depends on ARCH_DAVINCI_TNETV107X | 474 | depends on ARCH_DAVINCI_TNETV107X |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 622de73a445d..2aa6ce248b71 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -41,6 +41,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | |||
| 41 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 41 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
| 42 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 42 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
| 43 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | 43 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o |
| 44 | obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o | ||
| 44 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o | 45 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o |
| 45 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o | 46 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o |
| 46 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | 47 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o |
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c new file mode 100644 index 000000000000..69dc0cb20a00 --- /dev/null +++ b/drivers/input/keyboard/tc3589x-keypad.c | |||
| @@ -0,0 +1,472 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> | ||
| 5 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 6 | * | ||
| 7 | * License Terms: GNU General Public License, version 2 | ||
| 8 | * | ||
| 9 | * TC35893 MFD Keypad Controller driver | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/input.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/input/matrix_keypad.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/mfd/tc3589x.h> | ||
| 21 | |||
| 22 | /* Maximum supported keypad matrix row/columns size */ | ||
| 23 | #define TC3589x_MAX_KPROW 8 | ||
| 24 | #define TC3589x_MAX_KPCOL 12 | ||
| 25 | |||
| 26 | /* keypad related Constants */ | ||
| 27 | #define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF | ||
| 28 | #define DEDICATED_KEY_VAL 0xFF | ||
| 29 | |||
| 30 | /* Pull up/down masks */ | ||
| 31 | #define TC3589x_NO_PULL_MASK 0x0 | ||
| 32 | #define TC3589x_PULL_DOWN_MASK 0x1 | ||
| 33 | #define TC3589x_PULL_UP_MASK 0x2 | ||
| 34 | #define TC3589x_PULLUP_ALL_MASK 0xAA | ||
| 35 | #define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)) | ||
| 36 | |||
| 37 | /* Bit masks for IOCFG register */ | ||
| 38 | #define IOCFG_BALLCFG 0x01 | ||
| 39 | #define IOCFG_IG 0x08 | ||
| 40 | |||
| 41 | #define KP_EVCODE_COL_MASK 0x0F | ||
| 42 | #define KP_EVCODE_ROW_MASK 0x70 | ||
| 43 | #define KP_RELEASE_EVT_MASK 0x80 | ||
| 44 | |||
| 45 | #define KP_ROW_SHIFT 4 | ||
| 46 | |||
| 47 | #define KP_NO_VALID_KEY_MASK 0x7F | ||
| 48 | |||
| 49 | /* bit masks for RESTCTRL register */ | ||
| 50 | #define TC3589x_KBDRST 0x2 | ||
| 51 | #define TC3589x_IRQRST 0x10 | ||
| 52 | #define TC3589x_RESET_ALL 0x1B | ||
| 53 | |||
| 54 | /* KBDMFS register bit mask */ | ||
| 55 | #define TC3589x_KBDMFS_EN 0x1 | ||
| 56 | |||
| 57 | /* CLKEN register bitmask */ | ||
| 58 | #define KPD_CLK_EN 0x1 | ||
| 59 | |||
| 60 | /* RSTINTCLR register bit mask */ | ||
| 61 | #define IRQ_CLEAR 0x1 | ||
| 62 | |||
| 63 | /* bit masks for keyboard interrupts*/ | ||
| 64 | #define TC3589x_EVT_LOSS_INT 0x8 | ||
| 65 | #define TC3589x_EVT_INT 0x4 | ||
| 66 | #define TC3589x_KBD_LOSS_INT 0x2 | ||
| 67 | #define TC3589x_KBD_INT 0x1 | ||
| 68 | |||
| 69 | /* bit masks for keyboard interrupt clear*/ | ||
| 70 | #define TC3589x_EVT_INT_CLR 0x2 | ||
| 71 | #define TC3589x_KBD_INT_CLR 0x1 | ||
| 72 | |||
| 73 | #define TC3589x_KBD_KEYMAP_SIZE 64 | ||
| 74 | |||
| 75 | /** | ||
| 76 | * struct tc_keypad - data structure used by keypad driver | ||
| 77 | * @input: pointer to input device object | ||
| 78 | * @board: keypad platform device | ||
| 79 | * @krow: number of rows | ||
| 80 | * @kcol: number of coloumns | ||
| 81 | * @keymap: matrix scan code table for keycodes | ||
| 82 | */ | ||
| 83 | struct tc_keypad { | ||
| 84 | struct tc3589x *tc3589x; | ||
| 85 | struct input_dev *input; | ||
| 86 | const struct tc3589x_keypad_platform_data *board; | ||
| 87 | unsigned int krow; | ||
| 88 | unsigned int kcol; | ||
| 89 | unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE]; | ||
| 90 | bool keypad_stopped; | ||
| 91 | }; | ||
| 92 | |||
| 93 | static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) | ||
| 94 | { | ||
| 95 | int ret; | ||
| 96 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 97 | u8 settle_time = keypad->board->settle_time; | ||
| 98 | u8 dbounce_period = keypad->board->debounce_period; | ||
| 99 | u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */ | ||
| 100 | u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */ | ||
| 101 | |||
| 102 | /* validate platform configurations */ | ||
| 103 | if (keypad->board->kcol > TC3589x_MAX_KPCOL || | ||
| 104 | keypad->board->krow > TC3589x_MAX_KPROW || | ||
| 105 | keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE || | ||
| 106 | keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */ | ||
| 110 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE, | ||
| 111 | (rows << KP_ROW_SHIFT) | column); | ||
| 112 | if (ret < 0) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | /* configure dedicated key config, no dedicated key selected */ | ||
| 116 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL); | ||
| 117 | if (ret < 0) | ||
| 118 | return ret; | ||
| 119 | |||
| 120 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL); | ||
| 121 | if (ret < 0) | ||
| 122 | return ret; | ||
| 123 | |||
| 124 | /* Configure settle time */ | ||
| 125 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time); | ||
| 126 | if (ret < 0) | ||
| 127 | return ret; | ||
| 128 | |||
| 129 | /* Configure debounce time */ | ||
| 130 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period); | ||
| 131 | if (ret < 0) | ||
| 132 | return ret; | ||
| 133 | |||
| 134 | /* Start of initialise keypad GPIOs */ | ||
| 135 | ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG); | ||
| 136 | if (ret < 0) | ||
| 137 | return ret; | ||
| 138 | |||
| 139 | /* Configure pull-up resistors for all row GPIOs */ | ||
| 140 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB, | ||
| 141 | TC3589x_PULLUP_ALL_MASK); | ||
| 142 | if (ret < 0) | ||
| 143 | return ret; | ||
| 144 | |||
| 145 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB, | ||
| 146 | TC3589x_PULLUP_ALL_MASK); | ||
| 147 | if (ret < 0) | ||
| 148 | return ret; | ||
| 149 | |||
| 150 | /* Configure pull-up resistors for all column GPIOs */ | ||
| 151 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB, | ||
| 152 | TC3589x_PULLUP_ALL_MASK); | ||
| 153 | if (ret < 0) | ||
| 154 | return ret; | ||
| 155 | |||
| 156 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB, | ||
| 157 | TC3589x_PULLUP_ALL_MASK); | ||
| 158 | if (ret < 0) | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB, | ||
| 162 | TC3589x_PULLUP_ALL_MASK); | ||
| 163 | |||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | #define TC35893_DATA_REGS 4 | ||
| 168 | #define TC35893_KEYCODE_FIFO_EMPTY 0x7f | ||
| 169 | #define TC35893_KEYCODE_FIFO_CLEAR 0xff | ||
| 170 | #define TC35893_KEYPAD_ROW_SHIFT 0x3 | ||
| 171 | |||
| 172 | static irqreturn_t tc3589x_keypad_irq(int irq, void *dev) | ||
| 173 | { | ||
| 174 | struct tc_keypad *keypad = dev; | ||
| 175 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 176 | u8 i, row_index, col_index, kbd_code, up; | ||
| 177 | u8 code; | ||
| 178 | |||
| 179 | for (i = 0; i < TC35893_DATA_REGS * 2; i++) { | ||
| 180 | kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO); | ||
| 181 | |||
| 182 | /* loop till fifo is empty and no more keys are pressed */ | ||
| 183 | if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY || | ||
| 184 | kbd_code == TC35893_KEYCODE_FIFO_CLEAR) | ||
| 185 | continue; | ||
| 186 | |||
| 187 | /* valid key is found */ | ||
| 188 | col_index = kbd_code & KP_EVCODE_COL_MASK; | ||
| 189 | row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT; | ||
| 190 | code = MATRIX_SCAN_CODE(row_index, col_index, | ||
| 191 | TC35893_KEYPAD_ROW_SHIFT); | ||
| 192 | up = kbd_code & KP_RELEASE_EVT_MASK; | ||
| 193 | |||
| 194 | input_event(keypad->input, EV_MSC, MSC_SCAN, code); | ||
| 195 | input_report_key(keypad->input, keypad->keymap[code], !up); | ||
| 196 | input_sync(keypad->input); | ||
| 197 | } | ||
| 198 | |||
| 199 | /* clear IRQ */ | ||
| 200 | tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
| 201 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
| 202 | /* enable IRQ */ | ||
| 203 | tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
| 204 | 0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
| 205 | |||
| 206 | return IRQ_HANDLED; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int tc3589x_keypad_enable(struct tc_keypad *keypad) | ||
| 210 | { | ||
| 211 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | /* pull the keypad module out of reset */ | ||
| 215 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0); | ||
| 216 | if (ret < 0) | ||
| 217 | return ret; | ||
| 218 | |||
| 219 | /* configure KBDMFS */ | ||
| 220 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN); | ||
| 221 | if (ret < 0) | ||
| 222 | return ret; | ||
| 223 | |||
| 224 | /* enable the keypad clock */ | ||
| 225 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN); | ||
| 226 | if (ret < 0) | ||
| 227 | return ret; | ||
| 228 | |||
| 229 | /* clear pending IRQs */ | ||
| 230 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1); | ||
| 231 | if (ret < 0) | ||
| 232 | return ret; | ||
| 233 | |||
| 234 | /* enable the IRQs */ | ||
| 235 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0, | ||
| 236 | TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
| 237 | if (ret < 0) | ||
| 238 | return ret; | ||
| 239 | |||
| 240 | keypad->keypad_stopped = false; | ||
| 241 | |||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int tc3589x_keypad_disable(struct tc_keypad *keypad) | ||
| 246 | { | ||
| 247 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 248 | int ret; | ||
| 249 | |||
| 250 | /* clear IRQ */ | ||
| 251 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
| 252 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
| 253 | if (ret < 0) | ||
| 254 | return ret; | ||
| 255 | |||
| 256 | /* disable all interrupts */ | ||
| 257 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
| 258 | ~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | /* disable the keypad module */ | ||
| 263 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0); | ||
| 264 | if (ret < 0) | ||
| 265 | return ret; | ||
| 266 | |||
| 267 | /* put the keypad module into reset */ | ||
| 268 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1); | ||
| 269 | |||
| 270 | keypad->keypad_stopped = true; | ||
| 271 | |||
| 272 | return ret; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int tc3589x_keypad_open(struct input_dev *input) | ||
| 276 | { | ||
| 277 | int error; | ||
| 278 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
| 279 | |||
| 280 | /* enable the keypad module */ | ||
| 281 | error = tc3589x_keypad_enable(keypad); | ||
| 282 | if (error < 0) { | ||
| 283 | dev_err(&input->dev, "failed to enable keypad module\n"); | ||
| 284 | return error; | ||
| 285 | } | ||
| 286 | |||
| 287 | error = tc3589x_keypad_init_key_hardware(keypad); | ||
| 288 | if (error < 0) { | ||
| 289 | dev_err(&input->dev, "failed to configure keypad module\n"); | ||
| 290 | return error; | ||
| 291 | } | ||
| 292 | |||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | static void tc3589x_keypad_close(struct input_dev *input) | ||
| 297 | { | ||
| 298 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
| 299 | |||
| 300 | /* disable the keypad module */ | ||
| 301 | tc3589x_keypad_disable(keypad); | ||
| 302 | } | ||
| 303 | |||
| 304 | static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) | ||
| 305 | { | ||
| 306 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | ||
| 307 | struct tc_keypad *keypad; | ||
| 308 | struct input_dev *input; | ||
| 309 | const struct tc3589x_keypad_platform_data *plat; | ||
| 310 | int error, irq; | ||
| 311 | |||
| 312 | plat = tc3589x->pdata->keypad; | ||
| 313 | if (!plat) { | ||
| 314 | dev_err(&pdev->dev, "invalid keypad platform data\n"); | ||
| 315 | return -EINVAL; | ||
| 316 | } | ||
| 317 | |||
| 318 | irq = platform_get_irq(pdev, 0); | ||
| 319 | if (irq < 0) | ||
| 320 | return irq; | ||
| 321 | |||
| 322 | keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); | ||
| 323 | input = input_allocate_device(); | ||
| 324 | if (!keypad || !input) { | ||
| 325 | dev_err(&pdev->dev, "failed to allocate keypad memory\n"); | ||
| 326 | error = -ENOMEM; | ||
| 327 | goto err_free_mem; | ||
| 328 | } | ||
| 329 | |||
| 330 | keypad->board = plat; | ||
| 331 | keypad->input = input; | ||
| 332 | keypad->tc3589x = tc3589x; | ||
| 333 | |||
| 334 | input->id.bustype = BUS_I2C; | ||
| 335 | input->name = pdev->name; | ||
| 336 | input->dev.parent = &pdev->dev; | ||
| 337 | |||
| 338 | input->keycode = keypad->keymap; | ||
| 339 | input->keycodesize = sizeof(keypad->keymap[0]); | ||
| 340 | input->keycodemax = ARRAY_SIZE(keypad->keymap); | ||
| 341 | |||
| 342 | input->open = tc3589x_keypad_open; | ||
| 343 | input->close = tc3589x_keypad_close; | ||
| 344 | |||
| 345 | input_set_drvdata(input, keypad); | ||
| 346 | |||
| 347 | input_set_capability(input, EV_MSC, MSC_SCAN); | ||
| 348 | |||
| 349 | __set_bit(EV_KEY, input->evbit); | ||
| 350 | if (!plat->no_autorepeat) | ||
| 351 | __set_bit(EV_REP, input->evbit); | ||
| 352 | |||
| 353 | matrix_keypad_build_keymap(plat->keymap_data, 0x3, | ||
| 354 | input->keycode, input->keybit); | ||
| 355 | |||
| 356 | error = request_threaded_irq(irq, NULL, | ||
| 357 | tc3589x_keypad_irq, plat->irqtype, | ||
| 358 | "tc3589x-keypad", keypad); | ||
| 359 | if (error < 0) { | ||
| 360 | dev_err(&pdev->dev, | ||
| 361 | "Could not allocate irq %d,error %d\n", | ||
| 362 | irq, error); | ||
| 363 | goto err_free_mem; | ||
| 364 | } | ||
| 365 | |||
| 366 | error = input_register_device(input); | ||
| 367 | if (error) { | ||
| 368 | dev_err(&pdev->dev, "Could not register input device\n"); | ||
| 369 | goto err_free_irq; | ||
| 370 | } | ||
| 371 | |||
| 372 | /* let platform decide if keypad is a wakeup source or not */ | ||
| 373 | device_init_wakeup(&pdev->dev, plat->enable_wakeup); | ||
| 374 | device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup); | ||
| 375 | |||
| 376 | platform_set_drvdata(pdev, keypad); | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | |||
| 380 | err_free_irq: | ||
| 381 | free_irq(irq, keypad); | ||
| 382 | err_free_mem: | ||
| 383 | input_free_device(input); | ||
| 384 | kfree(keypad); | ||
| 385 | return error; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) | ||
| 389 | { | ||
| 390 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 391 | int irq = platform_get_irq(pdev, 0); | ||
| 392 | |||
| 393 | if (!keypad->keypad_stopped) | ||
| 394 | tc3589x_keypad_disable(keypad); | ||
| 395 | |||
| 396 | free_irq(irq, keypad); | ||
| 397 | |||
| 398 | input_unregister_device(keypad->input); | ||
| 399 | |||
| 400 | kfree(keypad); | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | #ifdef CONFIG_PM | ||
| 406 | static int tc3589x_keypad_suspend(struct device *dev) | ||
| 407 | { | ||
| 408 | struct platform_device *pdev = to_platform_device(dev); | ||
| 409 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 410 | int irq = platform_get_irq(pdev, 0); | ||
| 411 | |||
| 412 | /* keypad is already off; we do nothing */ | ||
| 413 | if (keypad->keypad_stopped) | ||
| 414 | return 0; | ||
| 415 | |||
| 416 | /* if device is not a wakeup source, disable it for powersave */ | ||
| 417 | if (!device_may_wakeup(&pdev->dev)) | ||
| 418 | tc3589x_keypad_disable(keypad); | ||
| 419 | else | ||
| 420 | enable_irq_wake(irq); | ||
| 421 | |||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | static int tc3589x_keypad_resume(struct device *dev) | ||
| 426 | { | ||
| 427 | struct platform_device *pdev = to_platform_device(dev); | ||
| 428 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 429 | int irq = platform_get_irq(pdev, 0); | ||
| 430 | |||
| 431 | if (!keypad->keypad_stopped) | ||
| 432 | return 0; | ||
| 433 | |||
| 434 | /* enable the device to resume normal operations */ | ||
| 435 | if (!device_may_wakeup(&pdev->dev)) | ||
| 436 | tc3589x_keypad_enable(keypad); | ||
| 437 | else | ||
| 438 | disable_irq_wake(irq); | ||
| 439 | |||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, | ||
| 444 | tc3589x_keypad_suspend, tc3589x_keypad_resume); | ||
| 445 | #endif | ||
| 446 | |||
| 447 | static struct platform_driver tc3589x_keypad_driver = { | ||
| 448 | .driver.name = "tc3589x-keypad", | ||
| 449 | .driver.owner = THIS_MODULE, | ||
| 450 | #ifdef CONFIG_PM | ||
| 451 | .driver.pm = &tc3589x_keypad_dev_pm_ops, | ||
| 452 | #endif | ||
| 453 | .probe = tc3589x_keypad_probe, | ||
| 454 | .remove = __devexit_p(tc3589x_keypad_remove), | ||
| 455 | }; | ||
| 456 | |||
| 457 | static int __init tc3589x_keypad_init(void) | ||
| 458 | { | ||
| 459 | return platform_driver_register(&tc3589x_keypad_driver); | ||
| 460 | } | ||
| 461 | module_init(tc3589x_keypad_init); | ||
| 462 | |||
| 463 | static void __exit tc3589x_keypad_exit(void) | ||
| 464 | { | ||
| 465 | return platform_driver_unregister(&tc3589x_keypad_driver); | ||
| 466 | } | ||
| 467 | module_exit(tc3589x_keypad_exit); | ||
| 468 | |||
| 469 | MODULE_LICENSE("GPL v2"); | ||
| 470 | MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer"); | ||
| 471 | MODULE_DESCRIPTION("TC35893 Keypad Driver"); | ||
| 472 | MODULE_ALIAS("platform:tc3589x-keypad") | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3a1493b8b5e5..e8e704f52746 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -218,12 +218,12 @@ config MFD_STMPE | |||
| 218 | Keypad: stmpe-keypad | 218 | Keypad: stmpe-keypad |
| 219 | Touchscreen: stmpe-ts | 219 | Touchscreen: stmpe-ts |
| 220 | 220 | ||
| 221 | config MFD_TC35892 | 221 | config MFD_TC3589X |
| 222 | bool "Support Toshiba TC35892" | 222 | bool "Support Toshiba TC35892 and variants" |
| 223 | depends on I2C=y && GENERIC_HARDIRQS | 223 | depends on I2C=y && GENERIC_HARDIRQS |
| 224 | select MFD_CORE | 224 | select MFD_CORE |
| 225 | help | 225 | help |
| 226 | Support for the Toshiba TC35892 I/O Expander. | 226 | Support for the Toshiba TC35892 and variants I/O Expander. |
| 227 | 227 | ||
| 228 | This driver provides common support for accessing the device, | 228 | This driver provides common support for accessing the device, |
| 229 | additional drivers must be enabled in order to use the | 229 | additional drivers must be enabled in order to use the |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f54b3659abbb..e590d1e44cf0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
| @@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o | |||
| 16 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o | 16 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o | 18 | obj-$(CONFIG_MFD_STMPE) += stmpe.o |
| 19 | obj-$(CONFIG_MFD_TC35892) += tc35892.o | 19 | obj-$(CONFIG_MFD_TC3589X) += tc3589x.o |
| 20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | 20 | obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o |
| 21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | 21 | obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o |
| 22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | 22 | obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o |
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c deleted file mode 100644 index e619e2a55997..000000000000 --- a/drivers/mfd/tc35892.c +++ /dev/null | |||
| @@ -1,345 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/irq.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/mfd/core.h> | ||
| 15 | #include <linux/mfd/tc35892.h> | ||
| 16 | |||
| 17 | /** | ||
| 18 | * tc35892_reg_read() - read a single TC35892 register | ||
| 19 | * @tc35892: Device to read from | ||
| 20 | * @reg: Register to read | ||
| 21 | */ | ||
| 22 | int tc35892_reg_read(struct tc35892 *tc35892, u8 reg) | ||
| 23 | { | ||
| 24 | int ret; | ||
| 25 | |||
| 26 | ret = i2c_smbus_read_byte_data(tc35892->i2c, reg); | ||
| 27 | if (ret < 0) | ||
| 28 | dev_err(tc35892->dev, "failed to read reg %#x: %d\n", | ||
| 29 | reg, ret); | ||
| 30 | |||
| 31 | return ret; | ||
| 32 | } | ||
| 33 | EXPORT_SYMBOL_GPL(tc35892_reg_read); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * tc35892_reg_read() - write a single TC35892 register | ||
| 37 | * @tc35892: Device to write to | ||
| 38 | * @reg: Register to read | ||
| 39 | * @data: Value to write | ||
| 40 | */ | ||
| 41 | int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data) | ||
| 42 | { | ||
| 43 | int ret; | ||
| 44 | |||
| 45 | ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data); | ||
| 46 | if (ret < 0) | ||
| 47 | dev_err(tc35892->dev, "failed to write reg %#x: %d\n", | ||
| 48 | reg, ret); | ||
| 49 | |||
| 50 | return ret; | ||
| 51 | } | ||
| 52 | EXPORT_SYMBOL_GPL(tc35892_reg_write); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * tc35892_block_read() - read multiple TC35892 registers | ||
| 56 | * @tc35892: Device to read from | ||
| 57 | * @reg: First register | ||
| 58 | * @length: Number of registers | ||
| 59 | * @values: Buffer to write to | ||
| 60 | */ | ||
| 61 | int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values) | ||
| 62 | { | ||
| 63 | int ret; | ||
| 64 | |||
| 65 | ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values); | ||
| 66 | if (ret < 0) | ||
| 67 | dev_err(tc35892->dev, "failed to read regs %#x: %d\n", | ||
| 68 | reg, ret); | ||
| 69 | |||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | EXPORT_SYMBOL_GPL(tc35892_block_read); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * tc35892_block_write() - write multiple TC35892 registers | ||
| 76 | * @tc35892: Device to write to | ||
| 77 | * @reg: First register | ||
| 78 | * @length: Number of registers | ||
| 79 | * @values: Values to write | ||
| 80 | */ | ||
| 81 | int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length, | ||
| 82 | const u8 *values) | ||
| 83 | { | ||
| 84 | int ret; | ||
| 85 | |||
| 86 | ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length, | ||
| 87 | values); | ||
| 88 | if (ret < 0) | ||
| 89 | dev_err(tc35892->dev, "failed to write regs %#x: %d\n", | ||
| 90 | reg, ret); | ||
| 91 | |||
| 92 | return ret; | ||
| 93 | } | ||
| 94 | EXPORT_SYMBOL_GPL(tc35892_block_write); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * tc35892_set_bits() - set the value of a bitfield in a TC35892 register | ||
| 98 | * @tc35892: Device to write to | ||
| 99 | * @reg: Register to write | ||
| 100 | * @mask: Mask of bits to set | ||
| 101 | * @values: Value to set | ||
| 102 | */ | ||
| 103 | int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val) | ||
| 104 | { | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | mutex_lock(&tc35892->lock); | ||
| 108 | |||
| 109 | ret = tc35892_reg_read(tc35892, reg); | ||
| 110 | if (ret < 0) | ||
| 111 | goto out; | ||
| 112 | |||
| 113 | ret &= ~mask; | ||
| 114 | ret |= val; | ||
| 115 | |||
| 116 | ret = tc35892_reg_write(tc35892, reg, ret); | ||
| 117 | |||
| 118 | out: | ||
| 119 | mutex_unlock(&tc35892->lock); | ||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | EXPORT_SYMBOL_GPL(tc35892_set_bits); | ||
| 123 | |||
| 124 | static struct resource gpio_resources[] = { | ||
| 125 | { | ||
| 126 | .start = TC35892_INT_GPIIRQ, | ||
| 127 | .end = TC35892_INT_GPIIRQ, | ||
| 128 | .flags = IORESOURCE_IRQ, | ||
| 129 | }, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct mfd_cell tc35892_devs[] = { | ||
| 133 | { | ||
| 134 | .name = "tc35892-gpio", | ||
| 135 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
| 136 | .resources = &gpio_resources[0], | ||
| 137 | }, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static irqreturn_t tc35892_irq(int irq, void *data) | ||
| 141 | { | ||
| 142 | struct tc35892 *tc35892 = data; | ||
| 143 | int status; | ||
| 144 | |||
| 145 | status = tc35892_reg_read(tc35892, TC35892_IRQST); | ||
| 146 | if (status < 0) | ||
| 147 | return IRQ_NONE; | ||
| 148 | |||
| 149 | while (status) { | ||
| 150 | int bit = __ffs(status); | ||
| 151 | |||
| 152 | handle_nested_irq(tc35892->irq_base + bit); | ||
| 153 | status &= ~(1 << bit); | ||
| 154 | } | ||
| 155 | |||
| 156 | /* | ||
| 157 | * A dummy read or write (to any register) appears to be necessary to | ||
| 158 | * have the last interrupt clear (for example, GPIO IC write) take | ||
| 159 | * effect. | ||
| 160 | */ | ||
| 161 | tc35892_reg_read(tc35892, TC35892_IRQST); | ||
| 162 | |||
| 163 | return IRQ_HANDLED; | ||
| 164 | } | ||
| 165 | |||
| 166 | static void tc35892_irq_dummy(unsigned int irq) | ||
| 167 | { | ||
| 168 | /* No mask/unmask at this level */ | ||
| 169 | } | ||
| 170 | |||
| 171 | static struct irq_chip tc35892_irq_chip = { | ||
| 172 | .name = "tc35892", | ||
| 173 | .mask = tc35892_irq_dummy, | ||
| 174 | .unmask = tc35892_irq_dummy, | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int tc35892_irq_init(struct tc35892 *tc35892) | ||
| 178 | { | ||
| 179 | int base = tc35892->irq_base; | ||
| 180 | int irq; | ||
| 181 | |||
| 182 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
| 183 | set_irq_chip_data(irq, tc35892); | ||
| 184 | set_irq_chip_and_handler(irq, &tc35892_irq_chip, | ||
| 185 | handle_edge_irq); | ||
| 186 | set_irq_nested_thread(irq, 1); | ||
| 187 | #ifdef CONFIG_ARM | ||
| 188 | set_irq_flags(irq, IRQF_VALID); | ||
| 189 | #else | ||
| 190 | set_irq_noprobe(irq); | ||
| 191 | #endif | ||
| 192 | } | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void tc35892_irq_remove(struct tc35892 *tc35892) | ||
| 198 | { | ||
| 199 | int base = tc35892->irq_base; | ||
| 200 | int irq; | ||
| 201 | |||
| 202 | for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) { | ||
| 203 | #ifdef CONFIG_ARM | ||
| 204 | set_irq_flags(irq, 0); | ||
| 205 | #endif | ||
| 206 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
| 207 | set_irq_chip_data(irq, NULL); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | static int tc35892_chip_init(struct tc35892 *tc35892) | ||
| 212 | { | ||
| 213 | int manf, ver, ret; | ||
| 214 | |||
| 215 | manf = tc35892_reg_read(tc35892, TC35892_MANFCODE); | ||
| 216 | if (manf < 0) | ||
| 217 | return manf; | ||
| 218 | |||
| 219 | ver = tc35892_reg_read(tc35892, TC35892_VERSION); | ||
| 220 | if (ver < 0) | ||
| 221 | return ver; | ||
| 222 | |||
| 223 | if (manf != TC35892_MANFCODE_MAGIC) { | ||
| 224 | dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf); | ||
| 225 | return -EINVAL; | ||
| 226 | } | ||
| 227 | |||
| 228 | dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
| 229 | |||
| 230 | /* Put everything except the IRQ module into reset */ | ||
| 231 | ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL, | ||
| 232 | TC35892_RSTCTRL_TIMRST | ||
| 233 | | TC35892_RSTCTRL_ROTRST | ||
| 234 | | TC35892_RSTCTRL_KBDRST | ||
| 235 | | TC35892_RSTCTRL_GPIRST); | ||
| 236 | if (ret < 0) | ||
| 237 | return ret; | ||
| 238 | |||
| 239 | /* Clear the reset interrupt. */ | ||
| 240 | return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1); | ||
| 241 | } | ||
| 242 | |||
| 243 | static int __devinit tc35892_probe(struct i2c_client *i2c, | ||
| 244 | const struct i2c_device_id *id) | ||
| 245 | { | ||
| 246 | struct tc35892_platform_data *pdata = i2c->dev.platform_data; | ||
| 247 | struct tc35892 *tc35892; | ||
| 248 | int ret; | ||
| 249 | |||
| 250 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
| 251 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
| 252 | return -EIO; | ||
| 253 | |||
| 254 | tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL); | ||
| 255 | if (!tc35892) | ||
| 256 | return -ENOMEM; | ||
| 257 | |||
| 258 | mutex_init(&tc35892->lock); | ||
| 259 | |||
| 260 | tc35892->dev = &i2c->dev; | ||
| 261 | tc35892->i2c = i2c; | ||
| 262 | tc35892->pdata = pdata; | ||
| 263 | tc35892->irq_base = pdata->irq_base; | ||
| 264 | tc35892->num_gpio = id->driver_data; | ||
| 265 | |||
| 266 | i2c_set_clientdata(i2c, tc35892); | ||
| 267 | |||
| 268 | ret = tc35892_chip_init(tc35892); | ||
| 269 | if (ret) | ||
| 270 | goto out_free; | ||
| 271 | |||
| 272 | ret = tc35892_irq_init(tc35892); | ||
| 273 | if (ret) | ||
| 274 | goto out_free; | ||
| 275 | |||
| 276 | ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq, | ||
| 277 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| 278 | "tc35892", tc35892); | ||
| 279 | if (ret) { | ||
| 280 | dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret); | ||
| 281 | goto out_removeirq; | ||
| 282 | } | ||
| 283 | |||
| 284 | ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs, | ||
| 285 | ARRAY_SIZE(tc35892_devs), NULL, | ||
| 286 | tc35892->irq_base); | ||
| 287 | if (ret) { | ||
| 288 | dev_err(tc35892->dev, "failed to add children\n"); | ||
| 289 | goto out_freeirq; | ||
| 290 | } | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | |||
| 294 | out_freeirq: | ||
| 295 | free_irq(tc35892->i2c->irq, tc35892); | ||
| 296 | out_removeirq: | ||
| 297 | tc35892_irq_remove(tc35892); | ||
| 298 | out_free: | ||
| 299 | kfree(tc35892); | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | |||
| 303 | static int __devexit tc35892_remove(struct i2c_client *client) | ||
| 304 | { | ||
| 305 | struct tc35892 *tc35892 = i2c_get_clientdata(client); | ||
| 306 | |||
| 307 | mfd_remove_devices(tc35892->dev); | ||
| 308 | |||
| 309 | free_irq(tc35892->i2c->irq, tc35892); | ||
| 310 | tc35892_irq_remove(tc35892); | ||
| 311 | |||
| 312 | kfree(tc35892); | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | static const struct i2c_device_id tc35892_id[] = { | ||
| 318 | { "tc35892", 24 }, | ||
| 319 | { } | ||
| 320 | }; | ||
| 321 | MODULE_DEVICE_TABLE(i2c, tc35892_id); | ||
| 322 | |||
| 323 | static struct i2c_driver tc35892_driver = { | ||
| 324 | .driver.name = "tc35892", | ||
| 325 | .driver.owner = THIS_MODULE, | ||
| 326 | .probe = tc35892_probe, | ||
| 327 | .remove = __devexit_p(tc35892_remove), | ||
| 328 | .id_table = tc35892_id, | ||
| 329 | }; | ||
| 330 | |||
| 331 | static int __init tc35892_init(void) | ||
| 332 | { | ||
| 333 | return i2c_add_driver(&tc35892_driver); | ||
| 334 | } | ||
| 335 | subsys_initcall(tc35892_init); | ||
| 336 | |||
| 337 | static void __exit tc35892_exit(void) | ||
| 338 | { | ||
| 339 | i2c_del_driver(&tc35892_driver); | ||
| 340 | } | ||
| 341 | module_exit(tc35892_exit); | ||
| 342 | |||
| 343 | MODULE_LICENSE("GPL v2"); | ||
| 344 | MODULE_DESCRIPTION("TC35892 MFD core driver"); | ||
| 345 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c new file mode 100644 index 000000000000..729dbeed2ce0 --- /dev/null +++ b/drivers/mfd/tc3589x.c | |||
| @@ -0,0 +1,422 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson | ||
| 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/irq.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/mfd/core.h> | ||
| 15 | #include <linux/mfd/tc3589x.h> | ||
| 16 | |||
| 17 | #define TC3589x_CLKMODE_MODCTL_SLEEP 0x0 | ||
| 18 | #define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0) | ||
| 19 | |||
| 20 | /** | ||
| 21 | * tc3589x_reg_read() - read a single TC3589x register | ||
| 22 | * @tc3589x: Device to read from | ||
| 23 | * @reg: Register to read | ||
| 24 | */ | ||
| 25 | int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) | ||
| 26 | { | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg); | ||
| 30 | if (ret < 0) | ||
| 31 | dev_err(tc3589x->dev, "failed to read reg %#x: %d\n", | ||
| 32 | reg, ret); | ||
| 33 | |||
| 34 | return ret; | ||
| 35 | } | ||
| 36 | EXPORT_SYMBOL_GPL(tc3589x_reg_read); | ||
| 37 | |||
| 38 | /** | ||
| 39 | * tc3589x_reg_read() - write a single TC3589x register | ||
| 40 | * @tc3589x: Device to write to | ||
| 41 | * @reg: Register to read | ||
| 42 | * @data: Value to write | ||
| 43 | */ | ||
| 44 | int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data) | ||
| 45 | { | ||
| 46 | int ret; | ||
| 47 | |||
| 48 | ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data); | ||
| 49 | if (ret < 0) | ||
| 50 | dev_err(tc3589x->dev, "failed to write reg %#x: %d\n", | ||
| 51 | reg, ret); | ||
| 52 | |||
| 53 | return ret; | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL_GPL(tc3589x_reg_write); | ||
| 56 | |||
| 57 | /** | ||
| 58 | * tc3589x_block_read() - read multiple TC3589x registers | ||
| 59 | * @tc3589x: Device to read from | ||
| 60 | * @reg: First register | ||
| 61 | * @length: Number of registers | ||
| 62 | * @values: Buffer to write to | ||
| 63 | */ | ||
| 64 | int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values) | ||
| 65 | { | ||
| 66 | int ret; | ||
| 67 | |||
| 68 | ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values); | ||
| 69 | if (ret < 0) | ||
| 70 | dev_err(tc3589x->dev, "failed to read regs %#x: %d\n", | ||
| 71 | reg, ret); | ||
| 72 | |||
| 73 | return ret; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(tc3589x_block_read); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * tc3589x_block_write() - write multiple TC3589x registers | ||
| 79 | * @tc3589x: Device to write to | ||
| 80 | * @reg: First register | ||
| 81 | * @length: Number of registers | ||
| 82 | * @values: Values to write | ||
| 83 | */ | ||
| 84 | int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, | ||
| 85 | const u8 *values) | ||
| 86 | { | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length, | ||
| 90 | values); | ||
| 91 | if (ret < 0) | ||
| 92 | dev_err(tc3589x->dev, "failed to write regs %#x: %d\n", | ||
| 93 | reg, ret); | ||
| 94 | |||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL_GPL(tc3589x_block_write); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * tc3589x_set_bits() - set the value of a bitfield in a TC3589x register | ||
| 101 | * @tc3589x: Device to write to | ||
| 102 | * @reg: Register to write | ||
| 103 | * @mask: Mask of bits to set | ||
| 104 | * @values: Value to set | ||
| 105 | */ | ||
| 106 | int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) | ||
| 107 | { | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | mutex_lock(&tc3589x->lock); | ||
| 111 | |||
| 112 | ret = tc3589x_reg_read(tc3589x, reg); | ||
| 113 | if (ret < 0) | ||
| 114 | goto out; | ||
| 115 | |||
| 116 | ret &= ~mask; | ||
| 117 | ret |= val; | ||
| 118 | |||
| 119 | ret = tc3589x_reg_write(tc3589x, reg, ret); | ||
| 120 | |||
| 121 | out: | ||
| 122 | mutex_unlock(&tc3589x->lock); | ||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | EXPORT_SYMBOL_GPL(tc3589x_set_bits); | ||
| 126 | |||
| 127 | static struct resource gpio_resources[] = { | ||
| 128 | { | ||
| 129 | .start = TC3589x_INT_GPIIRQ, | ||
| 130 | .end = TC3589x_INT_GPIIRQ, | ||
| 131 | .flags = IORESOURCE_IRQ, | ||
| 132 | }, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct resource keypad_resources[] = { | ||
| 136 | { | ||
| 137 | .start = TC3589x_INT_KBDIRQ, | ||
| 138 | .end = TC3589x_INT_KBDIRQ, | ||
| 139 | .flags = IORESOURCE_IRQ, | ||
| 140 | }, | ||
| 141 | }; | ||
| 142 | |||
| 143 | static struct mfd_cell tc3589x_dev_gpio[] = { | ||
| 144 | { | ||
| 145 | .name = "tc3589x-gpio", | ||
| 146 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
| 147 | .resources = &gpio_resources[0], | ||
| 148 | }, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static struct mfd_cell tc3589x_dev_keypad[] = { | ||
| 152 | { | ||
| 153 | .name = "tc3589x-keypad", | ||
| 154 | .num_resources = ARRAY_SIZE(keypad_resources), | ||
| 155 | .resources = &keypad_resources[0], | ||
| 156 | }, | ||
| 157 | }; | ||
| 158 | |||
| 159 | static irqreturn_t tc3589x_irq(int irq, void *data) | ||
| 160 | { | ||
| 161 | struct tc3589x *tc3589x = data; | ||
| 162 | int status; | ||
| 163 | |||
| 164 | again: | ||
| 165 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
| 166 | if (status < 0) | ||
| 167 | return IRQ_NONE; | ||
| 168 | |||
| 169 | while (status) { | ||
| 170 | int bit = __ffs(status); | ||
| 171 | |||
| 172 | handle_nested_irq(tc3589x->irq_base + bit); | ||
| 173 | status &= ~(1 << bit); | ||
| 174 | } | ||
| 175 | |||
| 176 | /* | ||
| 177 | * A dummy read or write (to any register) appears to be necessary to | ||
| 178 | * have the last interrupt clear (for example, GPIO IC write) take | ||
| 179 | * effect. In such a case, recheck for any interrupt which is still | ||
| 180 | * pending. | ||
| 181 | */ | ||
| 182 | status = tc3589x_reg_read(tc3589x, TC3589x_IRQST); | ||
| 183 | if (status) | ||
| 184 | goto again; | ||
| 185 | |||
| 186 | return IRQ_HANDLED; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int tc3589x_irq_init(struct tc3589x *tc3589x) | ||
| 190 | { | ||
| 191 | int base = tc3589x->irq_base; | ||
| 192 | int irq; | ||
| 193 | |||
| 194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
| 195 | set_irq_chip_data(irq, tc3589x); | ||
| 196 | set_irq_chip_and_handler(irq, &dummy_irq_chip, | ||
| 197 | handle_edge_irq); | ||
| 198 | set_irq_nested_thread(irq, 1); | ||
| 199 | #ifdef CONFIG_ARM | ||
| 200 | set_irq_flags(irq, IRQF_VALID); | ||
| 201 | #else | ||
| 202 | set_irq_noprobe(irq); | ||
| 203 | #endif | ||
| 204 | } | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | static void tc3589x_irq_remove(struct tc3589x *tc3589x) | ||
| 210 | { | ||
| 211 | int base = tc3589x->irq_base; | ||
| 212 | int irq; | ||
| 213 | |||
| 214 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | ||
| 215 | #ifdef CONFIG_ARM | ||
| 216 | set_irq_flags(irq, 0); | ||
| 217 | #endif | ||
| 218 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
| 219 | set_irq_chip_data(irq, NULL); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | static int tc3589x_chip_init(struct tc3589x *tc3589x) | ||
| 224 | { | ||
| 225 | int manf, ver, ret; | ||
| 226 | |||
| 227 | manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE); | ||
| 228 | if (manf < 0) | ||
| 229 | return manf; | ||
| 230 | |||
| 231 | ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION); | ||
| 232 | if (ver < 0) | ||
| 233 | return ver; | ||
| 234 | |||
| 235 | if (manf != TC3589x_MANFCODE_MAGIC) { | ||
| 236 | dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf); | ||
| 237 | return -EINVAL; | ||
| 238 | } | ||
| 239 | |||
| 240 | dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver); | ||
| 241 | |||
| 242 | /* | ||
| 243 | * Put everything except the IRQ module into reset; | ||
| 244 | * also spare the GPIO module for any pin initialization | ||
| 245 | * done during pre-kernel boot | ||
| 246 | */ | ||
| 247 | ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL, | ||
| 248 | TC3589x_RSTCTRL_TIMRST | ||
| 249 | | TC3589x_RSTCTRL_ROTRST | ||
| 250 | | TC3589x_RSTCTRL_KBDRST); | ||
| 251 | if (ret < 0) | ||
| 252 | return ret; | ||
| 253 | |||
| 254 | /* Clear the reset interrupt. */ | ||
| 255 | return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); | ||
| 256 | } | ||
| 257 | |||
| 258 | static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | ||
| 259 | { | ||
| 260 | int ret = 0; | ||
| 261 | unsigned int blocks = tc3589x->pdata->block; | ||
| 262 | |||
| 263 | if (blocks & TC3589x_BLOCK_GPIO) { | ||
| 264 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, | ||
| 265 | ARRAY_SIZE(tc3589x_dev_gpio), NULL, | ||
| 266 | tc3589x->irq_base); | ||
| 267 | if (ret) { | ||
| 268 | dev_err(tc3589x->dev, "failed to add gpio child\n"); | ||
| 269 | return ret; | ||
| 270 | } | ||
| 271 | dev_info(tc3589x->dev, "added gpio block\n"); | ||
| 272 | } | ||
| 273 | |||
| 274 | if (blocks & TC3589x_BLOCK_KEYPAD) { | ||
| 275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | ||
| 276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | ||
| 277 | tc3589x->irq_base); | ||
| 278 | if (ret) { | ||
| 279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | ||
| 280 | return ret; | ||
| 281 | } | ||
| 282 | dev_info(tc3589x->dev, "added keypad block\n"); | ||
| 283 | } | ||
| 284 | |||
| 285 | return ret; | ||
| 286 | } | ||
| 287 | |||
| 288 | static int __devinit tc3589x_probe(struct i2c_client *i2c, | ||
| 289 | const struct i2c_device_id *id) | ||
| 290 | { | ||
| 291 | struct tc3589x_platform_data *pdata = i2c->dev.platform_data; | ||
| 292 | struct tc3589x *tc3589x; | ||
| 293 | int ret; | ||
| 294 | |||
| 295 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | ||
| 296 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
| 297 | return -EIO; | ||
| 298 | |||
| 299 | tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); | ||
| 300 | if (!tc3589x) | ||
| 301 | return -ENOMEM; | ||
| 302 | |||
| 303 | mutex_init(&tc3589x->lock); | ||
| 304 | |||
| 305 | tc3589x->dev = &i2c->dev; | ||
| 306 | tc3589x->i2c = i2c; | ||
| 307 | tc3589x->pdata = pdata; | ||
| 308 | tc3589x->irq_base = pdata->irq_base; | ||
| 309 | tc3589x->num_gpio = id->driver_data; | ||
| 310 | |||
| 311 | i2c_set_clientdata(i2c, tc3589x); | ||
| 312 | |||
| 313 | ret = tc3589x_chip_init(tc3589x); | ||
| 314 | if (ret) | ||
| 315 | goto out_free; | ||
| 316 | |||
| 317 | ret = tc3589x_irq_init(tc3589x); | ||
| 318 | if (ret) | ||
| 319 | goto out_free; | ||
| 320 | |||
| 321 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, | ||
| 322 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| 323 | "tc3589x", tc3589x); | ||
| 324 | if (ret) { | ||
| 325 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | ||
| 326 | goto out_removeirq; | ||
| 327 | } | ||
| 328 | |||
| 329 | ret = tc3589x_device_init(tc3589x); | ||
| 330 | if (ret) { | ||
| 331 | dev_err(tc3589x->dev, "failed to add child devices\n"); | ||
| 332 | goto out_freeirq; | ||
| 333 | } | ||
| 334 | |||
| 335 | return 0; | ||
| 336 | |||
| 337 | out_freeirq: | ||
| 338 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
| 339 | out_removeirq: | ||
| 340 | tc3589x_irq_remove(tc3589x); | ||
| 341 | out_free: | ||
| 342 | kfree(tc3589x); | ||
| 343 | return ret; | ||
| 344 | } | ||
| 345 | |||
| 346 | static int __devexit tc3589x_remove(struct i2c_client *client) | ||
| 347 | { | ||
| 348 | struct tc3589x *tc3589x = i2c_get_clientdata(client); | ||
| 349 | |||
| 350 | mfd_remove_devices(tc3589x->dev); | ||
| 351 | |||
| 352 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
| 353 | tc3589x_irq_remove(tc3589x); | ||
| 354 | |||
| 355 | kfree(tc3589x); | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | static int tc3589x_suspend(struct device *dev) | ||
| 361 | { | ||
| 362 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
| 363 | struct i2c_client *client = tc3589x->i2c; | ||
| 364 | int ret = 0; | ||
| 365 | |||
| 366 | /* put the system to sleep mode */ | ||
| 367 | if (!device_may_wakeup(&client->dev)) | ||
| 368 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
| 369 | TC3589x_CLKMODE_MODCTL_SLEEP); | ||
| 370 | |||
| 371 | return ret; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int tc3589x_resume(struct device *dev) | ||
| 375 | { | ||
| 376 | struct tc3589x *tc3589x = dev_get_drvdata(dev); | ||
| 377 | struct i2c_client *client = tc3589x->i2c; | ||
| 378 | int ret = 0; | ||
| 379 | |||
| 380 | /* enable the system into operation */ | ||
| 381 | if (!device_may_wakeup(&client->dev)) | ||
| 382 | ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE, | ||
| 383 | TC3589x_CLKMODE_MODCTL_OPERATION); | ||
| 384 | |||
| 385 | return ret; | ||
| 386 | } | ||
| 387 | |||
| 388 | static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend, | ||
| 389 | tc3589x_resume); | ||
| 390 | |||
| 391 | static const struct i2c_device_id tc3589x_id[] = { | ||
| 392 | { "tc3589x", 24 }, | ||
| 393 | { } | ||
| 394 | }; | ||
| 395 | MODULE_DEVICE_TABLE(i2c, tc3589x_id); | ||
| 396 | |||
| 397 | static struct i2c_driver tc3589x_driver = { | ||
| 398 | .driver.name = "tc3589x", | ||
| 399 | .driver.owner = THIS_MODULE, | ||
| 400 | #ifdef CONFIG_PM | ||
| 401 | .driver.pm = &tc3589x_dev_pm_ops, | ||
| 402 | #endif | ||
| 403 | .probe = tc3589x_probe, | ||
| 404 | .remove = __devexit_p(tc3589x_remove), | ||
| 405 | .id_table = tc3589x_id, | ||
| 406 | }; | ||
| 407 | |||
| 408 | static int __init tc3589x_init(void) | ||
| 409 | { | ||
| 410 | return i2c_add_driver(&tc3589x_driver); | ||
| 411 | } | ||
| 412 | subsys_initcall(tc3589x_init); | ||
| 413 | |||
| 414 | static void __exit tc3589x_exit(void) | ||
| 415 | { | ||
| 416 | i2c_del_driver(&tc3589x_driver); | ||
| 417 | } | ||
| 418 | module_exit(tc3589x_exit); | ||
| 419 | |||
| 420 | MODULE_LICENSE("GPL v2"); | ||
| 421 | MODULE_DESCRIPTION("TC3589x MFD core driver"); | ||
| 422 | MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); | ||
diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c index 32b1c6fb2de1..5f771ab712c4 100644 --- a/drivers/net/caif/caif_shm_u5500.c +++ b/drivers/net/caif/caif_shm_u5500.c | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
| 14 | #include <mach/mbox.h> | 14 | #include <mach/mbox-db5500.h> |
| 15 | #include <net/caif/caif_shm.h> | 15 | #include <net/caif/caif_shm.h> |
| 16 | 16 | ||
| 17 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
diff --git a/include/linux/mfd/tc35892.h b/include/linux/mfd/tc35892.h deleted file mode 100644 index eff3094ca84e..000000000000 --- a/include/linux/mfd/tc35892.h +++ /dev/null | |||
| @@ -1,136 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef __LINUX_MFD_TC35892_H | ||
| 8 | #define __LINUX_MFD_TC35892_H | ||
| 9 | |||
| 10 | #include <linux/device.h> | ||
| 11 | |||
| 12 | #define TC35892_RSTCTRL_IRQRST (1 << 4) | ||
| 13 | #define TC35892_RSTCTRL_TIMRST (1 << 3) | ||
| 14 | #define TC35892_RSTCTRL_ROTRST (1 << 2) | ||
| 15 | #define TC35892_RSTCTRL_KBDRST (1 << 1) | ||
| 16 | #define TC35892_RSTCTRL_GPIRST (1 << 0) | ||
| 17 | |||
| 18 | #define TC35892_IRQST 0x91 | ||
| 19 | |||
| 20 | #define TC35892_MANFCODE_MAGIC 0x03 | ||
| 21 | #define TC35892_MANFCODE 0x80 | ||
| 22 | #define TC35892_VERSION 0x81 | ||
| 23 | #define TC35892_IOCFG 0xA7 | ||
| 24 | |||
| 25 | #define TC35892_CLKMODE 0x88 | ||
| 26 | #define TC35892_CLKCFG 0x89 | ||
| 27 | #define TC35892_CLKEN 0x8A | ||
| 28 | |||
| 29 | #define TC35892_RSTCTRL 0x82 | ||
| 30 | #define TC35892_EXTRSTN 0x83 | ||
| 31 | #define TC35892_RSTINTCLR 0x84 | ||
| 32 | |||
| 33 | #define TC35892_GPIOIS0 0xC9 | ||
| 34 | #define TC35892_GPIOIS1 0xCA | ||
| 35 | #define TC35892_GPIOIS2 0xCB | ||
| 36 | #define TC35892_GPIOIBE0 0xCC | ||
| 37 | #define TC35892_GPIOIBE1 0xCD | ||
| 38 | #define TC35892_GPIOIBE2 0xCE | ||
| 39 | #define TC35892_GPIOIEV0 0xCF | ||
| 40 | #define TC35892_GPIOIEV1 0xD0 | ||
| 41 | #define TC35892_GPIOIEV2 0xD1 | ||
| 42 | #define TC35892_GPIOIE0 0xD2 | ||
| 43 | #define TC35892_GPIOIE1 0xD3 | ||
| 44 | #define TC35892_GPIOIE2 0xD4 | ||
| 45 | #define TC35892_GPIORIS0 0xD6 | ||
| 46 | #define TC35892_GPIORIS1 0xD7 | ||
| 47 | #define TC35892_GPIORIS2 0xD8 | ||
| 48 | #define TC35892_GPIOMIS0 0xD9 | ||
| 49 | #define TC35892_GPIOMIS1 0xDA | ||
| 50 | #define TC35892_GPIOMIS2 0xDB | ||
| 51 | #define TC35892_GPIOIC0 0xDC | ||
| 52 | #define TC35892_GPIOIC1 0xDD | ||
| 53 | #define TC35892_GPIOIC2 0xDE | ||
| 54 | |||
| 55 | #define TC35892_GPIODATA0 0xC0 | ||
| 56 | #define TC35892_GPIOMASK0 0xc1 | ||
| 57 | #define TC35892_GPIODATA1 0xC2 | ||
| 58 | #define TC35892_GPIOMASK1 0xc3 | ||
| 59 | #define TC35892_GPIODATA2 0xC4 | ||
| 60 | #define TC35892_GPIOMASK2 0xC5 | ||
| 61 | |||
| 62 | #define TC35892_GPIODIR0 0xC6 | ||
| 63 | #define TC35892_GPIODIR1 0xC7 | ||
| 64 | #define TC35892_GPIODIR2 0xC8 | ||
| 65 | |||
| 66 | #define TC35892_GPIOSYNC0 0xE6 | ||
| 67 | #define TC35892_GPIOSYNC1 0xE7 | ||
| 68 | #define TC35892_GPIOSYNC2 0xE8 | ||
| 69 | |||
| 70 | #define TC35892_GPIOWAKE0 0xE9 | ||
| 71 | #define TC35892_GPIOWAKE1 0xEA | ||
| 72 | #define TC35892_GPIOWAKE2 0xEB | ||
| 73 | |||
| 74 | #define TC35892_GPIOODM0 0xE0 | ||
| 75 | #define TC35892_GPIOODE0 0xE1 | ||
| 76 | #define TC35892_GPIOODM1 0xE2 | ||
| 77 | #define TC35892_GPIOODE1 0xE3 | ||
| 78 | #define TC35892_GPIOODM2 0xE4 | ||
| 79 | #define TC35892_GPIOODE2 0xE5 | ||
| 80 | |||
| 81 | #define TC35892_INT_GPIIRQ 0 | ||
| 82 | #define TC35892_INT_TI0IRQ 1 | ||
| 83 | #define TC35892_INT_TI1IRQ 2 | ||
| 84 | #define TC35892_INT_TI2IRQ 3 | ||
| 85 | #define TC35892_INT_ROTIRQ 5 | ||
| 86 | #define TC35892_INT_KBDIRQ 6 | ||
| 87 | #define TC35892_INT_PORIRQ 7 | ||
| 88 | |||
| 89 | #define TC35892_NR_INTERNAL_IRQS 8 | ||
| 90 | #define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x)) | ||
| 91 | |||
| 92 | struct tc35892 { | ||
| 93 | struct mutex lock; | ||
| 94 | struct device *dev; | ||
| 95 | struct i2c_client *i2c; | ||
| 96 | |||
| 97 | int irq_base; | ||
| 98 | int num_gpio; | ||
| 99 | struct tc35892_platform_data *pdata; | ||
| 100 | }; | ||
| 101 | |||
| 102 | extern int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data); | ||
| 103 | extern int tc35892_reg_read(struct tc35892 *tc35892, u8 reg); | ||
| 104 | extern int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, | ||
| 105 | u8 *values); | ||
| 106 | extern int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length, | ||
| 107 | const u8 *values); | ||
| 108 | extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * struct tc35892_gpio_platform_data - TC35892 GPIO platform data | ||
| 112 | * @gpio_base: first gpio number assigned to TC35892. A maximum of | ||
| 113 | * %TC35892_NR_GPIOS GPIOs will be allocated. | ||
| 114 | * @setup: callback for board-specific initialization | ||
| 115 | * @remove: callback for board-specific teardown | ||
| 116 | */ | ||
| 117 | struct tc35892_gpio_platform_data { | ||
| 118 | int gpio_base; | ||
| 119 | void (*setup)(struct tc35892 *tc35892, unsigned gpio_base); | ||
| 120 | void (*remove)(struct tc35892 *tc35892, unsigned gpio_base); | ||
| 121 | }; | ||
| 122 | |||
| 123 | /** | ||
| 124 | * struct tc35892_platform_data - TC35892 platform data | ||
| 125 | * @irq_base: base IRQ number. %TC35892_NR_IRQS irqs will be used. | ||
| 126 | * @gpio: GPIO-specific platform data | ||
| 127 | */ | ||
| 128 | struct tc35892_platform_data { | ||
| 129 | int irq_base; | ||
| 130 | struct tc35892_gpio_platform_data *gpio; | ||
| 131 | }; | ||
| 132 | |||
| 133 | #define TC35892_NR_GPIOS 24 | ||
| 134 | #define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS) | ||
| 135 | |||
| 136 | #endif | ||
diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h new file mode 100644 index 000000000000..16c76e124f9c --- /dev/null +++ b/include/linux/mfd/tc3589x.h | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * License Terms: GNU General Public License, version 2 | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef __LINUX_MFD_TC3589x_H | ||
| 8 | #define __LINUX_MFD_TC3589x_H | ||
| 9 | |||
| 10 | #include <linux/device.h> | ||
| 11 | |||
| 12 | enum tx3589x_block { | ||
| 13 | TC3589x_BLOCK_GPIO = 1 << 0, | ||
| 14 | TC3589x_BLOCK_KEYPAD = 1 << 1, | ||
| 15 | }; | ||
| 16 | |||
| 17 | #define TC3589x_RSTCTRL_IRQRST (1 << 4) | ||
| 18 | #define TC3589x_RSTCTRL_TIMRST (1 << 3) | ||
| 19 | #define TC3589x_RSTCTRL_ROTRST (1 << 2) | ||
| 20 | #define TC3589x_RSTCTRL_KBDRST (1 << 1) | ||
| 21 | #define TC3589x_RSTCTRL_GPIRST (1 << 0) | ||
| 22 | |||
| 23 | /* Keyboard Configuration Registers */ | ||
| 24 | #define TC3589x_KBDSETTLE_REG 0x01 | ||
| 25 | #define TC3589x_KBDBOUNCE 0x02 | ||
| 26 | #define TC3589x_KBDSIZE 0x03 | ||
| 27 | #define TC3589x_KBCFG_LSB 0x04 | ||
| 28 | #define TC3589x_KBCFG_MSB 0x05 | ||
| 29 | #define TC3589x_KBDIC 0x08 | ||
| 30 | #define TC3589x_KBDMSK 0x09 | ||
| 31 | #define TC3589x_EVTCODE_FIFO 0x10 | ||
| 32 | #define TC3589x_KBDMFS 0x8F | ||
| 33 | |||
| 34 | #define TC3589x_IRQST 0x91 | ||
| 35 | |||
| 36 | #define TC3589x_MANFCODE_MAGIC 0x03 | ||
| 37 | #define TC3589x_MANFCODE 0x80 | ||
| 38 | #define TC3589x_VERSION 0x81 | ||
| 39 | #define TC3589x_IOCFG 0xA7 | ||
| 40 | |||
| 41 | #define TC3589x_CLKMODE 0x88 | ||
| 42 | #define TC3589x_CLKCFG 0x89 | ||
| 43 | #define TC3589x_CLKEN 0x8A | ||
| 44 | |||
| 45 | #define TC3589x_RSTCTRL 0x82 | ||
| 46 | #define TC3589x_EXTRSTN 0x83 | ||
| 47 | #define TC3589x_RSTINTCLR 0x84 | ||
| 48 | |||
| 49 | /* Pull up/down configuration registers */ | ||
| 50 | #define TC3589x_IOCFG 0xA7 | ||
| 51 | #define TC3589x_IOPULLCFG0_LSB 0xAA | ||
| 52 | #define TC3589x_IOPULLCFG0_MSB 0xAB | ||
| 53 | #define TC3589x_IOPULLCFG1_LSB 0xAC | ||
| 54 | #define TC3589x_IOPULLCFG1_MSB 0xAD | ||
| 55 | #define TC3589x_IOPULLCFG2_LSB 0xAE | ||
| 56 | |||
| 57 | #define TC3589x_GPIOIS0 0xC9 | ||
| 58 | #define TC3589x_GPIOIS1 0xCA | ||
| 59 | #define TC3589x_GPIOIS2 0xCB | ||
| 60 | #define TC3589x_GPIOIBE0 0xCC | ||
| 61 | #define TC3589x_GPIOIBE1 0xCD | ||
| 62 | #define TC3589x_GPIOIBE2 0xCE | ||
| 63 | #define TC3589x_GPIOIEV0 0xCF | ||
| 64 | #define TC3589x_GPIOIEV1 0xD0 | ||
| 65 | #define TC3589x_GPIOIEV2 0xD1 | ||
| 66 | #define TC3589x_GPIOIE0 0xD2 | ||
| 67 | #define TC3589x_GPIOIE1 0xD3 | ||
| 68 | #define TC3589x_GPIOIE2 0xD4 | ||
| 69 | #define TC3589x_GPIORIS0 0xD6 | ||
| 70 | #define TC3589x_GPIORIS1 0xD7 | ||
| 71 | #define TC3589x_GPIORIS2 0xD8 | ||
| 72 | #define TC3589x_GPIOMIS0 0xD9 | ||
| 73 | #define TC3589x_GPIOMIS1 0xDA | ||
| 74 | #define TC3589x_GPIOMIS2 0xDB | ||
| 75 | #define TC3589x_GPIOIC0 0xDC | ||
| 76 | #define TC3589x_GPIOIC1 0xDD | ||
| 77 | #define TC3589x_GPIOIC2 0xDE | ||
| 78 | |||
| 79 | #define TC3589x_GPIODATA0 0xC0 | ||
| 80 | #define TC3589x_GPIOMASK0 0xc1 | ||
| 81 | #define TC3589x_GPIODATA1 0xC2 | ||
| 82 | #define TC3589x_GPIOMASK1 0xc3 | ||
| 83 | #define TC3589x_GPIODATA2 0xC4 | ||
| 84 | #define TC3589x_GPIOMASK2 0xC5 | ||
| 85 | |||
| 86 | #define TC3589x_GPIODIR0 0xC6 | ||
| 87 | #define TC3589x_GPIODIR1 0xC7 | ||
| 88 | #define TC3589x_GPIODIR2 0xC8 | ||
| 89 | |||
| 90 | #define TC3589x_GPIOSYNC0 0xE6 | ||
| 91 | #define TC3589x_GPIOSYNC1 0xE7 | ||
| 92 | #define TC3589x_GPIOSYNC2 0xE8 | ||
| 93 | |||
| 94 | #define TC3589x_GPIOWAKE0 0xE9 | ||
| 95 | #define TC3589x_GPIOWAKE1 0xEA | ||
| 96 | #define TC3589x_GPIOWAKE2 0xEB | ||
| 97 | |||
| 98 | #define TC3589x_GPIOODM0 0xE0 | ||
| 99 | #define TC3589x_GPIOODE0 0xE1 | ||
| 100 | #define TC3589x_GPIOODM1 0xE2 | ||
| 101 | #define TC3589x_GPIOODE1 0xE3 | ||
| 102 | #define TC3589x_GPIOODM2 0xE4 | ||
| 103 | #define TC3589x_GPIOODE2 0xE5 | ||
| 104 | |||
| 105 | #define TC3589x_INT_GPIIRQ 0 | ||
| 106 | #define TC3589x_INT_TI0IRQ 1 | ||
| 107 | #define TC3589x_INT_TI1IRQ 2 | ||
| 108 | #define TC3589x_INT_TI2IRQ 3 | ||
| 109 | #define TC3589x_INT_ROTIRQ 5 | ||
| 110 | #define TC3589x_INT_KBDIRQ 6 | ||
| 111 | #define TC3589x_INT_PORIRQ 7 | ||
| 112 | |||
| 113 | #define TC3589x_NR_INTERNAL_IRQS 8 | ||
| 114 | #define TC3589x_INT_GPIO(x) (TC3589x_NR_INTERNAL_IRQS + (x)) | ||
| 115 | |||
| 116 | struct tc3589x { | ||
| 117 | struct mutex lock; | ||
| 118 | struct device *dev; | ||
| 119 | struct i2c_client *i2c; | ||
| 120 | |||
| 121 | int irq_base; | ||
| 122 | int num_gpio; | ||
| 123 | struct tc3589x_platform_data *pdata; | ||
| 124 | }; | ||
| 125 | |||
| 126 | extern int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data); | ||
| 127 | extern int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg); | ||
| 128 | extern int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, | ||
| 129 | u8 *values); | ||
| 130 | extern int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, | ||
| 131 | const u8 *values); | ||
| 132 | extern int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Keypad related platform specific constants | ||
| 136 | * These values may be modified for fine tuning | ||
| 137 | */ | ||
| 138 | #define TC_KPD_ROWS 0x8 | ||
| 139 | #define TC_KPD_COLUMNS 0x8 | ||
| 140 | #define TC_KPD_DEBOUNCE_PERIOD 0xA3 | ||
| 141 | #define TC_KPD_SETTLE_TIME 0xA3 | ||
| 142 | |||
| 143 | /** | ||
| 144 | * struct tc35893_platform_data - data structure for platform specific data | ||
| 145 | * @keymap_data: matrix scan code table for keycodes | ||
| 146 | * @krow: mask for available rows, value is 0xFF | ||
| 147 | * @kcol: mask for available columns, value is 0xFF | ||
| 148 | * @debounce_period: platform specific debounce time | ||
| 149 | * @settle_time: platform specific settle down time | ||
| 150 | * @irqtype: type of interrupt, falling or rising edge | ||
| 151 | * @enable_wakeup: specifies if keypad event can wake up system from sleep | ||
| 152 | * @no_autorepeat: flag for auto repetition | ||
| 153 | */ | ||
| 154 | struct tc3589x_keypad_platform_data { | ||
| 155 | const struct matrix_keymap_data *keymap_data; | ||
| 156 | u8 krow; | ||
| 157 | u8 kcol; | ||
| 158 | u8 debounce_period; | ||
| 159 | u8 settle_time; | ||
| 160 | unsigned long irqtype; | ||
| 161 | bool enable_wakeup; | ||
| 162 | bool no_autorepeat; | ||
| 163 | }; | ||
| 164 | |||
| 165 | /** | ||
| 166 | * struct tc3589x_gpio_platform_data - TC3589x GPIO platform data | ||
| 167 | * @gpio_base: first gpio number assigned to TC3589x. A maximum of | ||
| 168 | * %TC3589x_NR_GPIOS GPIOs will be allocated. | ||
| 169 | * @setup: callback for board-specific initialization | ||
| 170 | * @remove: callback for board-specific teardown | ||
| 171 | */ | ||
| 172 | struct tc3589x_gpio_platform_data { | ||
| 173 | int gpio_base; | ||
| 174 | void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base); | ||
| 175 | void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base); | ||
| 176 | }; | ||
| 177 | |||
| 178 | /** | ||
| 179 | * struct tc3589x_platform_data - TC3589x platform data | ||
| 180 | * @block: bitmask of blocks to enable (use TC3589x_BLOCK_*) | ||
| 181 | * @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used. | ||
| 182 | * @gpio: GPIO-specific platform data | ||
| 183 | * @keypad: keypad-specific platform data | ||
| 184 | */ | ||
| 185 | struct tc3589x_platform_data { | ||
| 186 | unsigned int block; | ||
| 187 | int irq_base; | ||
| 188 | struct tc3589x_gpio_platform_data *gpio; | ||
| 189 | const struct tc3589x_keypad_platform_data *keypad; | ||
| 190 | }; | ||
| 191 | |||
| 192 | #define TC3589x_NR_GPIOS 24 | ||
| 193 | #define TC3589x_NR_IRQS TC3589x_INT_GPIO(TC3589x_NR_GPIOS) | ||
| 194 | |||
| 195 | #endif | ||
