avtimer: msm: allow driver to register to SSR framework
Sub System Restart[SSR] framework allows driver to handle unexpected crash in middle of operation. Also, adding support clk_div dtsi entry to calculate avtimer_lsw value. Change-Id: I521e3c010dadd00a06a0fe8998a1759b2eb81b55 Signed-off-by: Asish Bhattacharya <asishb@codeaurora.org> Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
This commit is contained in:
parent
9eec4f972e
commit
172f93ee42
|
@ -12,10 +12,15 @@ Required properties:
|
|||
"avtimer_msb_addr" : AVtimer msb physical address
|
||||
- compatible : Must be "qcom,avtimer"
|
||||
|
||||
Optional properties:
|
||||
- clk_div : For 8916 the clk is at 27MHz and hence ticks are to be
|
||||
divided by 27 to achive the msec value.
|
||||
|
||||
Example:
|
||||
qcom,avtimer {
|
||||
compatible = "qcom,avtimer";
|
||||
reg = <0xfe053008 0x4>,
|
||||
<0xfe05300c 0x4>;
|
||||
reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
|
||||
qcom,clk_div = <27>;
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/avtimer.h>
|
||||
#include <linux/avtimer_kernel.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/msmb_isp.h>
|
||||
#include <mach/msm_bus.h>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <mach/qdsp6v2/apr.h>
|
||||
#include <sound/q6core.h>
|
||||
|
||||
#define DEVICE_NAME "avtimer"
|
||||
#define TIMEOUT_MS 1000
|
||||
|
@ -58,6 +59,8 @@ struct avtimer_t {
|
|||
int timer_handle;
|
||||
void __iomem *p_avtimer_msw;
|
||||
void __iomem *p_avtimer_lsw;
|
||||
uint32_t clk_div;
|
||||
atomic_t adsp_ready;
|
||||
};
|
||||
|
||||
static struct avtimer_t avtimer;
|
||||
|
@ -102,6 +105,7 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
|
|||
pr_debug("%s: Reset event received in AV timer\n", __func__);
|
||||
apr_reset(avtimer.core_handle_q);
|
||||
avtimer.core_handle_q = NULL;
|
||||
atomic_set(&avtimer.adsp_ready, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -239,8 +243,10 @@ int avcs_core_disable_power_collapse(int enable)
|
|||
goto done;
|
||||
}
|
||||
rc = avcs_core_enable_avtimer("timer");
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
avtimer.avtimer_open_cnt++;
|
||||
atomic_set(&avtimer.adsp_ready, 1);
|
||||
}
|
||||
} else {
|
||||
if (avtimer.avtimer_open_cnt > 0) {
|
||||
avtimer.avtimer_open_cnt--;
|
||||
|
@ -257,6 +263,31 @@ done:
|
|||
}
|
||||
EXPORT_SYMBOL(avcs_core_disable_power_collapse);
|
||||
|
||||
int avcs_core_query_timer(uint64_t *avtimer_tick)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t avtimer_msw = 0, avtimer_lsw = 0;
|
||||
|
||||
if (!atomic_read(&avtimer.adsp_ready)) {
|
||||
if (q6core_is_adsp_ready()) {
|
||||
ret = avcs_core_disable_power_collapse(1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
return -ENETRESET;
|
||||
}
|
||||
}
|
||||
avtimer_msw = ioread32(avtimer.p_avtimer_msw);
|
||||
avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
|
||||
|
||||
avtimer_lsw = avtimer_lsw/avtimer.clk_div;
|
||||
*avtimer_tick =
|
||||
(uint64_t)((uint64_t)avtimer_msw << 32)
|
||||
| avtimer_lsw;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(avcs_core_query_timer);
|
||||
|
||||
static int avtimer_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return avcs_core_disable_power_collapse(1);
|
||||
|
@ -285,6 +316,7 @@ static long avtimer_ioctl(struct file *file, unsigned int ioctl_num,
|
|||
avtimer_msw_2nd = ioread32(avtimer.p_avtimer_msw);
|
||||
} while (avtimer_msw_1st != avtimer_msw_2nd);
|
||||
|
||||
avtimer_lsw = avtimer_lsw/avtimer.clk_div;
|
||||
avtimer_tick =
|
||||
((uint64_t) avtimer_msw_1st << 32) | avtimer_lsw;
|
||||
|
||||
|
@ -317,6 +349,7 @@ static int dev_avtimer_probe(struct platform_device *pdev)
|
|||
dev_t dev = MKDEV(major, 0);
|
||||
struct device *device_handle;
|
||||
struct resource *reg_lsb = NULL, *reg_msb = NULL;
|
||||
uint32_t clk_div_val;
|
||||
|
||||
if (!pdev) {
|
||||
pr_err("%s: Invalid params\n", __func__);
|
||||
|
@ -360,14 +393,15 @@ static int dev_avtimer_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (result < 0) {
|
||||
pr_err("%s: Registering avtimer device failed\n", __func__);
|
||||
dev_err(&pdev->dev, "%s: Registering avtimer device failed\n",
|
||||
__func__);
|
||||
goto unmap;
|
||||
}
|
||||
|
||||
avtimer.avtimer_class = class_create(THIS_MODULE, "avtimer");
|
||||
if (IS_ERR(avtimer.avtimer_class)) {
|
||||
result = PTR_ERR(avtimer.avtimer_class);
|
||||
pr_err("%s: Error creating avtimer class: %d\n",
|
||||
dev_err(&pdev->dev, "%s: Error creating avtimer class: %d\n",
|
||||
__func__, result);
|
||||
goto unregister_chrdev_region;
|
||||
}
|
||||
|
@ -376,7 +410,8 @@ static int dev_avtimer_probe(struct platform_device *pdev)
|
|||
result = cdev_add(&avtimer.myc, dev, 1);
|
||||
|
||||
if (result < 0) {
|
||||
pr_err("%s: Registering file operations failed\n", __func__);
|
||||
dev_err(&pdev->dev, "%s: Registering file operations failed\n",
|
||||
__func__);
|
||||
goto class_destroy;
|
||||
}
|
||||
|
||||
|
@ -394,6 +429,13 @@ static int dev_avtimer_probe(struct platform_device *pdev)
|
|||
pr_debug("%s: Device create done for avtimer major=%d\n",
|
||||
__func__, major);
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"qcom,clk_div", &clk_div_val))
|
||||
avtimer.clk_div = 1;
|
||||
else
|
||||
avtimer.clk_div = clk_div_val;
|
||||
|
||||
pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
|
||||
return 0;
|
||||
|
||||
class_destroy:
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AVTIMER_H
|
||||
#define _AVTIMER_H
|
||||
|
||||
#include <uapi/linux/avtimer.h>
|
||||
|
||||
int avcs_core_open(void);
|
||||
int avcs_core_disable_power_collapse(int disable);/* true or flase */
|
||||
int avcs_core_query_timer(uint64_t *avtimer_tick);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _UAPI_AVTIMER_H
|
||||
#define _UAPI_AVTIMER_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define MAJOR_NUM 100
|
||||
|
||||
#define IOCTL_GET_AVTIMER_TICK _IOR(MAJOR_NUM, 0, char *)
|
||||
/*
|
||||
* This IOCTL is used read the avtimer tick value.
|
||||
* Avtimer is a 64 bit timer tick, hence the expected
|
||||
* argument is of type uint64_t
|
||||
*/
|
||||
struct dev_avtimer_data {
|
||||
uint32_t avtimer_msw_phy_addr;
|
||||
uint32_t avtimer_lsw_phy_addr;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue