|
@@ -84,3 +84,84 @@ static LIST_HEAD(adc_pending); /* protected by adc_device.lock */
|
|
|
|
|
|
#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
|
|
|
|
|
|
+static inline void s3c_adc_convert(struct adc_device *adc)
|
|
|
+{
|
|
|
+ unsigned con = readl(adc->regs + S3C2410_ADCCON);
|
|
|
+
|
|
|
+ con |= S3C2410_ADCCON_ENABLE_START;
|
|
|
+ writel(con, adc->regs + S3C2410_ADCCON);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void s3c_adc_select(struct adc_device *adc,
|
|
|
+ struct s3c_adc_client *client)
|
|
|
+{
|
|
|
+ unsigned con = readl(adc->regs + S3C2410_ADCCON);
|
|
|
+ enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
|
|
|
+
|
|
|
+ client->select_cb(client, 1);
|
|
|
+
|
|
|
+ if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2)
|
|
|
+ con &= ~S3C2410_ADCCON_MUXMASK;
|
|
|
+ con &= ~S3C2410_ADCCON_STDBM;
|
|
|
+ con &= ~S3C2410_ADCCON_STARTMASK;
|
|
|
+
|
|
|
+ if (!client->is_ts) {
|
|
|
+ if (cpu == TYPE_ADCV3)
|
|
|
+ writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
|
|
|
+ else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
|
|
|
+ writel(client->channel & 0xf,
|
|
|
+ adc->regs + S3C2443_ADCMUX);
|
|
|
+ else
|
|
|
+ con |= S3C2410_ADCCON_SELMUX(client->channel);
|
|
|
+ }
|
|
|
+
|
|
|
+ writel(con, adc->regs + S3C2410_ADCCON);
|
|
|
+}
|
|
|
+
|
|
|
+static void s3c_adc_dbgshow(struct adc_device *adc)
|
|
|
+{
|
|
|
+ adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
|
|
|
+ readl(adc->regs + S3C2410_ADCCON),
|
|
|
+ readl(adc->regs + S3C2410_ADCTSC),
|
|
|
+ readl(adc->regs + S3C2410_ADCDLY));
|
|
|
+}
|
|
|
+
|
|
|
+static void s3c_adc_try(struct adc_device *adc)
|
|
|
+{
|
|
|
+ struct s3c_adc_client *next = adc->ts_pend;
|
|
|
+
|
|
|
+ if (!next && !list_empty(&adc_pending)) {
|
|
|
+ next = list_first_entry(&adc_pending,
|
|
|
+ struct s3c_adc_client, pend);
|
|
|
+ list_del(&next->pend);
|
|
|
+ } else
|
|
|
+ adc->ts_pend = NULL;
|
|
|
+
|
|
|
+ if (next) {
|
|
|
+ adc_dbg(adc, "new client is %p\n", next);
|
|
|
+ adc->cur = next;
|
|
|
+ s3c_adc_select(adc, next);
|
|
|
+ s3c_adc_convert(adc);
|
|
|
+ s3c_adc_dbgshow(adc);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int s3c_adc_start(struct s3c_adc_client *client,
|
|
|
+ unsigned int channel, unsigned int nr_samples)
|
|
|
+{
|
|
|
+ struct adc_device *adc = adc_dev;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (!adc) {
|
|
|
+ printk(KERN_ERR "%s: failed to find adc\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_lock_irqsave(&adc->lock, flags);
|
|
|
+
|
|
|
+ if (client->is_ts && adc->ts_pend) {
|
|
|
+ spin_unlock_irqrestore(&adc->lock, flags);
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ client->channel = channel;
|