From 172f93ee424bc28d23b7673ad06e4b3375feb0c7 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Mon, 22 Sep 2014 16:00:37 +0530 Subject: [PATCH] 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 Signed-off-by: Laxminath Kasam --- .../bindings/platform/msm/avtimer.txt | 5 ++ .../platform/msm/camera_v2/isp/msm_isp.h | 2 +- drivers/platform/msm/avtimer.c | 50 +++++++++++++++++-- include/linux/avtimer_kernel.h | 24 +++++++++ include/uapi/linux/avtimer.h | 19 +++++++ 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 include/linux/avtimer_kernel.h create mode 100644 include/uapi/linux/avtimer.h diff --git a/Documentation/devicetree/bindings/platform/msm/avtimer.txt b/Documentation/devicetree/bindings/platform/msm/avtimer.txt index 86c9b676ad5..2d892623f9c 100644 --- a/Documentation/devicetree/bindings/platform/msm/avtimer.txt +++ b/Documentation/devicetree/bindings/platform/msm/avtimer.txt @@ -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>; }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index e8702e4f0ab..08cc00c2380 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/platform/msm/avtimer.c b/drivers/platform/msm/avtimer.c index d5fa885fcfa..fbbf7f67ce2 100644 --- a/drivers/platform/msm/avtimer.c +++ b/drivers/platform/msm/avtimer.c @@ -25,6 +25,7 @@ #include #include #include +#include #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: diff --git a/include/linux/avtimer_kernel.h b/include/linux/avtimer_kernel.h new file mode 100644 index 00000000000..5eff8ccff4c --- /dev/null +++ b/include/linux/avtimer_kernel.h @@ -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 + +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 diff --git a/include/uapi/linux/avtimer.h b/include/uapi/linux/avtimer.h new file mode 100644 index 00000000000..f688b380e28 --- /dev/null +++ b/include/uapi/linux/avtimer.h @@ -0,0 +1,19 @@ +#ifndef _UAPI_AVTIMER_H +#define _UAPI_AVTIMER_H + +#include + +#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