blob: 76a19f494f25ea5c35ebb8d7944a10874c56d6ad [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * Qualcomm PMIC8058 NFC driver
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/err.h>
21#include <linux/mfd/pmic8058.h>
22#include <linux/pmic8058-nfc.h>
23#include <linux/debugfs.h>
24#include <linux/slab.h>
25
26/* PMIC8058 NFC */
27#define SSBI_REG_NFC_CTRL 0x14D
28#define SSBI_REG_NFC_TEST 0x14E
29
30/* NFC_CTRL */
31#define PM8058_NFC_SUPPORT_EN 0x80
32#define PM8058_NFC_LDO_EN 0x40
33#define PM8058_NFC_EN 0x20
34#define PM8058_NFC_EXT_VDDLDO_EN 0x10
35#define PM8058_NFC_VPH_PWR_EN 0x08
36#define PM8058_NFC_RESERVED 0x04
37#define PM8058_NFC_VDDLDO_LEVEL 0x03
38
39/* NFC_TEST */
40#define PM8058_NFC_VDDLDO_MON_EN 0x80
41#define PM8058_NFC_ATEST_EN 0x40
42#define PM8058_NFC_DTEST1_EN 0x20
43#define PM8058_NFC_RESERVED2 0x18
44#define PM8058_NFC_VDDLDO_OK_S 0x04
45#define PM8058_NFC_MBG_EN_S 0x02
46#define PM8058_NFC_EXT_EN_S 0x01
47
48struct pm8058_nfc_device {
49 struct mutex nfc_mutex;
50 struct pm8058_chip *pm_chip;
51#if defined(CONFIG_DEBUG_FS)
52 struct dentry *dent;
53#endif
54};
55static struct pm8058_nfc_device *nfc_dev;
56
57/* APIs */
58/*
59 * pm8058_nfc_request - request a handle to access NFC device
60 */
61struct pm8058_nfc_device *pm8058_nfc_request(void)
62{
63 return nfc_dev;
64}
65EXPORT_SYMBOL(pm8058_nfc_request);
66
67/*
68 * pm8058_nfc_config - configure NFC signals
69 *
70 * @nfcdev: the NFC device
71 * @mask: signal mask to configure
72 * @flags: control flags
73 */
74int pm8058_nfc_config(struct pm8058_nfc_device *nfcdev, u32 mask, u32 flags)
75{
76 u8 nfc_ctrl, nfc_test, m, f;
77 int rc;
78
79 if (nfcdev == NULL || IS_ERR(nfcdev) || !mask)
80 return -EINVAL;
81 if (nfcdev->pm_chip == NULL)
82 return -ENODEV;
83
84 mutex_lock(&nfcdev->nfc_mutex);
85
86 if (!(mask & PM_NFC_CTRL_REQ))
87 goto config_test;
88
89 rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
90 if (rc) {
91 pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_ctrl=0x%x)\n",
92 __func__, rc, nfc_ctrl);
93 goto config_done;
94 }
95
96 m = mask & 0x00ff;
97 f = flags & 0x00ff;
98 nfc_ctrl &= ~m;
99 nfc_ctrl |= m & f;
100
101 rc = pm8058_write(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
102 if (rc) {
103 pr_err("%s: FAIL pm8058_write(): rc=%d (nfc_ctrl=0x%x)\n",
104 __func__, rc, nfc_ctrl);
105 goto config_done;
106 }
107
108config_test:
109 if (!(mask & PM_NFC_TEST_REQ))
110 goto config_done;
111
112 rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
113 if (rc) {
114 pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_test=0x%x)\n",
115 __func__, rc, nfc_test);
116 goto config_done;
117 }
118
119 m = (mask >> 8) & 0x00ff;
120 f = (flags >> 8) & 0x00ff;
121 nfc_test &= ~m;
122 nfc_test |= m & f;
123
124 rc = pm8058_write(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
125 if (rc) {
126 pr_err("%s: FAIL pm8058_write(): rc=%d (nfc_test=0x%x)\n",
127 __func__, rc, nfc_test);
128 goto config_done;
129 }
130
131config_done:
132 mutex_unlock(&nfcdev->nfc_mutex);
133 return 0;
134}
135EXPORT_SYMBOL(pm8058_nfc_config);
136
137/*
138 * pm8058_nfc_get_status - get NFC status
139 *
140 * @nfcdev: the NFC device
141 * @mask: of status mask to read
142 * @status: pointer to the status variable
143 */
144int pm8058_nfc_get_status(struct pm8058_nfc_device *nfcdev,
145 u32 mask, u32 *status)
146{
147 u8 nfc_ctrl, nfc_test;
148 u32 st;
149 int rc;
150
151 if (nfcdev == NULL || IS_ERR(nfcdev) || status == NULL)
152 return -EINVAL;
153 if (nfcdev->pm_chip == NULL)
154 return -ENODEV;
155
156 st = 0;
157 mutex_lock(&nfcdev->nfc_mutex);
158
159 if (!(mask & PM_NFC_CTRL_REQ))
160 goto read_test;
161
162 rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_CTRL, &nfc_ctrl, 1);
163 if (rc) {
164 pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_ctrl=0x%x)\n",
165 __func__, rc, nfc_ctrl);
166 goto get_status_done;
167 }
168
169read_test:
170 if (!(mask & (PM_NFC_TEST_REQ | PM_NFC_TEST_STATUS)))
171 goto get_status_done;
172
173 rc = pm8058_read(nfcdev->pm_chip, SSBI_REG_NFC_TEST, &nfc_test, 1);
174 if (rc)
175 pr_err("%s: FAIL pm8058_read(): rc=%d (nfc_test=0x%x)\n",
176 __func__, rc, nfc_test);
177
178get_status_done:
179 st = nfc_ctrl;
180 st |= nfc_test << 8;
181 *status = st;
182
183 mutex_unlock(&nfcdev->nfc_mutex);
184 return 0;
185}
186EXPORT_SYMBOL(pm8058_nfc_get_status);
187
188/*
189 * pm8058_nfc_free - free the NFC device
190 */
191void pm8058_nfc_free(struct pm8058_nfc_device *nfcdev)
192{
193 /* Disable all signals */
194 pm8058_nfc_config(nfcdev, PM_NFC_CTRL_REQ, 0);
195}
196EXPORT_SYMBOL(pm8058_nfc_free);
197
198#if defined(CONFIG_DEBUG_FS)
199static int pm8058_nfc_debug_set(void *data, u64 val)
200{
201 struct pm8058_nfc_device *nfcdev;
202 u32 mask, control;
203 int rc;
204
205 nfcdev = (struct pm8058_nfc_device *)data;
206 control = (u32)val & 0xffff;
207 mask = ((u32)val >> 16) & 0xffff;
208 rc = pm8058_nfc_config(nfcdev, mask, control);
209 if (rc)
210 pr_err("%s: ERR pm8058_nfc_config: rc=%d, "
211 "[mask, control]=[0x%x, 0x%x]\n",
212 __func__, rc, mask, control);
213
214 return 0;
215}
216
217static int pm8058_nfc_debug_get(void *data, u64 *val)
218{
219 struct pm8058_nfc_device *nfcdev;
220 u32 status;
221 int rc;
222
223 nfcdev = (struct pm8058_nfc_device *)data;
224 rc = pm8058_nfc_get_status(nfcdev, (u32)-1, &status);
225 if (rc)
226 pr_err("%s: ERR pm8058_nfc_get_status: rc=%d, status=0x%x\n",
227 __func__, rc, status);
228
229 if (val)
230 *val = (u64)status;
231 return 0;
232}
233
234DEFINE_SIMPLE_ATTRIBUTE(pm8058_nfc_fops, pm8058_nfc_debug_get,
235 pm8058_nfc_debug_set, "%llu\n");
236
237static int pm8058_nfc_debug_init(struct pm8058_nfc_device *nfcdev)
238{
239 struct dentry *dent;
240
241 dent = debugfs_create_file("pm8058-nfc", 0644, NULL,
242 (void *)nfcdev, &pm8058_nfc_fops);
243
244 if (dent == NULL || IS_ERR(dent))
245 pr_err("%s: ERR debugfs_create_file: dent=0x%x\n",
246 __func__, (unsigned)dent);
247
248 nfcdev->dent = dent;
249 return 0;
250}
251#endif
252
253static int __devinit pmic8058_nfc_probe(struct platform_device *pdev)
254{
255 struct pm8058_chip *pm_chip;
256 struct pm8058_nfc_device *nfcdev;
257
258 pm_chip = dev_get_drvdata(pdev->dev.parent);
259 if (pm_chip == NULL) {
260 pr_err("%s: no parent data passed in.\n", __func__);
261 return -EFAULT;
262 }
263
264 nfcdev = kzalloc(sizeof *nfcdev, GFP_KERNEL);
265 if (nfcdev == NULL) {
266 pr_err("%s: kzalloc() failed.\n", __func__);
267 return -ENOMEM;
268 }
269
270 mutex_init(&nfcdev->nfc_mutex);
271
272 nfcdev->pm_chip = pm_chip;
273 nfc_dev = nfcdev;
274 platform_set_drvdata(pdev, nfcdev);
275
276#if defined(CONFIG_DEBUG_FS)
277 pm8058_nfc_debug_init(nfc_dev);
278#endif
279
280 pr_notice("%s: OK\n", __func__);
281 return 0;
282}
283
284static int __devexit pmic8058_nfc_remove(struct platform_device *pdev)
285{
286 struct pm8058_nfc_device *nfcdev = platform_get_drvdata(pdev);
287
288#if defined(CONFIG_DEBUG_FS)
289 debugfs_remove(nfcdev->dent);
290#endif
291
292 platform_set_drvdata(pdev, nfcdev->pm_chip);
293 kfree(nfcdev);
294 return 0;
295}
296
297static struct platform_driver pmic8058_nfc_driver = {
298 .probe = pmic8058_nfc_probe,
299 .remove = __devexit_p(pmic8058_nfc_remove),
300 .driver = {
301 .name = "pm8058-nfc",
302 .owner = THIS_MODULE,
303 },
304};
305
306static int __init pm8058_nfc_init(void)
307{
308 return platform_driver_register(&pmic8058_nfc_driver);
309}
310
311static void __exit pm8058_nfc_exit(void)
312{
313 platform_driver_unregister(&pmic8058_nfc_driver);
314}
315
316module_init(pm8058_nfc_init);
317module_exit(pm8058_nfc_exit);
318
319MODULE_LICENSE("GPL v2");
320MODULE_DESCRIPTION("PMIC8058 NFC driver");
321MODULE_VERSION("1.0");
322MODULE_ALIAS("platform:pmic8058-nfc");