root/arch/arm/plat-samsung/adc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3c_adc_convert
  2. s3c_adc_select
  3. s3c_adc_dbgshow
  4. s3c_adc_try
  5. s3c_adc_start
  6. s3c_convert_done
  7. s3c_adc_read
  8. s3c_adc_default_select
  9. s3c_adc_register
  10. s3c_adc_release
  11. s3c_adc_irq
  12. s3c_adc_probe
  13. s3c_adc_remove
  14. s3c_adc_suspend
  15. s3c_adc_resume
  16. adc_init

   1 // SPDX-License-Identifier: GPL-1.0+
   2 //
   3 // Copyright (c) 2008 Simtec Electronics
   4 //      http://armlinux.simtec.co.uk/
   5 //      Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
   6 //
   7 // Samsung ADC device core
   8 
   9 #include <linux/module.h>
  10 #include <linux/kernel.h>
  11 #include <linux/mod_devicetable.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/sched.h>
  14 #include <linux/list.h>
  15 #include <linux/slab.h>
  16 #include <linux/err.h>
  17 #include <linux/clk.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/io.h>
  20 #include <linux/regulator/consumer.h>
  21 
  22 #include <plat/regs-adc.h>
  23 #include <plat/adc.h>
  24 
  25 /* This driver is designed to control the usage of the ADC block between
  26  * the touchscreen and any other drivers that may need to use it, such as
  27  * the hwmon driver.
  28  *
  29  * Priority will be given to the touchscreen driver, but as this itself is
  30  * rate limited it should not starve other requests which are processed in
  31  * order that they are received.
  32  *
  33  * Each user registers to get a client block which uniquely identifies it
  34  * and stores information such as the necessary functions to callback when
  35  * action is required.
  36  */
  37 
  38 enum s3c_cpu_type {
  39         TYPE_ADCV1, /* S3C24XX */
  40         TYPE_ADCV11, /* S3C2443 */
  41         TYPE_ADCV12, /* S3C2416, S3C2450 */
  42         TYPE_ADCV2, /* S3C64XX */
  43         TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
  44 };
  45 
  46 struct s3c_adc_client {
  47         struct platform_device  *pdev;
  48         struct list_head         pend;
  49         wait_queue_head_t       *wait;
  50 
  51         unsigned int             nr_samples;
  52         int                      result;
  53         unsigned char            is_ts;
  54         unsigned char            channel;
  55 
  56         void    (*select_cb)(struct s3c_adc_client *c, unsigned selected);
  57         void    (*convert_cb)(struct s3c_adc_client *c,
  58                               unsigned val1, unsigned val2,
  59                               unsigned *samples_left);
  60 };
  61 
  62 struct adc_device {
  63         struct platform_device  *pdev;
  64         struct platform_device  *owner;
  65         struct clk              *clk;
  66         struct s3c_adc_client   *cur;
  67         struct s3c_adc_client   *ts_pend;
  68         void __iomem            *regs;
  69         spinlock_t               lock;
  70 
  71         unsigned int             prescale;
  72 
  73         int                      irq;
  74         struct regulator        *vdd;
  75 };
  76 
  77 static struct adc_device *adc_dev;
  78 
  79 static LIST_HEAD(adc_pending);  /* protected by adc_device.lock */
  80 
  81 #define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
  82 
  83 static inline void s3c_adc_convert(struct adc_device *adc)
  84 {
  85         unsigned con = readl(adc->regs + S3C2410_ADCCON);
  86 
  87         con |= S3C2410_ADCCON_ENABLE_START;
  88         writel(con, adc->regs + S3C2410_ADCCON);
  89 }
  90 
  91 static inline void s3c_adc_select(struct adc_device *adc,
  92                                   struct s3c_adc_client *client)
  93 {
  94         unsigned con = readl(adc->regs + S3C2410_ADCCON);
  95         enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
  96 
  97         client->select_cb(client, 1);
  98 
  99         if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2)
 100                 con &= ~S3C2410_ADCCON_MUXMASK;
 101         con &= ~S3C2410_ADCCON_STDBM;
 102         con &= ~S3C2410_ADCCON_STARTMASK;
 103 
 104         if (!client->is_ts) {
 105                 if (cpu == TYPE_ADCV3)
 106                         writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
 107                 else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
 108                         writel(client->channel & 0xf,
 109                                                 adc->regs + S3C2443_ADCMUX);
 110                 else
 111                         con |= S3C2410_ADCCON_SELMUX(client->channel);
 112         }
 113 
 114         writel(con, adc->regs + S3C2410_ADCCON);
 115 }
 116 
 117 static void s3c_adc_dbgshow(struct adc_device *adc)
 118 {
 119         adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
 120                 readl(adc->regs + S3C2410_ADCCON),
 121                 readl(adc->regs + S3C2410_ADCTSC),
 122                 readl(adc->regs + S3C2410_ADCDLY));
 123 }
 124 
 125 static void s3c_adc_try(struct adc_device *adc)
 126 {
 127         struct s3c_adc_client *next = adc->ts_pend;
 128 
 129         if (!next && !list_empty(&adc_pending)) {
 130                 next = list_first_entry(&adc_pending,
 131                                         struct s3c_adc_client, pend);
 132                 list_del(&next->pend);
 133         } else
 134                 adc->ts_pend = NULL;
 135 
 136         if (next) {
 137                 adc_dbg(adc, "new client is %p\n", next);
 138                 adc->cur = next;
 139                 s3c_adc_select(adc, next);
 140                 s3c_adc_convert(adc);
 141                 s3c_adc_dbgshow(adc);
 142         }
 143 }
 144 
 145 int s3c_adc_start(struct s3c_adc_client *client,
 146                   unsigned int channel, unsigned int nr_samples)
 147 {
 148         struct adc_device *adc = adc_dev;
 149         unsigned long flags;
 150 
 151         if (!adc) {
 152                 printk(KERN_ERR "%s: failed to find adc\n", __func__);
 153                 return -EINVAL;
 154         }
 155 
 156         spin_lock_irqsave(&adc->lock, flags);
 157 
 158         if (client->is_ts && adc->ts_pend) {
 159                 spin_unlock_irqrestore(&adc->lock, flags);
 160                 return -EAGAIN;
 161         }
 162 
 163         client->channel = channel;
 164         client->nr_samples = nr_samples;
 165 
 166         if (client->is_ts)
 167                 adc->ts_pend = client;
 168         else
 169                 list_add_tail(&client->pend, &adc_pending);
 170 
 171         if (!adc->cur)
 172                 s3c_adc_try(adc);
 173 
 174         spin_unlock_irqrestore(&adc->lock, flags);
 175 
 176         return 0;
 177 }
 178 EXPORT_SYMBOL_GPL(s3c_adc_start);
 179 
 180 static void s3c_convert_done(struct s3c_adc_client *client,
 181                              unsigned v, unsigned u, unsigned *left)
 182 {
 183         client->result = v;
 184         wake_up(client->wait);
 185 }
 186 
 187 int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
 188 {
 189         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
 190         int ret;
 191 
 192         client->convert_cb = s3c_convert_done;
 193         client->wait = &wake;
 194         client->result = -1;
 195 
 196         ret = s3c_adc_start(client, ch, 1);
 197         if (ret < 0)
 198                 goto err;
 199 
 200         ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
 201         if (client->result < 0) {
 202                 ret = -ETIMEDOUT;
 203                 goto err;
 204         }
 205 
 206         client->convert_cb = NULL;
 207         return client->result;
 208 
 209 err:
 210         return ret;
 211 }
 212 EXPORT_SYMBOL_GPL(s3c_adc_read);
 213 
 214 static void s3c_adc_default_select(struct s3c_adc_client *client,
 215                                    unsigned select)
 216 {
 217 }
 218 
 219 struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
 220                                         void (*select)(struct s3c_adc_client *client,
 221                                                        unsigned int selected),
 222                                         void (*conv)(struct s3c_adc_client *client,
 223                                                      unsigned d0, unsigned d1,
 224                                                      unsigned *samples_left),
 225                                         unsigned int is_ts)
 226 {
 227         struct s3c_adc_client *client;
 228 
 229         WARN_ON(!pdev);
 230 
 231         if (!select)
 232                 select = s3c_adc_default_select;
 233 
 234         if (!pdev)
 235                 return ERR_PTR(-EINVAL);
 236 
 237         client = kzalloc(sizeof(*client), GFP_KERNEL);
 238         if (!client)
 239                 return ERR_PTR(-ENOMEM);
 240 
 241         client->pdev = pdev;
 242         client->is_ts = is_ts;
 243         client->select_cb = select;
 244         client->convert_cb = conv;
 245 
 246         return client;
 247 }
 248 EXPORT_SYMBOL_GPL(s3c_adc_register);
 249 
 250 void s3c_adc_release(struct s3c_adc_client *client)
 251 {
 252         unsigned long flags;
 253 
 254         spin_lock_irqsave(&adc_dev->lock, flags);
 255 
 256         /* We should really check that nothing is in progress. */
 257         if (adc_dev->cur == client)
 258                 adc_dev->cur = NULL;
 259         if (adc_dev->ts_pend == client)
 260                 adc_dev->ts_pend = NULL;
 261         else {
 262                 struct list_head *p, *n;
 263                 struct s3c_adc_client *tmp;
 264 
 265                 list_for_each_safe(p, n, &adc_pending) {
 266                         tmp = list_entry(p, struct s3c_adc_client, pend);
 267                         if (tmp == client)
 268                                 list_del(&tmp->pend);
 269                 }
 270         }
 271 
 272         if (adc_dev->cur == NULL)
 273                 s3c_adc_try(adc_dev);
 274 
 275         spin_unlock_irqrestore(&adc_dev->lock, flags);
 276         kfree(client);
 277 }
 278 EXPORT_SYMBOL_GPL(s3c_adc_release);
 279 
 280 static irqreturn_t s3c_adc_irq(int irq, void *pw)
 281 {
 282         struct adc_device *adc = pw;
 283         struct s3c_adc_client *client = adc->cur;
 284         enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
 285         unsigned data0, data1;
 286 
 287         if (!client) {
 288                 dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
 289                 goto exit;
 290         }
 291 
 292         data0 = readl(adc->regs + S3C2410_ADCDAT0);
 293         data1 = readl(adc->regs + S3C2410_ADCDAT1);
 294         adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
 295 
 296         client->nr_samples--;
 297 
 298         if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) {
 299                 data0 &= 0x3ff;
 300                 data1 &= 0x3ff;
 301         } else {
 302                 /* S3C2416/S3C64XX/S5P ADC resolution is 12-bit */
 303                 data0 &= 0xfff;
 304                 data1 &= 0xfff;
 305         }
 306 
 307         if (client->convert_cb)
 308                 (client->convert_cb)(client, data0, data1, &client->nr_samples);
 309 
 310         if (client->nr_samples > 0) {
 311                 /* fire another conversion for this */
 312 
 313                 client->select_cb(client, 1);
 314                 s3c_adc_convert(adc);
 315         } else {
 316                 spin_lock(&adc->lock);
 317                 (client->select_cb)(client, 0);
 318                 adc->cur = NULL;
 319 
 320                 s3c_adc_try(adc);
 321                 spin_unlock(&adc->lock);
 322         }
 323 
 324 exit:
 325         if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) {
 326                 /* Clear ADC interrupt */
 327                 writel(0, adc->regs + S3C64XX_ADCCLRINT);
 328         }
 329         return IRQ_HANDLED;
 330 }
 331 
 332 static int s3c_adc_probe(struct platform_device *pdev)
 333 {
 334         struct device *dev = &pdev->dev;
 335         struct adc_device *adc;
 336         struct resource *regs;
 337         enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
 338         int ret;
 339         unsigned tmp;
 340 
 341         adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL);
 342         if (!adc)
 343                 return -ENOMEM;
 344 
 345         spin_lock_init(&adc->lock);
 346 
 347         adc->pdev = pdev;
 348         adc->prescale = S3C2410_ADCCON_PRSCVL(49);
 349 
 350         adc->vdd = devm_regulator_get(dev, "vdd");
 351         if (IS_ERR(adc->vdd)) {
 352                 dev_err(dev, "operating without regulator \"vdd\" .\n");
 353                 return PTR_ERR(adc->vdd);
 354         }
 355 
 356         adc->irq = platform_get_irq(pdev, 1);
 357         if (adc->irq <= 0) {
 358                 dev_err(dev, "failed to get adc irq\n");
 359                 return -ENOENT;
 360         }
 361 
 362         ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev),
 363                                 adc);
 364         if (ret < 0) {
 365                 dev_err(dev, "failed to attach adc irq\n");
 366                 return ret;
 367         }
 368 
 369         adc->clk = devm_clk_get(dev, "adc");
 370         if (IS_ERR(adc->clk)) {
 371                 dev_err(dev, "failed to get adc clock\n");
 372                 return PTR_ERR(adc->clk);
 373         }
 374 
 375         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 376         adc->regs = devm_ioremap_resource(dev, regs);
 377         if (IS_ERR(adc->regs))
 378                 return PTR_ERR(adc->regs);
 379 
 380         ret = regulator_enable(adc->vdd);
 381         if (ret)
 382                 return ret;
 383 
 384         clk_prepare_enable(adc->clk);
 385 
 386         tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
 387 
 388         /* Enable 12-bit ADC resolution */
 389         if (cpu == TYPE_ADCV12)
 390                 tmp |= S3C2416_ADCCON_RESSEL;
 391         if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
 392                 tmp |= S3C64XX_ADCCON_RESSEL;
 393 
 394         writel(tmp, adc->regs + S3C2410_ADCCON);
 395 
 396         dev_info(dev, "attached adc driver\n");
 397 
 398         platform_set_drvdata(pdev, adc);
 399         adc_dev = adc;
 400 
 401         return 0;
 402 }
 403 
 404 static int s3c_adc_remove(struct platform_device *pdev)
 405 {
 406         struct adc_device *adc = platform_get_drvdata(pdev);
 407 
 408         clk_disable_unprepare(adc->clk);
 409         regulator_disable(adc->vdd);
 410 
 411         return 0;
 412 }
 413 
 414 #ifdef CONFIG_PM
 415 static int s3c_adc_suspend(struct device *dev)
 416 {
 417         struct adc_device *adc = dev_get_drvdata(dev);
 418         unsigned long flags;
 419         u32 con;
 420 
 421         spin_lock_irqsave(&adc->lock, flags);
 422 
 423         con = readl(adc->regs + S3C2410_ADCCON);
 424         con |= S3C2410_ADCCON_STDBM;
 425         writel(con, adc->regs + S3C2410_ADCCON);
 426 
 427         disable_irq(adc->irq);
 428         spin_unlock_irqrestore(&adc->lock, flags);
 429         clk_disable(adc->clk);
 430         regulator_disable(adc->vdd);
 431 
 432         return 0;
 433 }
 434 
 435 static int s3c_adc_resume(struct device *dev)
 436 {
 437         struct platform_device *pdev = to_platform_device(dev);
 438         struct adc_device *adc = platform_get_drvdata(pdev);
 439         enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
 440         int ret;
 441         unsigned long tmp;
 442 
 443         ret = regulator_enable(adc->vdd);
 444         if (ret)
 445                 return ret;
 446         clk_enable(adc->clk);
 447         enable_irq(adc->irq);
 448 
 449         tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
 450 
 451         /* Enable 12-bit ADC resolution */
 452         if (cpu == TYPE_ADCV12)
 453                 tmp |= S3C2416_ADCCON_RESSEL;
 454         if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
 455                 tmp |= S3C64XX_ADCCON_RESSEL;
 456 
 457         writel(tmp, adc->regs + S3C2410_ADCCON);
 458 
 459         return 0;
 460 }
 461 
 462 #else
 463 #define s3c_adc_suspend NULL
 464 #define s3c_adc_resume NULL
 465 #endif
 466 
 467 static const struct platform_device_id s3c_adc_driver_ids[] = {
 468         {
 469                 .name           = "s3c24xx-adc",
 470                 .driver_data    = TYPE_ADCV1,
 471         }, {
 472                 .name           = "s3c2443-adc",
 473                 .driver_data    = TYPE_ADCV11,
 474         }, {
 475                 .name           = "s3c2416-adc",
 476                 .driver_data    = TYPE_ADCV12,
 477         }, {
 478                 .name           = "s3c64xx-adc",
 479                 .driver_data    = TYPE_ADCV2,
 480         }, {
 481                 .name           = "samsung-adc-v3",
 482                 .driver_data    = TYPE_ADCV3,
 483         },
 484         { }
 485 };
 486 MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
 487 
 488 static const struct dev_pm_ops adc_pm_ops = {
 489         .suspend        = s3c_adc_suspend,
 490         .resume         = s3c_adc_resume,
 491 };
 492 
 493 static struct platform_driver s3c_adc_driver = {
 494         .id_table       = s3c_adc_driver_ids,
 495         .driver         = {
 496                 .name   = "s3c-adc",
 497                 .pm     = &adc_pm_ops,
 498         },
 499         .probe          = s3c_adc_probe,
 500         .remove         = s3c_adc_remove,
 501 };
 502 
 503 static int __init adc_init(void)
 504 {
 505         int ret;
 506 
 507         ret = platform_driver_register(&s3c_adc_driver);
 508         if (ret)
 509                 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
 510 
 511         return ret;
 512 }
 513 
 514 module_init(adc_init);

/* [<][>][^][v][top][bottom][index][help] */