blob: eeb3e2c9dae95467ee87052b5ee54745492c8551 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010,2011 The Linux Foundation. All rights reserved.
Anirudh Ghayalc2019332011-11-12 06:29:10 +05302 *
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 PMIC8XXX NFC driver
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/err.h>
21#include <linux/debugfs.h>
22#include <linux/slab.h>
23#include <linux/mfd/pm8xxx/core.h>
24#include <linux/mfd/pm8xxx/nfc.h>
25
26/* PM8XXX NFC */
27#define SSBI_REG_NFC_CTRL 0x14D
28#define SSBI_REG_NFC_TEST 0x14E
29
30/* NFC_CTRL */
31#define PM8XXX_NFC_SUPPORT_EN 0x80
32#define PM8XXX_NFC_LDO_EN 0x40
33#define PM8XXX_NFC_EN 0x20
34#define PM8XXX_NFC_EXT_VDDLDO_EN 0x10
35#define PM8XXX_NFC_VPH_PWR_EN 0x08
36#define PM8XXX_NFC_RESERVED 0x04
37#define PM8XXX_NFC_VDDLDO_LEVEL 0x03
38
39/* NFC_TEST */
40#define PM8XXX_NFC_VDDLDO_MON_EN 0x80
41#define PM8XXX_NFC_ATEST_EN 0x40
42#define PM8XXX_NFC_DTEST1_EN 0x20
43#define PM8XXX_NFC_RESERVED2 0x18
44#define PM8XXX_NFC_VDDLDO_OK_S 0x04
45#define PM8XXX_NFC_MBG_EN_S 0x02
46#define PM8XXX_NFC_EXT_EN_S 0x01
47
48struct pm8xxx_nfc_device {
49 struct device *dev;
50 struct mutex nfc_mutex;
51#if defined(CONFIG_DEBUG_FS)
52 struct dentry *dent;
53#endif
54};
55static struct pm8xxx_nfc_device *nfc_dev;
56
57/* APIs */
58/*
59 * pm8xxx_nfc_request - request a handle to access NFC device
60 */
61struct pm8xxx_nfc_device *pm8xxx_nfc_request(void)
62{
63 return nfc_dev;
64}
65EXPORT_SYMBOL(pm8xxx_nfc_request);
66
67/*
68 * pm8xxx_nfc_config - configure NFC signals
69 *
70 * @nfcdev: the NFC device
71 * @mask: signal mask to configure
72 * @flags: control flags
73 */
74int pm8xxx_nfc_config(struct pm8xxx_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
82 mutex_lock(&nfcdev->nfc_mutex);
83
84 if (!(mask & PM_NFC_CTRL_REQ))
85 goto config_test;
86
87 rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, &nfc_ctrl);
88 if (rc) {
89 pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_ctrl=0x%x)\n",
90 __func__, rc, nfc_ctrl);
91 goto config_done;
92 }
93
94 m = mask & 0x00ff;
95 f = flags & 0x00ff;
96 nfc_ctrl &= ~m;
97 nfc_ctrl |= m & f;
98
99 rc = pm8xxx_writeb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, nfc_ctrl);
100 if (rc) {
101 pr_err("%s: FAIL pm8xxx_writeb(): rc=%d (nfc_ctrl=0x%x)\n",
102 __func__, rc, nfc_ctrl);
103 goto config_done;
104 }
105
106config_test:
107 if (!(mask & PM_NFC_TEST_REQ))
108 goto config_done;
109
110 rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, &nfc_test);
111 if (rc) {
112 pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_test=0x%x)\n",
113 __func__, rc, nfc_test);
114 goto config_done;
115 }
116
117 m = (mask >> 8) & 0x00ff;
118 f = (flags >> 8) & 0x00ff;
119 nfc_test &= ~m;
120 nfc_test |= m & f;
121
122 rc = pm8xxx_writeb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, nfc_test);
123 if (rc) {
124 pr_err("%s: FAIL pm8xxx_writeb(): rc=%d (nfc_test=0x%x)\n",
125 __func__, rc, nfc_test);
126 goto config_done;
127 }
128
129config_done:
130 mutex_unlock(&nfcdev->nfc_mutex);
131 return 0;
132}
133EXPORT_SYMBOL(pm8xxx_nfc_config);
134
135/*
136 * pm8xxx_nfc_get_status - get NFC status
137 *
138 * @nfcdev: the NFC device
139 * @mask: of status mask to read
140 * @status: pointer to the status variable
141 */
142int pm8xxx_nfc_get_status(struct pm8xxx_nfc_device *nfcdev,
143 u32 mask, u32 *status)
144{
145 u8 nfc_ctrl, nfc_test;
146 u32 st;
147 int rc;
148
149 if (nfcdev == NULL || IS_ERR(nfcdev) || status == NULL)
150 return -EINVAL;
151
152 st = 0;
153 mutex_lock(&nfcdev->nfc_mutex);
154
155 if (!(mask & PM_NFC_CTRL_REQ))
156 goto read_test;
157
158 rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_CTRL, &nfc_ctrl);
159 if (rc) {
160 pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_ctrl=0x%x)\n",
161 __func__, rc, nfc_ctrl);
162 goto get_status_done;
163 }
164
165read_test:
166 if (!(mask & (PM_NFC_TEST_REQ | PM_NFC_TEST_STATUS)))
167 goto get_status_done;
168
169 rc = pm8xxx_readb(nfcdev->dev->parent, SSBI_REG_NFC_TEST, &nfc_test);
170 if (rc)
171 pr_err("%s: FAIL pm8xxx_readb(): rc=%d (nfc_test=0x%x)\n",
172 __func__, rc, nfc_test);
173
174get_status_done:
175 st = nfc_ctrl;
176 st |= nfc_test << 8;
177 *status = st;
178
179 mutex_unlock(&nfcdev->nfc_mutex);
180 return 0;
181}
182EXPORT_SYMBOL(pm8xxx_nfc_get_status);
183
184/*
185 * pm8xxx_nfc_free - free the NFC device
186 */
187void pm8xxx_nfc_free(struct pm8xxx_nfc_device *nfcdev)
188{
189 /* Disable all signals */
190 pm8xxx_nfc_config(nfcdev, PM_NFC_CTRL_REQ, 0);
191}
192EXPORT_SYMBOL(pm8xxx_nfc_free);
193
194#if defined(CONFIG_DEBUG_FS)
195static int pm8xxx_nfc_debug_set(void *data, u64 val)
196{
197 struct pm8xxx_nfc_device *nfcdev;
198 u32 mask, control;
199 int rc;
200
201 nfcdev = (struct pm8xxx_nfc_device *)data;
202 control = (u32)val & 0xffff;
203 mask = ((u32)val >> 16) & 0xffff;
204 rc = pm8xxx_nfc_config(nfcdev, mask, control);
205 if (rc)
206 pr_err("%s: ERR pm8xxx_nfc_config: rc=%d, "
207 "[mask, control]=[0x%x, 0x%x]\n",
208 __func__, rc, mask, control);
209
210 return 0;
211}
212
213static int pm8xxx_nfc_debug_get(void *data, u64 *val)
214{
215 struct pm8xxx_nfc_device *nfcdev;
216 u32 status;
217 int rc;
218
219 nfcdev = (struct pm8xxx_nfc_device *)data;
220 rc = pm8xxx_nfc_get_status(nfcdev, (u32)-1, &status);
221 if (rc)
222 pr_err("%s: ERR pm8xxx_nfc_get_status: rc=%d, status=0x%x\n",
223 __func__, rc, status);
224
225 if (val)
226 *val = (u64)status;
227 return 0;
228}
229
230DEFINE_SIMPLE_ATTRIBUTE(pm8xxx_nfc_fops, pm8xxx_nfc_debug_get,
231 pm8xxx_nfc_debug_set, "%llu\n");
232
233static int pm8xxx_nfc_debug_init(struct pm8xxx_nfc_device *nfcdev)
234{
235 struct dentry *dent;
236
237 dent = debugfs_create_file("pm8xxx-nfc", 0644, NULL,
238 (void *)nfcdev, &pm8xxx_nfc_fops);
239
240 if (dent == NULL || IS_ERR(dent))
241 pr_err("%s: ERR debugfs_create_file: dent=0x%x\n",
242 __func__, (unsigned)dent);
243
244 nfcdev->dent = dent;
245 return 0;
246}
247#endif
248
249static int __devinit pm8xxx_nfc_probe(struct platform_device *pdev)
250{
251 struct pm8xxx_nfc_device *nfcdev;
252
253 nfcdev = kzalloc(sizeof *nfcdev, GFP_KERNEL);
254 if (nfcdev == NULL) {
255 pr_err("%s: kzalloc() failed.\n", __func__);
256 return -ENOMEM;
257 }
258
259 mutex_init(&nfcdev->nfc_mutex);
260
261 nfcdev->dev = &pdev->dev;
262 nfc_dev = nfcdev;
263 platform_set_drvdata(pdev, nfcdev);
264
265#if defined(CONFIG_DEBUG_FS)
266 pm8xxx_nfc_debug_init(nfc_dev);
267#endif
268
269 pr_notice("%s: OK\n", __func__);
270 return 0;
271}
272
273static int __devexit pm8xxx_nfc_remove(struct platform_device *pdev)
274{
275 struct pm8xxx_nfc_device *nfcdev = platform_get_drvdata(pdev);
276
277#if defined(CONFIG_DEBUG_FS)
278 debugfs_remove(nfcdev->dent);
279#endif
280
281 platform_set_drvdata(pdev, NULL);
282 kfree(nfcdev);
283 return 0;
284}
285
286static struct platform_driver pm8xxx_nfc_driver = {
287 .probe = pm8xxx_nfc_probe,
288 .remove = __devexit_p(pm8xxx_nfc_remove),
289 .driver = {
290 .name = PM8XXX_NFC_DEV_NAME,
291 .owner = THIS_MODULE,
292 },
293};
294
295static int __init pm8xxx_nfc_init(void)
296{
297 return platform_driver_register(&pm8xxx_nfc_driver);
298}
299
300static void __exit pm8xxx_nfc_exit(void)
301{
302 platform_driver_unregister(&pm8xxx_nfc_driver);
303}
304
305module_init(pm8xxx_nfc_init);
306module_exit(pm8xxx_nfc_exit);
307
308MODULE_LICENSE("GPL v2");
309MODULE_DESCRIPTION("PM8XXX NFC driver");
310MODULE_VERSION("1.0");
311MODULE_ALIAS("platform:" PM8XXX_NFC_DEV_NAME);