blob: 78a132a525f1784ed7a1712c8d5e783df039237c [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2009-2011, 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 MPP driver
15 *
16 */
17
18#include <linux/platform_device.h>
19#include <linux/gpio.h>
20#include <linux/mfd/pmic8058.h>
21#include <mach/mpp.h>
22#include <linux/seq_file.h>
23
24#ifndef CONFIG_GPIOLIB
25#include "gpio_chip.h"
26#endif
27
28/* MPP Control Registers */
29#define SSBI_MPP_CNTRL_BASE 0x50
30#define SSBI_MPP_CNTRL(n) (SSBI_MPP_CNTRL_BASE + (n))
31
32/* MPP Type */
33#define PM8058_MPP_TYPE_MASK 0xE0
34#define PM8058_MPP_TYPE_SHIFT 5
35
36/* MPP Config Level */
37#define PM8058_MPP_CONFIG_LVL_MASK 0x1C
38#define PM8058_MPP_CONFIG_LVL_SHIFT 2
39
40/* MPP Config Control */
41#define PM8058_MPP_CONFIG_CTL_MASK 0x03
42
43static int pm8058_mpp_get(struct gpio_chip *chip, unsigned mpp)
44{
45 struct pm8058_gpio_platform_data *pdata;
46 struct pm8058_chip *pm_chip;
47
48 if (mpp >= PM8058_MPPS || chip == NULL)
49 return -EINVAL;
50
51 pdata = chip->dev->platform_data;
52 pm_chip = dev_get_drvdata(chip->dev->parent);
53
54 return pm8058_irq_get_rt_status(pm_chip,
55 pdata->irq_base + mpp);
56}
57
58#ifndef CONFIG_GPIOLIB
59static int pm8058_mpp_get_irq_num(struct gpio_chip *chip,
60 unsigned int gpio,
61 unsigned int *irqp,
62 unsigned long *irqnumflagsp)
63{
64 struct pm8058_gpio_platform_data *pdata;
65
66 pdata = chip->dev->platform_data;
67 gpio -= chip->start;
68 *irqp = pdata->irq_base + gpio;
69 if (irqnumflagsp)
70 *irqnumflagsp = 0;
71 return 0;
72}
73
74static int pm8058_mpp_read(struct gpio_chip *chip, unsigned n)
75{
76 n -= chip->start;
77 return pm8058_mpp_get(chip, n);
78}
79
80struct msm_gpio_chip pm8058_mpp_chip = {
81 .chip = {
82 .get_irq_num = pm8058_mpp_get_irq_num,
83 .read = pm8058_mpp_read,
84 }
85};
86
87int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
88 unsigned control)
89{
90 u8 config;
91 int rc;
92 struct pm8058_chip *pm_chip;
93
94 if (mpp >= PM8058_MPPS)
95 return -EINVAL;
96
97 pm_chip = dev_get_drvdata(pm8058_mpp_chip->dev->parent);
98
99 config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
100 config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
101 PM8058_MPP_CONFIG_LVL_MASK;
102 config |= control & PM8058_MPP_CONFIG_CTL_MASK;
103
104 rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
105 if (rc)
106 pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
107
108 return rc;
109}
110EXPORT_SYMBOL(pm8058_mpp_config);
111
112static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
113{
114 int rc;
115 struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
116
117 pm8058_mpp_chip.chip.dev = &pdev->dev;
118 pm8058_mpp_chip.chip.start = pdata->gpio_base;
119 pm8058_mpp_chip.chip.end = pdata->gpio_base + PM8058_MPPS - 1;
120 rc = register_gpio_chip(&pm8058_mpp_chip.chip);
121 if (!rc) {
122 if (pdata->init)
123 ret = pdata->init();
124 }
125 pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
126
127 return rc;
128}
129
130static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
131{
132 return 0;
133}
134
135#else
136
137static int pm8058_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
138{
139 struct pm8058_gpio_platform_data *pdata;
140 pdata = chip->dev->platform_data;
141 return pdata->irq_base + offset;
142}
143
144static int pm8058_mpp_read(struct gpio_chip *chip, unsigned offset)
145{
146 return pm8058_mpp_get(chip, offset);
147}
148
149static void pm8058_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
150{
151 static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
152 "a_out", "sink", "dtest_sink", "dtest_out" };
153 struct pm8058_chip *pm_chip = dev_get_drvdata(chip->dev->parent);
154 u8 type, state, ctrl;
155 const char *label;
156 int i;
157
158 for (i = 0; i < PM8058_MPPS; i++) {
159 pm8058_read(pm_chip, SSBI_MPP_CNTRL(i), &ctrl, 1);
160 label = gpiochip_is_requested(chip, i);
161 type = (ctrl & PM8058_MPP_TYPE_MASK) >>
162 PM8058_MPP_TYPE_SHIFT;
163 state = pm8058_mpp_get(chip, i);
164 seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
165 " %s 0x%02x\n",
166 chip->base + i,
167 label ? label : "--",
168 ctype[type],
169 state ? "hi" : "lo",
170 ctrl);
171 }
172}
173
174static struct gpio_chip pm8058_mpp_chip = {
175 .label = "pm8058-mpp",
176 .to_irq = pm8058_mpp_to_irq,
177 .get = pm8058_mpp_read,
178 .dbg_show = pm8058_mpp_dbg_show,
179 .ngpio = PM8058_MPPS,
180 .can_sleep = 1,
181};
182
183int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
184 unsigned control)
185{
186 u8 config;
187 int rc;
188 struct pm8058_chip *pm_chip;
189
190 if (mpp >= PM8058_MPPS)
191 return -EINVAL;
192
193 pm_chip = dev_get_drvdata(pm8058_mpp_chip.dev->parent);
194
195 config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
196 config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
197 PM8058_MPP_CONFIG_LVL_MASK;
198 config |= control & PM8058_MPP_CONFIG_CTL_MASK;
199
200 rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
201 if (rc)
202 pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
203
204 return rc;
205}
206EXPORT_SYMBOL(pm8058_mpp_config);
207
208static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
209{
210 int ret;
211 struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
212
213 pm8058_mpp_chip.dev = &pdev->dev;
214 pm8058_mpp_chip.base = pdata->gpio_base;
215 ret = gpiochip_add(&pm8058_mpp_chip);
216 if (!ret) {
217 if (pdata->init)
218 ret = pdata->init();
219 }
220
221 pr_info("%s: gpiochip_add(): ret=%d\n", __func__, ret);
222 return ret;
223}
224
225static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
226{
227 return gpiochip_remove(&pm8058_mpp_chip);
228}
229
230#endif
231
232static struct platform_driver pm8058_mpp_driver = {
233 .probe = pm8058_mpp_probe,
234 .remove = __devexit_p(pm8058_mpp_remove),
235 .driver = {
236 .name = "pm8058-mpp",
237 .owner = THIS_MODULE,
238 },
239};
240
241static int __init pm8058_mpp_init(void)
242{
243 return platform_driver_register(&pm8058_mpp_driver);
244}
245
246static void __exit pm8058_mpp_exit(void)
247{
248 platform_driver_unregister(&pm8058_mpp_driver);
249}
250
251subsys_initcall(pm8058_mpp_init);
252module_exit(pm8058_mpp_exit);
253
254MODULE_LICENSE("GPL v2");
255MODULE_DESCRIPTION("PMIC8058 MPP driver");
256MODULE_VERSION("1.0");
257MODULE_ALIAS("platform:pm8058-mpp");
258