2 * arch/arm/mach-omap2/hsi.c
4 * HSI device definition
6 * Copyright (C) 2011 Texas Instruments, Inc.
7 * Original Author: Sebastien JAN <s-jan@ti.com>
9 * This package is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 #include <linux/device.h>
18 #include <linux/platform_device.h>
19 #include <linux/err.h>
20 #include <linux/clk.h>
22 #include <linux/gpio.h>
23 #include <linux/irq.h>
24 #include <linux/jiffies.h>
25 #include <linux/notifier.h>
26 #include <linux/hsi_driver_if.h>
28 #include <plat/omap_hsi.h>
29 #include <plat/omap_hwmod.h>
30 #include <plat/omap_device.h>
32 #include <../drivers/omap_hsi/hsi_driver.h>
39 static int omap_hsi_wakeup_enable(int hsi_port
);
40 static int omap_hsi_wakeup_disable(int hsi_port
);
41 #define OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME "omap_hsi"
42 #define OMAP_HSI_PLATFORM_DEVICE_NAME "omap_hsi.0"
43 #define OMAP_HSI_HWMOD_NAME "hsi"
44 #define OMAP_HSI_HWMOD_CLASSNAME "hsi"
47 #define OMAP_MUX_MODE_MASK 0x7
50 /* Hack till correct hwmod-mux api gets used */
51 #define CA_WAKE_MUX_REG (0x4a1000C2)
52 #define OMAP44XX_PADCONF_WAKEUPENABLE0 (1 << 14)
53 #define OMAP44XX_PADCONF_WAKEUPEVENT0 (1 << 15)
55 static int omap_mux_read_signal(const char *muxname
)
58 val
= omap_readw(CA_WAKE_MUX_REG
);
62 static int omap_mux_enable_wakeup(const char *muxname
)
65 val
= omap_readw(CA_WAKE_MUX_REG
);
66 val
|= OMAP44XX_PADCONF_WAKEUPENABLE0
;
67 omap_writew(val
, CA_WAKE_MUX_REG
);
71 static int omap_mux_disable_wakeup(const char *muxname
)
74 val
= omap_readw(CA_WAKE_MUX_REG
);
75 val
&= ~OMAP44XX_PADCONF_WAKEUPENABLE0
;
76 omap_writew(val
, CA_WAKE_MUX_REG
);
81 * NOTE: We abuse a little bit the struct port_ctx to use it also for
86 static struct hsi_port_ctx omap_hsi_port_ctx
[] = {
89 .hst
.mode
= HSI_MODE_FRAME
,
90 .hst
.flow
= HSI_FLOW_SYNCHRONIZED
,
91 .hst
.frame_size
= HSI_FRAMESIZE_DEFAULT
,
92 .hst
.divisor
= HSI_DIVISOR_DEFAULT
,
93 .hst
.channels
= HSI_CHANNELS_DEFAULT
,
94 .hst
.arb_mode
= HSI_ARBMODE_ROUNDROBIN
,
95 .hsr
.mode
= HSI_MODE_FRAME
,
96 .hsr
.flow
= HSI_FLOW_SYNCHRONIZED
,
97 .hsr
.frame_size
= HSI_FRAMESIZE_DEFAULT
,
98 .hsr
.channels
= HSI_CHANNELS_DEFAULT
,
99 .hsr
.divisor
= HSI_DIVISOR_DEFAULT
,
100 .hsr
.counters
= HSI_COUNTERS_FT_DEFAULT
|
101 HSI_COUNTERS_TB_DEFAULT
|
102 HSI_COUNTERS_FB_DEFAULT
,
103 .cawake_padconf_name
= "usbb1_ulpitll_clk.hsi1_cawake",
104 .cawake_padconf_hsi_mode
= OMAP_MUX_MODE1
,
108 static struct hsi_ctrl_ctx omap_hsi_ctrl_ctx
= {
112 .pctx
= omap_hsi_port_ctx
,
115 static struct hsi_platform_data omap_hsi_platform_data
= {
116 .num_ports
= ARRAY_SIZE(omap_hsi_port_ctx
),
117 .hsi_gdd_chan_count
= HSI_HSI_DMA_CHANNEL_MAX
,
118 .default_hsi_fclk
= HSI_DEFAULT_FCLK
,
119 .fifo_mapping_strategy
= HSI_FIFO_MAPPING_ALL_PORT1
,
120 .ctx
= &omap_hsi_ctrl_ctx
,
121 .device_enable
= omap_device_enable
,
122 .device_idle
= omap_device_idle
,
123 .device_shutdown
= omap_device_shutdown
,
124 .device_scale
= omap_device_scale
,
125 .wakeup_enable
= omap_hsi_wakeup_enable
,
126 .wakeup_disable
= omap_hsi_wakeup_disable
,
127 .wakeup_is_from_hsi
= omap_hsi_is_io_wakeup_from_hsi
,
128 .board_suspend
= omap_hsi_prepare_suspend
,
132 static u32
omap_hsi_configure_errata(void)
136 if (cpu_is_omap44xx()) {
137 SET_HSI_ERRATA(errata
, HSI_ERRATUM_i696_SW_RESET_FSM_STUCK
);
138 SET_HSI_ERRATA(errata
, HSI_ERRATUM_ixxx_3WIRES_NO_SWAKEUP
);
139 SET_HSI_ERRATA(errata
, HSI_ERRATUM_i702_PM_HSI_SWAKEUP
);
145 static struct platform_device
*hsi_get_hsi_platform_device(void)
148 struct platform_device
*pdev
;
150 /* HSI_TODO: handle platform device id (or port) (0/1) */
151 dev
= bus_find_device_by_name(&platform_bus_type
, NULL
,
152 OMAP_HSI_PLATFORM_DEVICE_NAME
);
154 pr_debug("Could not find platform device %s\n",
155 OMAP_HSI_PLATFORM_DEVICE_NAME
);
160 /* Could not find driver for platform device. */
164 pdev
= to_platform_device(dev
);
169 static struct hsi_dev
*hsi_get_hsi_controller_data(struct platform_device
*pd
)
171 struct hsi_dev
*hsi_ctrl
;
176 hsi_ctrl
= (struct hsi_dev
*) platform_get_drvdata(pd
);
178 pr_err("Could not find HSI controller data\n");
186 * hsi_get_hsi_port_ctx_data - Returns a pointer on the port context
188 * @hsi_port - port number to obtain context. Range [1, 2]
190 * Return value :* If success: pointer on the HSI port context requested
193 static struct hsi_port_ctx
*hsi_get_hsi_port_ctx_data(int hsi_port
)
197 for (i
= 0; i
< omap_hsi_platform_data
.num_ports
; i
++)
198 if (omap_hsi_platform_data
.ctx
->pctx
[i
].port_number
== hsi_port
)
199 return &omap_hsi_platform_data
.ctx
->pctx
[i
];
205 * omap_hsi_is_io_pad_hsi - Indicates if IO Pad has been muxed for HSI CAWAKE
207 * @hsi_port - port number to check for HSI muxing. Range [1, 2]
209 * Return value :* 0 if CAWAKE Padconf has not been found or CAWAKE not muxed for
213 static int omap_hsi_is_io_pad_hsi(int hsi_port
)
215 struct hsi_port_ctx
*port_ctx
;
218 port_ctx
= hsi_get_hsi_port_ctx_data(hsi_port
);
222 /* Check for IO pad */
223 val
= omap_mux_read_signal(port_ctx
->cawake_padconf_name
);
227 /* Continue only if CAWAKE is muxed */
228 if ((val
& OMAP_MUX_MODE_MASK
) != port_ctx
->cawake_padconf_hsi_mode
)
235 * omap_hsi_is_io_wakeup_from_hsi - Indicates an IO wakeup from HSI CAWAKE
237 * @hsi_port - returns port number which triggered wakeup. Range [1, 2].
238 * Only valid if return value is 1 (HSI wakeup detected)
240 * Return value :* false if CAWAKE Padconf has not been found or no IOWAKEUP event
241 * occured for CAWAKE.
242 * * true if HSI wakeup detected on port *hsi_port
244 bool omap_hsi_is_io_wakeup_from_hsi(int *hsi_port
)
246 struct hsi_port_ctx
*port_ctx
;
250 for (i
= 0; i
< omap_hsi_platform_data
.num_ports
; i
++) {
251 port_ctx
= &omap_hsi_platform_data
.ctx
->pctx
[i
];
253 /* Check for IO pad wakeup */
254 val
= omap_mux_read_signal(port_ctx
->cawake_padconf_name
);
258 /* Continue only if CAWAKE is muxed */
259 if ((val
& OMAP_MUX_MODE_MASK
) !=
260 port_ctx
->cawake_padconf_hsi_mode
)
263 if (val
& OMAP44XX_PADCONF_WAKEUPEVENT0
) {
264 *hsi_port
= port_ctx
->port_number
;
275 * omap_hsi_wakeup_enable - Enable HSI wakeup feature from RET/OFF mode
277 * @hsi_port - reference to the HSI port onto which enable wakeup feature.
280 * Return value :* 0 if CAWAKE has been configured to wakeup platform
281 * * -ENODEV if CAWAKE is not muxed on padconf
283 static int omap_hsi_wakeup_enable(int hsi_port
)
285 struct hsi_port_ctx
*port_ctx
;
288 if (omap_hsi_is_io_pad_hsi(hsi_port
)) {
289 port_ctx
= hsi_get_hsi_port_ctx_data(hsi_port
);
290 ret
= omap_mux_enable_wakeup(port_ctx
->cawake_padconf_name
);
291 omap4_trigger_ioctrl();
293 pr_debug("HSI port %d not muxed, failed to enable IO wakeup\n",
301 * omap_hsi_wakeup_disable - Disable HSI wakeup feature from RET/OFF mode
303 * @hsi_port - reference to the HSI port onto which disable wakeup feature.
306 * Return value :* 0 if CAWAKE has been configured to not wakeup platform
307 * * -ENODEV if CAWAKE is not muxed on padconf
309 static int omap_hsi_wakeup_disable(int hsi_port
)
311 struct hsi_port_ctx
*port_ctx
;
314 if (omap_hsi_is_io_pad_hsi(hsi_port
)) {
315 port_ctx
= hsi_get_hsi_port_ctx_data(hsi_port
);
316 ret
= omap_mux_disable_wakeup(port_ctx
->cawake_padconf_name
);
317 omap4_trigger_ioctrl();
319 pr_debug("HSI port %d not muxed, failed to disable IO wakeup\n",
327 * omap_hsi_prepare_suspend - Prepare HSI for suspend mode
329 * @hsi_port - reference to the HSI port. Range [1, 2]
330 * @dev_may_wakeup - value of sysfs flag indicating device wakeup capability
332 * Return value :* 0 if CAWAKE padconf has been configured properly
333 * * -ENODEV if CAWAKE is not muxed on padconf.
336 int omap_hsi_prepare_suspend(int hsi_port
, bool dev_may_wakeup
)
341 ret
= omap_hsi_wakeup_enable(hsi_port
);
343 ret
= omap_hsi_wakeup_disable(hsi_port
);
349 * omap_hsi_io_wakeup_check - Check if IO wakeup is from HSI and schedule HSI
352 * Return value : * 0 if HSI tasklet scheduled.
353 * * negative value else.
355 int omap_hsi_io_wakeup_check(void)
357 int hsi_port
, ret
= -1;
359 /* Modem HSI wakeup */
360 if (omap_hsi_is_io_wakeup_from_hsi(&hsi_port
))
361 ret
= omap_hsi_wakeup(hsi_port
);
367 * omap_hsi_wakeup - Prepare HSI for wakeup from suspend mode (RET/OFF)
369 * @hsi_port - reference to the HSI port which triggered wakeup.
372 * Return value : * 0 if HSI tasklet scheduled.
373 * * negative value else.
375 int omap_hsi_wakeup(int hsi_port
)
377 static struct platform_device
*pdev
;
378 static struct hsi_dev
*hsi_ctrl
;
382 pdev
= hsi_get_hsi_platform_device();
387 if (!device_may_wakeup(&pdev
->dev
)) {
388 dev_info(&pdev
->dev
, "Modem not allowed to wakeup platform\n");
393 hsi_ctrl
= hsi_get_hsi_controller_data(pdev
);
398 for (i
= 0; i
< omap_hsi_platform_data
.num_ports
; i
++) {
399 if (omap_hsi_platform_data
.ctx
->pctx
[i
].port_number
== hsi_port
)
403 if (i
== omap_hsi_platform_data
.num_ports
)
407 /* Check no other interrupt handler has already scheduled the tasklet */
408 if (test_and_set_bit(HSI_FLAGS_TASKLET_LOCK
,
409 &hsi_ctrl
->hsi_port
[i
].flags
))
412 dev_dbg(hsi_ctrl
->dev
, "Modem wakeup detected from HSI CAWAKE Pad port "
415 /* CAWAKE falling or rising edge detected */
416 hsi_ctrl
->hsi_port
[i
].cawake_off_event
= true;
417 tasklet_hi_schedule(&hsi_ctrl
->hsi_port
[i
].hsi_tasklet
);
419 /* Disable interrupt until Bottom Half has cleared */
420 /* the IRQ status register */
421 disable_irq_nosync(hsi_ctrl
->hsi_port
[i
].irq
);
426 /* HSI_TODO : This requires some fine tuning & completion of
427 * activate/deactivate latency values
429 static struct omap_device_pm_latency omap_hsi_latency
[] = {
431 .deactivate_func
= omap_device_idle_hwmods
,
432 .activate_func
= omap_device_enable_hwmods
,
433 .flags
= OMAP_DEVICE_LATENCY_AUTO_ADJUST
,
437 /* HSI device registration */
438 static int __init
omap_hsi_register(struct omap_hwmod
*oh
, void *user
)
440 struct omap_device
*od
;
441 struct hsi_platform_data
*pdata
= &omap_hsi_platform_data
;
444 pr_err("Could not look up %s omap_hwmod\n",
445 OMAP_HSI_HWMOD_NAME
);
449 omap_hsi_platform_data
.errata
= omap_hsi_configure_errata();
451 od
= omap_device_build(OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME
, 0, oh
,
452 pdata
, sizeof(*pdata
), omap_hsi_latency
,
453 ARRAY_SIZE(omap_hsi_latency
), false);
454 WARN(IS_ERR(od
), "Can't build omap_device for %s:%s.\n",
455 OMAP_HSI_PLATFORM_DEVICE_DRIVER_NAME
, oh
->name
);
457 pr_info("HSI: device registered as omap_hwmod: %s\n", oh
->name
);
461 static void __init
omap_4430hsi_pad_conf(void)
464 * HSI pad conf: hsi1_ca/ac_wake/flag/data/ready
465 * Also configure gpio_92/95/157/187 used by modem
468 omap_mux_init_signal("usbb1_ulpitll_clk.hsi1_cawake", \
469 OMAP_PIN_INPUT_PULLDOWN
| \
470 OMAP_PIN_OFF_NONE
| \
471 OMAP_PIN_OFF_WAKEUPENABLE
);
473 omap_mux_init_signal("usbb1_ulpitll_dir.hsi1_caflag", \
477 omap_mux_init_signal("usbb1_ulpitll_stp.hsi1_cadata", \
481 omap_mux_init_signal("usbb1_ulpitll_nxt.hsi1_acready", \
485 omap_mux_init_signal("usbb1_ulpitll_dat0.hsi1_acwake", \
489 omap_mux_init_signal("usbb1_ulpitll_dat1.hsi1_acdata", \
493 omap_mux_init_signal("usbb1_ulpitll_dat2.hsi1_acflag", \
497 omap_mux_init_signal("usbb1_ulpitll_dat3.hsi1_caready", \
501 omap_mux_init_signal("usbb1_ulpitll_dat4.gpio_92", \
504 omap_mux_init_signal("usbb1_ulpitll_dat7.gpio_95", \
505 OMAP_PIN_INPUT_PULLDOWN
| \
508 omap_mux_init_signal("usbb2_ulpitll_clk.gpio_157", \
512 omap_mux_init_signal("sys_boot3.gpio_187", \
517 int __init
omap_hsi_dev_init(void)
519 /* Keep this for genericity, although there is only one hwmod for HSI */
520 return omap_hwmod_for_each_by_class(OMAP_HSI_HWMOD_CLASSNAME
,
521 omap_hsi_register
, NULL
);
523 postcore_initcall(omap_hsi_dev_init
);
525 /* HSI devices registration */
526 int __init
omap_hsi_init(void)
528 omap_4430hsi_pad_conf();