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:
Laxminath Kasam 2014-09-22 16:00:37 +05:30
parent 9eec4f972e
commit 172f93ee42
5 changed files with 95 additions and 5 deletions

View File

@ -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>;
};

View File

@ -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>

View File

@ -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:

View File

@ -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

View File

@ -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