0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/kernel.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/sched.h>
0014 #include <linux/list.h>
0015 #include <linux/slab.h>
0016 #include <linux/err.h>
0017 #include <linux/clk.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/io.h>
0020 #include <linux/regulator/consumer.h>
0021
0022 #include "regs-adc.h"
0023 #include <linux/soc/samsung/s3c-adc.h>
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 enum s3c_cpu_type {
0039 TYPE_ADCV1,
0040 TYPE_ADCV11,
0041 TYPE_ADCV12,
0042 TYPE_ADCV2,
0043 TYPE_ADCV3,
0044 };
0045
0046 struct s3c_adc_client {
0047 struct platform_device *pdev;
0048 struct list_head pend;
0049 wait_queue_head_t *wait;
0050
0051 unsigned int nr_samples;
0052 int result;
0053 unsigned char is_ts;
0054 unsigned char channel;
0055
0056 void (*select_cb)(struct s3c_adc_client *c, unsigned selected);
0057 void (*convert_cb)(struct s3c_adc_client *c,
0058 unsigned val1, unsigned val2,
0059 unsigned *samples_left);
0060 };
0061
0062 struct adc_device {
0063 struct platform_device *pdev;
0064 struct platform_device *owner;
0065 struct clk *clk;
0066 struct s3c_adc_client *cur;
0067 struct s3c_adc_client *ts_pend;
0068 void __iomem *regs;
0069 spinlock_t lock;
0070
0071 unsigned int prescale;
0072
0073 int irq;
0074 struct regulator *vdd;
0075 };
0076
0077 static struct adc_device *adc_dev;
0078
0079 static LIST_HEAD(adc_pending);
0080
0081 #define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
0082
0083 static inline void s3c_adc_convert(struct adc_device *adc)
0084 {
0085 unsigned con = readl(adc->regs + S3C2410_ADCCON);
0086
0087 con |= S3C2410_ADCCON_ENABLE_START;
0088 writel(con, adc->regs + S3C2410_ADCCON);
0089 }
0090
0091 static inline void s3c_adc_select(struct adc_device *adc,
0092 struct s3c_adc_client *client)
0093 {
0094 unsigned con = readl(adc->regs + S3C2410_ADCCON);
0095 enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
0096
0097 client->select_cb(client, 1);
0098
0099 if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2)
0100 con &= ~S3C2410_ADCCON_MUXMASK;
0101 con &= ~S3C2410_ADCCON_STDBM;
0102 con &= ~S3C2410_ADCCON_STARTMASK;
0103
0104 if (!client->is_ts) {
0105 if (cpu == TYPE_ADCV3)
0106 writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
0107 else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
0108 writel(client->channel & 0xf,
0109 adc->regs + S3C2443_ADCMUX);
0110 else
0111 con |= S3C2410_ADCCON_SELMUX(client->channel);
0112 }
0113
0114 writel(con, adc->regs + S3C2410_ADCCON);
0115 }
0116
0117 static void s3c_adc_dbgshow(struct adc_device *adc)
0118 {
0119 adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
0120 readl(adc->regs + S3C2410_ADCCON),
0121 readl(adc->regs + S3C2410_ADCTSC),
0122 readl(adc->regs + S3C2410_ADCDLY));
0123 }
0124
0125 static void s3c_adc_try(struct adc_device *adc)
0126 {
0127 struct s3c_adc_client *next = adc->ts_pend;
0128
0129 if (!next && !list_empty(&adc_pending)) {
0130 next = list_first_entry(&adc_pending,
0131 struct s3c_adc_client, pend);
0132 list_del(&next->pend);
0133 } else
0134 adc->ts_pend = NULL;
0135
0136 if (next) {
0137 adc_dbg(adc, "new client is %p\n", next);
0138 adc->cur = next;
0139 s3c_adc_select(adc, next);
0140 s3c_adc_convert(adc);
0141 s3c_adc_dbgshow(adc);
0142 }
0143 }
0144
0145 int s3c_adc_start(struct s3c_adc_client *client,
0146 unsigned int channel, unsigned int nr_samples)
0147 {
0148 struct adc_device *adc = adc_dev;
0149 unsigned long flags;
0150
0151 if (!adc) {
0152 printk(KERN_ERR "%s: failed to find adc\n", __func__);
0153 return -EINVAL;
0154 }
0155
0156 spin_lock_irqsave(&adc->lock, flags);
0157
0158 if (client->is_ts && adc->ts_pend) {
0159 spin_unlock_irqrestore(&adc->lock, flags);
0160 return -EAGAIN;
0161 }
0162
0163 client->channel = channel;
0164 client->nr_samples = nr_samples;
0165
0166 if (client->is_ts)
0167 adc->ts_pend = client;
0168 else
0169 list_add_tail(&client->pend, &adc_pending);
0170
0171 if (!adc->cur)
0172 s3c_adc_try(adc);
0173
0174 spin_unlock_irqrestore(&adc->lock, flags);
0175
0176 return 0;
0177 }
0178 EXPORT_SYMBOL_GPL(s3c_adc_start);
0179
0180 static void s3c_convert_done(struct s3c_adc_client *client,
0181 unsigned v, unsigned u, unsigned *left)
0182 {
0183 client->result = v;
0184 wake_up(client->wait);
0185 }
0186
0187 int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
0188 {
0189 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
0190 int ret;
0191
0192 client->convert_cb = s3c_convert_done;
0193 client->wait = &wake;
0194 client->result = -1;
0195
0196 ret = s3c_adc_start(client, ch, 1);
0197 if (ret < 0)
0198 goto err;
0199
0200 ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
0201 if (client->result < 0) {
0202 ret = -ETIMEDOUT;
0203 goto err;
0204 }
0205
0206 client->convert_cb = NULL;
0207 return client->result;
0208
0209 err:
0210 return ret;
0211 }
0212 EXPORT_SYMBOL_GPL(s3c_adc_read);
0213
0214 static void s3c_adc_default_select(struct s3c_adc_client *client,
0215 unsigned select)
0216 {
0217 }
0218
0219 struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
0220 void (*select)(struct s3c_adc_client *client,
0221 unsigned int selected),
0222 void (*conv)(struct s3c_adc_client *client,
0223 unsigned d0, unsigned d1,
0224 unsigned *samples_left),
0225 unsigned int is_ts)
0226 {
0227 struct s3c_adc_client *client;
0228
0229 WARN_ON(!pdev);
0230
0231 if (!select)
0232 select = s3c_adc_default_select;
0233
0234 if (!pdev)
0235 return ERR_PTR(-EINVAL);
0236
0237 client = kzalloc(sizeof(*client), GFP_KERNEL);
0238 if (!client)
0239 return ERR_PTR(-ENOMEM);
0240
0241 client->pdev = pdev;
0242 client->is_ts = is_ts;
0243 client->select_cb = select;
0244 client->convert_cb = conv;
0245
0246 return client;
0247 }
0248 EXPORT_SYMBOL_GPL(s3c_adc_register);
0249
0250 void s3c_adc_release(struct s3c_adc_client *client)
0251 {
0252 unsigned long flags;
0253
0254 spin_lock_irqsave(&adc_dev->lock, flags);
0255
0256
0257 if (adc_dev->cur == client)
0258 adc_dev->cur = NULL;
0259 if (adc_dev->ts_pend == client)
0260 adc_dev->ts_pend = NULL;
0261 else {
0262 struct list_head *p, *n;
0263 struct s3c_adc_client *tmp;
0264
0265 list_for_each_safe(p, n, &adc_pending) {
0266 tmp = list_entry(p, struct s3c_adc_client, pend);
0267 if (tmp == client)
0268 list_del(&tmp->pend);
0269 }
0270 }
0271
0272 if (adc_dev->cur == NULL)
0273 s3c_adc_try(adc_dev);
0274
0275 spin_unlock_irqrestore(&adc_dev->lock, flags);
0276 kfree(client);
0277 }
0278 EXPORT_SYMBOL_GPL(s3c_adc_release);
0279
0280 static irqreturn_t s3c_adc_irq(int irq, void *pw)
0281 {
0282 struct adc_device *adc = pw;
0283 struct s3c_adc_client *client = adc->cur;
0284 enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
0285 unsigned data0, data1;
0286
0287 if (!client) {
0288 dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
0289 goto exit;
0290 }
0291
0292 data0 = readl(adc->regs + S3C2410_ADCDAT0);
0293 data1 = readl(adc->regs + S3C2410_ADCDAT1);
0294 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
0295
0296 client->nr_samples--;
0297
0298 if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) {
0299 data0 &= 0x3ff;
0300 data1 &= 0x3ff;
0301 } else {
0302
0303 data0 &= 0xfff;
0304 data1 &= 0xfff;
0305 }
0306
0307 if (client->convert_cb)
0308 (client->convert_cb)(client, data0, data1, &client->nr_samples);
0309
0310 if (client->nr_samples > 0) {
0311
0312
0313 client->select_cb(client, 1);
0314 s3c_adc_convert(adc);
0315 } else {
0316 spin_lock(&adc->lock);
0317 (client->select_cb)(client, 0);
0318 adc->cur = NULL;
0319
0320 s3c_adc_try(adc);
0321 spin_unlock(&adc->lock);
0322 }
0323
0324 exit:
0325 if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) {
0326
0327 writel(0, adc->regs + S3C64XX_ADCCLRINT);
0328 }
0329 return IRQ_HANDLED;
0330 }
0331
0332 static int s3c_adc_probe(struct platform_device *pdev)
0333 {
0334 struct device *dev = &pdev->dev;
0335 struct adc_device *adc;
0336 enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
0337 int ret;
0338 unsigned tmp;
0339
0340 adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL);
0341 if (!adc)
0342 return -ENOMEM;
0343
0344 spin_lock_init(&adc->lock);
0345
0346 adc->pdev = pdev;
0347 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
0348
0349 adc->vdd = devm_regulator_get(dev, "vdd");
0350 if (IS_ERR(adc->vdd)) {
0351 dev_err(dev, "operating without regulator \"vdd\" .\n");
0352 return PTR_ERR(adc->vdd);
0353 }
0354
0355 adc->irq = platform_get_irq(pdev, 1);
0356 if (adc->irq <= 0)
0357 return -ENOENT;
0358
0359 ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev),
0360 adc);
0361 if (ret < 0) {
0362 dev_err(dev, "failed to attach adc irq\n");
0363 return ret;
0364 }
0365
0366 adc->clk = devm_clk_get(dev, "adc");
0367 if (IS_ERR(adc->clk)) {
0368 dev_err(dev, "failed to get adc clock\n");
0369 return PTR_ERR(adc->clk);
0370 }
0371
0372 adc->regs = devm_platform_ioremap_resource(pdev, 0);
0373 if (IS_ERR(adc->regs))
0374 return PTR_ERR(adc->regs);
0375
0376 ret = regulator_enable(adc->vdd);
0377 if (ret)
0378 return ret;
0379
0380 clk_prepare_enable(adc->clk);
0381
0382 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
0383
0384
0385 if (cpu == TYPE_ADCV12)
0386 tmp |= S3C2416_ADCCON_RESSEL;
0387 if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
0388 tmp |= S3C64XX_ADCCON_RESSEL;
0389
0390 writel(tmp, adc->regs + S3C2410_ADCCON);
0391
0392 dev_info(dev, "attached adc driver\n");
0393
0394 platform_set_drvdata(pdev, adc);
0395 adc_dev = adc;
0396
0397 return 0;
0398 }
0399
0400 static int s3c_adc_remove(struct platform_device *pdev)
0401 {
0402 struct adc_device *adc = platform_get_drvdata(pdev);
0403
0404 clk_disable_unprepare(adc->clk);
0405 regulator_disable(adc->vdd);
0406
0407 return 0;
0408 }
0409
0410 #ifdef CONFIG_PM
0411 static int s3c_adc_suspend(struct device *dev)
0412 {
0413 struct adc_device *adc = dev_get_drvdata(dev);
0414 unsigned long flags;
0415 u32 con;
0416
0417 spin_lock_irqsave(&adc->lock, flags);
0418
0419 con = readl(adc->regs + S3C2410_ADCCON);
0420 con |= S3C2410_ADCCON_STDBM;
0421 writel(con, adc->regs + S3C2410_ADCCON);
0422
0423 disable_irq(adc->irq);
0424 spin_unlock_irqrestore(&adc->lock, flags);
0425 clk_disable(adc->clk);
0426 regulator_disable(adc->vdd);
0427
0428 return 0;
0429 }
0430
0431 static int s3c_adc_resume(struct device *dev)
0432 {
0433 struct platform_device *pdev = to_platform_device(dev);
0434 struct adc_device *adc = platform_get_drvdata(pdev);
0435 enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
0436 int ret;
0437 unsigned long tmp;
0438
0439 ret = regulator_enable(adc->vdd);
0440 if (ret)
0441 return ret;
0442 clk_enable(adc->clk);
0443 enable_irq(adc->irq);
0444
0445 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
0446
0447
0448 if (cpu == TYPE_ADCV12)
0449 tmp |= S3C2416_ADCCON_RESSEL;
0450 if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
0451 tmp |= S3C64XX_ADCCON_RESSEL;
0452
0453 writel(tmp, adc->regs + S3C2410_ADCCON);
0454
0455 return 0;
0456 }
0457
0458 #else
0459 #define s3c_adc_suspend NULL
0460 #define s3c_adc_resume NULL
0461 #endif
0462
0463 static const struct platform_device_id s3c_adc_driver_ids[] = {
0464 {
0465 .name = "s3c24xx-adc",
0466 .driver_data = TYPE_ADCV1,
0467 }, {
0468 .name = "s3c2443-adc",
0469 .driver_data = TYPE_ADCV11,
0470 }, {
0471 .name = "s3c2416-adc",
0472 .driver_data = TYPE_ADCV12,
0473 }, {
0474 .name = "s3c64xx-adc",
0475 .driver_data = TYPE_ADCV2,
0476 }, {
0477 .name = "samsung-adc-v3",
0478 .driver_data = TYPE_ADCV3,
0479 },
0480 { }
0481 };
0482 MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
0483
0484 static const struct dev_pm_ops adc_pm_ops = {
0485 .suspend = s3c_adc_suspend,
0486 .resume = s3c_adc_resume,
0487 };
0488
0489 static struct platform_driver s3c_adc_driver = {
0490 .id_table = s3c_adc_driver_ids,
0491 .driver = {
0492 .name = "s3c-adc",
0493 .pm = &adc_pm_ops,
0494 },
0495 .probe = s3c_adc_probe,
0496 .remove = s3c_adc_remove,
0497 };
0498
0499 static int __init adc_init(void)
0500 {
0501 int ret;
0502
0503 ret = platform_driver_register(&s3c_adc_driver);
0504 if (ret)
0505 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
0506
0507 return ret;
0508 }
0509
0510 module_init(adc_init);