blob: 0506e7e09da1b9af3df911f8205fe77e06081ee0 [file] [log] [blame]
Joonwoo Park4a14a552012-08-02 11:03:21 -07001/*
Bharath Ramachandramurthy15c509c2013-03-22 16:31:08 -07002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Joonwoo Park4a14a552012-08-02 11:03:21 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/err.h>
18#include <linux/delay.h>
19#include <linux/platform_device.h>
Stephen Boyd77db8bb2012-06-27 15:15:16 -070020#include <mach/subsystem_restart.h>
Joonwoo Park4a14a552012-08-02 11:03:21 -070021#include <mach/qdsp6v2/apr.h>
Venkat Sudhir480db8a2012-11-09 15:31:50 -080022#include <linux/of_device.h>
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070023#include <linux/sysfs.h>
Joonwoo Park4a14a552012-08-02 11:03:21 -070024
25#define Q6_PIL_GET_DELAY_MS 100
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070026#define BOOT_CMD 1
27
28static ssize_t adsp_boot_store(struct kobject *kobj,
29 struct kobj_attribute *attr,
30 const char *buf, size_t count);
Joonwoo Park4a14a552012-08-02 11:03:21 -070031
32struct adsp_loader_private {
33 void *pil_h;
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070034 struct kobject *boot_adsp_obj;
35 struct attribute_group *attr_group;
Joonwoo Park4a14a552012-08-02 11:03:21 -070036};
37
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070038static struct kobj_attribute adsp_boot_attribute =
39 __ATTR(boot, 0220, NULL, adsp_boot_store);
40
41static struct attribute *attrs[] = {
42 &adsp_boot_attribute.attr,
43 NULL,
44};
45
46static struct platform_device *adsp_private;
47
48static void adsp_loader_do(struct platform_device *pdev)
Joonwoo Park4a14a552012-08-02 11:03:21 -070049{
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070050
51 struct adsp_loader_private *priv = NULL;
52
Venkat Sudhir480db8a2012-11-09 15:31:50 -080053 const char *adsp_dt = "qcom,adsp-state";
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070054 int rc = 0;
Venkat Sudhir480db8a2012-11-09 15:31:50 -080055 u32 adsp_state;
Joonwoo Park4a14a552012-08-02 11:03:21 -070056
Venkat Sudhir480db8a2012-11-09 15:31:50 -080057 rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
58 if (rc) {
59 dev_err(&pdev->dev,
60 "%s: ADSP state = %x\n", __func__, adsp_state);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070061 return;
Joonwoo Park4a14a552012-08-02 11:03:21 -070062 }
63
Venkat Sudhir480db8a2012-11-09 15:31:50 -080064 if (adsp_state == APR_SUBSYS_DOWN) {
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070065 if (pdev) {
66 priv = platform_get_drvdata(pdev);
67 } else {
68 pr_err("%s: Private data get failed\n", __func__);
69 goto fail;
70 }
Joonwoo Park4a14a552012-08-02 11:03:21 -070071
Venkat Sudhir480db8a2012-11-09 15:31:50 -080072
73 priv->pil_h = subsystem_get("adsp");
74 if (IS_ERR(priv->pil_h)) {
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070075 pr_err("%s: pil get failed,\n",
76 __func__);
Venkat Sudhir480db8a2012-11-09 15:31:50 -080077 goto fail;
78 }
79
Venkat Sudhir480db8a2012-11-09 15:31:50 -080080 /* Set the state of the ADSP in APR driver */
81 apr_set_q6_state(APR_SUBSYS_LOADED);
82 } else if (adsp_state == APR_SUBSYS_LOADED) {
83 dev_dbg(&pdev->dev,
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070084 "%s: ADSP state = %x\n", __func__, adsp_state);
Venkat Sudhir480db8a2012-11-09 15:31:50 -080085 apr_set_q6_state(APR_SUBSYS_LOADED);
86 }
Joonwoo Park4a14a552012-08-02 11:03:21 -070087
Joonwoo Park4a14a552012-08-02 11:03:21 -070088
89 pr_info("%s: Q6/ADSP image is loaded\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070090 return;
Joonwoo Park4a14a552012-08-02 11:03:21 -070091fail:
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070092
93 pr_err("%s: Q6/ADSP image loading failed\n", __func__);
94 return;
95}
96
97
98static ssize_t adsp_boot_store(struct kobject *kobj,
99 struct kobj_attribute *attr,
100 const char *buf,
101 size_t count)
102{
103 int boot = 0;
104 sscanf(buf, "%du", &boot);
105
106 if (boot == BOOT_CMD) {
107 pr_debug("%s:going to call adsp_loader_do", __func__);
108 adsp_loader_do(adsp_private);
109 }
110 return count;
111}
112
113static int adsp_loader_init_sysfs(struct platform_device *pdev)
114{
115 int ret = -EINVAL;
116 struct adsp_loader_private *priv = NULL;
117 adsp_private = NULL;
118
119 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
120 if (!priv) {
121 pr_err("%s: memory alloc failed\n", __func__);
122 ret = -ENOMEM;
123 goto error_return;
124 }
125
126 platform_set_drvdata(pdev, priv);
127
128 priv->pil_h = NULL;
129 priv->boot_adsp_obj = NULL;
130 priv->attr_group = devm_kzalloc(&pdev->dev,
131 sizeof(*(priv->attr_group)),
132 GFP_KERNEL);
133 if (!priv->attr_group) {
134 pr_err("%s: malloc attr_group failed\n",
135 __func__);
136 ret = -ENOMEM;
137 goto error_return;
138 }
139
140 priv->attr_group->attrs = attrs;
141
142 priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
143 if (!priv->boot_adsp_obj) {
144 pr_err("%s: sysfs create and add failed\n",
145 __func__);
146 ret = -ENOMEM;
147 goto error_return;
148 }
149
150 ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
151 if (ret) {
152 pr_err("%s: sysfs create group failed %d\n", \
153 __func__, ret);
154 goto error_return;
155 }
156
157 adsp_private = pdev;
158
159 return 0;
160
161error_return:
162
163 if (priv->boot_adsp_obj) {
164 kobject_del(priv->boot_adsp_obj);
165 priv->boot_adsp_obj = NULL;
166 }
167
168 return ret;
Joonwoo Park4a14a552012-08-02 11:03:21 -0700169}
170
171static int adsp_loader_remove(struct platform_device *pdev)
172{
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700173 struct adsp_loader_private *priv = NULL;
Joonwoo Park4a14a552012-08-02 11:03:21 -0700174
175 priv = platform_get_drvdata(pdev);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700176
177 if (!priv)
178 return 0;
179
180 if (priv->pil_h) {
Venkat Sudhir480db8a2012-11-09 15:31:50 -0800181 subsystem_put(priv->pil_h);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700182 priv->pil_h = NULL;
183 }
184
185 if (priv->boot_adsp_obj) {
186 sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
187 kobject_del(priv->boot_adsp_obj);
188 priv->boot_adsp_obj = NULL;
189 }
190
191 return 0;
192}
193
194static int adsp_loader_probe(struct platform_device *pdev)
195{
196 int ret = adsp_loader_init_sysfs(pdev);
197 if (ret != 0) {
198 pr_err("%s: Error in initing sysfs\n", __func__);
199 return ret;
200 }
Joonwoo Park4a14a552012-08-02 11:03:21 -0700201
202 return 0;
203}
204
205static const struct of_device_id adsp_loader_dt_match[] = {
206 { .compatible = "qcom,adsp-loader" },
207 { }
208};
209MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
210
211static struct platform_driver adsp_loader_driver = {
212 .driver = {
213 .name = "adsp-loader",
214 .owner = THIS_MODULE,
215 .of_match_table = adsp_loader_dt_match,
216 },
217 .probe = adsp_loader_probe,
218 .remove = __devexit_p(adsp_loader_remove),
219};
220
221static int __init adsp_loader_init(void)
222{
223 return platform_driver_register(&adsp_loader_driver);
224}
225module_init(adsp_loader_init);
226
227static void __exit adsp_loader_exit(void)
228{
229 platform_driver_unregister(&adsp_loader_driver);
230}
231module_exit(adsp_loader_exit);
232
233MODULE_DESCRIPTION("ADSP Loader module");
234MODULE_LICENSE("GPL v2");