blob: 0bd2010001cd862cd745b1c01d6e720ccecda0ba [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
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -070057 if (!pdev) {
58 dev_err(&pdev->dev, "%s: Platform device null \n", __func__);
59 goto fail;
60 }
61
62 if (!pdev->dev.of_node) {
63 dev_err(&pdev->dev,
64 "%s: Device tree information missing \n", __func__);
65 goto fail;
66 }
67
Venkat Sudhir480db8a2012-11-09 15:31:50 -080068 rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
69 if (rc) {
70 dev_err(&pdev->dev,
71 "%s: ADSP state = %x\n", __func__, adsp_state);
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -070072 goto fail;
Joonwoo Park4a14a552012-08-02 11:03:21 -070073 }
74
Venkat Sudhir480db8a2012-11-09 15:31:50 -080075 if (adsp_state == APR_SUBSYS_DOWN) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -070076 priv = platform_get_drvdata(pdev);
77 if (!priv) {
78 dev_err(&pdev->dev,
79 " %s: Private data get failed\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070080 goto fail;
81 }
Joonwoo Park4a14a552012-08-02 11:03:21 -070082
Venkat Sudhir480db8a2012-11-09 15:31:50 -080083
84 priv->pil_h = subsystem_get("adsp");
85 if (IS_ERR(priv->pil_h)) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -070086 dev_err(&pdev->dev, "%s: pil get failed,\n",
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070087 __func__);
Venkat Sudhir480db8a2012-11-09 15:31:50 -080088 goto fail;
89 }
90
Venkat Sudhir480db8a2012-11-09 15:31:50 -080091 /* Set the state of the ADSP in APR driver */
92 apr_set_q6_state(APR_SUBSYS_LOADED);
93 } else if (adsp_state == APR_SUBSYS_LOADED) {
94 dev_dbg(&pdev->dev,
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -070095 "%s: ADSP state = %x\n", __func__, adsp_state);
Venkat Sudhir480db8a2012-11-09 15:31:50 -080096 apr_set_q6_state(APR_SUBSYS_LOADED);
97 }
Joonwoo Park4a14a552012-08-02 11:03:21 -070098
Joonwoo Park4a14a552012-08-02 11:03:21 -070099
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700100 dev_info(&pdev->dev, "%s: Q6/ADSP image is loaded\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700101 return;
Joonwoo Park4a14a552012-08-02 11:03:21 -0700102fail:
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700103
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700104 dev_err(&pdev->dev, "%s: Q6/ADSP image loading failed\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700105 return;
106}
107
108
109static ssize_t adsp_boot_store(struct kobject *kobj,
110 struct kobj_attribute *attr,
111 const char *buf,
112 size_t count)
113{
114 int boot = 0;
115 sscanf(buf, "%du", &boot);
116
117 if (boot == BOOT_CMD) {
118 pr_debug("%s:going to call adsp_loader_do", __func__);
119 adsp_loader_do(adsp_private);
120 }
121 return count;
122}
123
124static int adsp_loader_init_sysfs(struct platform_device *pdev)
125{
126 int ret = -EINVAL;
127 struct adsp_loader_private *priv = NULL;
128 adsp_private = NULL;
129
130 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
131 if (!priv) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700132 dev_err(&pdev->dev, "%s: memory alloc failed\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700133 ret = -ENOMEM;
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700134 return ret;
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700135 }
136
137 platform_set_drvdata(pdev, priv);
138
139 priv->pil_h = NULL;
140 priv->boot_adsp_obj = NULL;
141 priv->attr_group = devm_kzalloc(&pdev->dev,
142 sizeof(*(priv->attr_group)),
143 GFP_KERNEL);
144 if (!priv->attr_group) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700145 dev_err(&pdev->dev, "%s: malloc attr_group failed\n",
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700146 __func__);
147 ret = -ENOMEM;
148 goto error_return;
149 }
150
151 priv->attr_group->attrs = attrs;
152
153 priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
154 if (!priv->boot_adsp_obj) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700155 dev_err(&pdev->dev, "%s: sysfs create and add failed\n",
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700156 __func__);
157 ret = -ENOMEM;
158 goto error_return;
159 }
160
161 ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
162 if (ret) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700163 dev_err(&pdev->dev, "%s: sysfs create group failed %d\n", \
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700164 __func__, ret);
165 goto error_return;
166 }
167
168 adsp_private = pdev;
169
170 return 0;
171
172error_return:
173
174 if (priv->boot_adsp_obj) {
175 kobject_del(priv->boot_adsp_obj);
176 priv->boot_adsp_obj = NULL;
177 }
178
179 return ret;
Joonwoo Park4a14a552012-08-02 11:03:21 -0700180}
181
182static int adsp_loader_remove(struct platform_device *pdev)
183{
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700184 struct adsp_loader_private *priv = NULL;
Joonwoo Park4a14a552012-08-02 11:03:21 -0700185
186 priv = platform_get_drvdata(pdev);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700187
188 if (!priv)
189 return 0;
190
191 if (priv->pil_h) {
Venkat Sudhir480db8a2012-11-09 15:31:50 -0800192 subsystem_put(priv->pil_h);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700193 priv->pil_h = NULL;
194 }
195
196 if (priv->boot_adsp_obj) {
197 sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
198 kobject_del(priv->boot_adsp_obj);
199 priv->boot_adsp_obj = NULL;
200 }
201
202 return 0;
203}
204
205static int adsp_loader_probe(struct platform_device *pdev)
206{
207 int ret = adsp_loader_init_sysfs(pdev);
208 if (ret != 0) {
Krishnankutty Kolathappilly5b8eb9e2013-09-19 14:09:17 -0700209 dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__);
Krishnankutty Kolathappilly2ce63522013-08-26 13:54:22 -0700210 return ret;
211 }
Joonwoo Park4a14a552012-08-02 11:03:21 -0700212
213 return 0;
214}
215
216static const struct of_device_id adsp_loader_dt_match[] = {
217 { .compatible = "qcom,adsp-loader" },
218 { }
219};
220MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
221
222static struct platform_driver adsp_loader_driver = {
223 .driver = {
224 .name = "adsp-loader",
225 .owner = THIS_MODULE,
226 .of_match_table = adsp_loader_dt_match,
227 },
228 .probe = adsp_loader_probe,
229 .remove = __devexit_p(adsp_loader_remove),
230};
231
232static int __init adsp_loader_init(void)
233{
234 return platform_driver_register(&adsp_loader_driver);
235}
236module_init(adsp_loader_init);
237
238static void __exit adsp_loader_exit(void)
239{
240 platform_driver_unregister(&adsp_loader_driver);
241}
242module_exit(adsp_loader_exit);
243
244MODULE_DESCRIPTION("ADSP Loader module");
245MODULE_LICENSE("GPL v2");