diff options
Diffstat (limited to 'drivers/iio/adc/exynos_adc.c')
-rw-r--r-- | drivers/iio/adc/exynos_adc.c | 224 |
1 files changed, 217 insertions, 7 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 3a2dbb3b4926..c15756d7bf7f 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/regulator/consumer.h> | 35 | #include <linux/regulator/consumer.h> |
36 | #include <linux/of_platform.h> | 36 | #include <linux/of_platform.h> |
37 | #include <linux/err.h> | 37 | #include <linux/err.h> |
38 | #include <linux/input.h> | ||
38 | 39 | ||
39 | #include <linux/iio/iio.h> | 40 | #include <linux/iio/iio.h> |
40 | #include <linux/iio/machine.h> | 41 | #include <linux/iio/machine.h> |
@@ -42,12 +43,18 @@ | |||
42 | #include <linux/mfd/syscon.h> | 43 | #include <linux/mfd/syscon.h> |
43 | #include <linux/regmap.h> | 44 | #include <linux/regmap.h> |
44 | 45 | ||
46 | #include <linux/platform_data/touchscreen-s3c2410.h> | ||
47 | |||
45 | /* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ | 48 | /* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ |
46 | #define ADC_V1_CON(x) ((x) + 0x00) | 49 | #define ADC_V1_CON(x) ((x) + 0x00) |
50 | #define ADC_V1_TSC(x) ((x) + 0x04) | ||
47 | #define ADC_V1_DLY(x) ((x) + 0x08) | 51 | #define ADC_V1_DLY(x) ((x) + 0x08) |
48 | #define ADC_V1_DATX(x) ((x) + 0x0C) | 52 | #define ADC_V1_DATX(x) ((x) + 0x0C) |
53 | #define ADC_V1_DATY(x) ((x) + 0x10) | ||
54 | #define ADC_V1_UPDN(x) ((x) + 0x14) | ||
49 | #define ADC_V1_INTCLR(x) ((x) + 0x18) | 55 | #define ADC_V1_INTCLR(x) ((x) + 0x18) |
50 | #define ADC_V1_MUX(x) ((x) + 0x1c) | 56 | #define ADC_V1_MUX(x) ((x) + 0x1c) |
57 | #define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20) | ||
51 | 58 | ||
52 | /* S3C2410 ADC registers definitions */ | 59 | /* S3C2410 ADC registers definitions */ |
53 | #define ADC_S3C2410_MUX(x) ((x) + 0x18) | 60 | #define ADC_S3C2410_MUX(x) ((x) + 0x18) |
@@ -71,6 +78,30 @@ | |||
71 | #define ADC_S3C2410_DATX_MASK 0x3FF | 78 | #define ADC_S3C2410_DATX_MASK 0x3FF |
72 | #define ADC_S3C2416_CON_RES_SEL (1u << 3) | 79 | #define ADC_S3C2416_CON_RES_SEL (1u << 3) |
73 | 80 | ||
81 | /* touch screen always uses channel 0 */ | ||
82 | #define ADC_S3C2410_MUX_TS 0 | ||
83 | |||
84 | /* ADCTSC Register Bits */ | ||
85 | #define ADC_S3C2443_TSC_UD_SEN (1u << 8) | ||
86 | #define ADC_S3C2410_TSC_YM_SEN (1u << 7) | ||
87 | #define ADC_S3C2410_TSC_YP_SEN (1u << 6) | ||
88 | #define ADC_S3C2410_TSC_XM_SEN (1u << 5) | ||
89 | #define ADC_S3C2410_TSC_XP_SEN (1u << 4) | ||
90 | #define ADC_S3C2410_TSC_PULL_UP_DISABLE (1u << 3) | ||
91 | #define ADC_S3C2410_TSC_AUTO_PST (1u << 2) | ||
92 | #define ADC_S3C2410_TSC_XY_PST(x) (((x) & 0x3) << 0) | ||
93 | |||
94 | #define ADC_TSC_WAIT4INT (ADC_S3C2410_TSC_YM_SEN | \ | ||
95 | ADC_S3C2410_TSC_YP_SEN | \ | ||
96 | ADC_S3C2410_TSC_XP_SEN | \ | ||
97 | ADC_S3C2410_TSC_XY_PST(3)) | ||
98 | |||
99 | #define ADC_TSC_AUTOPST (ADC_S3C2410_TSC_YM_SEN | \ | ||
100 | ADC_S3C2410_TSC_YP_SEN | \ | ||
101 | ADC_S3C2410_TSC_XP_SEN | \ | ||
102 | ADC_S3C2410_TSC_AUTO_PST | \ | ||
103 | ADC_S3C2410_TSC_XY_PST(0)) | ||
104 | |||
74 | /* Bit definitions for ADC_V2 */ | 105 | /* Bit definitions for ADC_V2 */ |
75 | #define ADC_V2_CON1_SOFT_RESET (1u << 2) | 106 | #define ADC_V2_CON1_SOFT_RESET (1u << 2) |
76 | 107 | ||
@@ -88,7 +119,9 @@ | |||
88 | /* Bit definitions common for ADC_V1 and ADC_V2 */ | 119 | /* Bit definitions common for ADC_V1 and ADC_V2 */ |
89 | #define ADC_CON_EN_START (1u << 0) | 120 | #define ADC_CON_EN_START (1u << 0) |
90 | #define ADC_CON_EN_START_MASK (0x3 << 0) | 121 | #define ADC_CON_EN_START_MASK (0x3 << 0) |
122 | #define ADC_DATX_PRESSED (1u << 15) | ||
91 | #define ADC_DATX_MASK 0xFFF | 123 | #define ADC_DATX_MASK 0xFFF |
124 | #define ADC_DATY_MASK 0xFFF | ||
92 | 125 | ||
93 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) | 126 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) |
94 | 127 | ||
@@ -98,17 +131,24 @@ | |||
98 | struct exynos_adc { | 131 | struct exynos_adc { |
99 | struct exynos_adc_data *data; | 132 | struct exynos_adc_data *data; |
100 | struct device *dev; | 133 | struct device *dev; |
134 | struct input_dev *input; | ||
101 | void __iomem *regs; | 135 | void __iomem *regs; |
102 | struct regmap *pmu_map; | 136 | struct regmap *pmu_map; |
103 | struct clk *clk; | 137 | struct clk *clk; |
104 | struct clk *sclk; | 138 | struct clk *sclk; |
105 | unsigned int irq; | 139 | unsigned int irq; |
140 | unsigned int tsirq; | ||
141 | unsigned int delay; | ||
106 | struct regulator *vdd; | 142 | struct regulator *vdd; |
107 | 143 | ||
108 | struct completion completion; | 144 | struct completion completion; |
109 | 145 | ||
110 | u32 value; | 146 | u32 value; |
111 | unsigned int version; | 147 | unsigned int version; |
148 | |||
149 | bool read_ts; | ||
150 | u32 ts_x; | ||
151 | u32 ts_y; | ||
112 | }; | 152 | }; |
113 | 153 | ||
114 | struct exynos_adc_data { | 154 | struct exynos_adc_data { |
@@ -197,6 +237,9 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info) | |||
197 | /* Enable 12-bit ADC resolution */ | 237 | /* Enable 12-bit ADC resolution */ |
198 | con1 |= ADC_V1_CON_RES; | 238 | con1 |= ADC_V1_CON_RES; |
199 | writel(con1, ADC_V1_CON(info->regs)); | 239 | writel(con1, ADC_V1_CON(info->regs)); |
240 | |||
241 | /* set touchscreen delay */ | ||
242 | writel(info->delay, ADC_V1_DLY(info->regs)); | ||
200 | } | 243 | } |
201 | 244 | ||
202 | static void exynos_adc_v1_exit_hw(struct exynos_adc *info) | 245 | static void exynos_adc_v1_exit_hw(struct exynos_adc *info) |
@@ -480,8 +523,8 @@ static int exynos_read_raw(struct iio_dev *indio_dev, | |||
480 | if (info->data->start_conv) | 523 | if (info->data->start_conv) |
481 | info->data->start_conv(info, chan->address); | 524 | info->data->start_conv(info, chan->address); |
482 | 525 | ||
483 | timeout = wait_for_completion_timeout | 526 | timeout = wait_for_completion_timeout(&info->completion, |
484 | (&info->completion, EXYNOS_ADC_TIMEOUT); | 527 | EXYNOS_ADC_TIMEOUT); |
485 | if (timeout == 0) { | 528 | if (timeout == 0) { |
486 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); | 529 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); |
487 | if (info->data->init_hw) | 530 | if (info->data->init_hw) |
@@ -498,13 +541,55 @@ static int exynos_read_raw(struct iio_dev *indio_dev, | |||
498 | return ret; | 541 | return ret; |
499 | } | 542 | } |
500 | 543 | ||
544 | static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y) | ||
545 | { | ||
546 | struct exynos_adc *info = iio_priv(indio_dev); | ||
547 | unsigned long timeout; | ||
548 | int ret; | ||
549 | |||
550 | mutex_lock(&indio_dev->mlock); | ||
551 | info->read_ts = true; | ||
552 | |||
553 | reinit_completion(&info->completion); | ||
554 | |||
555 | writel(ADC_S3C2410_TSC_PULL_UP_DISABLE | ADC_TSC_AUTOPST, | ||
556 | ADC_V1_TSC(info->regs)); | ||
557 | |||
558 | /* Select the ts channel to be used and Trigger conversion */ | ||
559 | info->data->start_conv(info, ADC_S3C2410_MUX_TS); | ||
560 | |||
561 | timeout = wait_for_completion_timeout(&info->completion, | ||
562 | EXYNOS_ADC_TIMEOUT); | ||
563 | if (timeout == 0) { | ||
564 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); | ||
565 | if (info->data->init_hw) | ||
566 | info->data->init_hw(info); | ||
567 | ret = -ETIMEDOUT; | ||
568 | } else { | ||
569 | *x = info->ts_x; | ||
570 | *y = info->ts_y; | ||
571 | ret = 0; | ||
572 | } | ||
573 | |||
574 | info->read_ts = false; | ||
575 | mutex_unlock(&indio_dev->mlock); | ||
576 | |||
577 | return ret; | ||
578 | } | ||
579 | |||
501 | static irqreturn_t exynos_adc_isr(int irq, void *dev_id) | 580 | static irqreturn_t exynos_adc_isr(int irq, void *dev_id) |
502 | { | 581 | { |
503 | struct exynos_adc *info = (struct exynos_adc *)dev_id; | 582 | struct exynos_adc *info = (struct exynos_adc *)dev_id; |
504 | u32 mask = info->data->mask; | 583 | u32 mask = info->data->mask; |
505 | 584 | ||
506 | /* Read value */ | 585 | /* Read value */ |
507 | info->value = readl(ADC_V1_DATX(info->regs)) & mask; | 586 | if (info->read_ts) { |
587 | info->ts_x = readl(ADC_V1_DATX(info->regs)); | ||
588 | info->ts_y = readl(ADC_V1_DATY(info->regs)); | ||
589 | writel(ADC_TSC_WAIT4INT | ADC_S3C2443_TSC_UD_SEN, ADC_V1_TSC(info->regs)); | ||
590 | } else { | ||
591 | info->value = readl(ADC_V1_DATX(info->regs)) & mask; | ||
592 | } | ||
508 | 593 | ||
509 | /* clear irq */ | 594 | /* clear irq */ |
510 | if (info->data->clear_irq) | 595 | if (info->data->clear_irq) |
@@ -515,6 +600,46 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id) | |||
515 | return IRQ_HANDLED; | 600 | return IRQ_HANDLED; |
516 | } | 601 | } |
517 | 602 | ||
603 | /* | ||
604 | * Here we (ab)use a threaded interrupt handler to stay running | ||
605 | * for as long as the touchscreen remains pressed, we report | ||
606 | * a new event with the latest data and then sleep until the | ||
607 | * next timer tick. This mirrors the behavior of the old | ||
608 | * driver, with much less code. | ||
609 | */ | ||
610 | static irqreturn_t exynos_ts_isr(int irq, void *dev_id) | ||
611 | { | ||
612 | struct exynos_adc *info = dev_id; | ||
613 | struct iio_dev *dev = dev_get_drvdata(info->dev); | ||
614 | u32 x, y; | ||
615 | bool pressed; | ||
616 | int ret; | ||
617 | |||
618 | while (info->input->users) { | ||
619 | ret = exynos_read_s3c64xx_ts(dev, &x, &y); | ||
620 | if (ret == -ETIMEDOUT) | ||
621 | break; | ||
622 | |||
623 | pressed = x & y & ADC_DATX_PRESSED; | ||
624 | if (!pressed) { | ||
625 | input_report_key(info->input, BTN_TOUCH, 0); | ||
626 | input_sync(info->input); | ||
627 | break; | ||
628 | } | ||
629 | |||
630 | input_report_abs(info->input, ABS_X, x & ADC_DATX_MASK); | ||
631 | input_report_abs(info->input, ABS_Y, y & ADC_DATY_MASK); | ||
632 | input_report_key(info->input, BTN_TOUCH, 1); | ||
633 | input_sync(info->input); | ||
634 | |||
635 | msleep(1); | ||
636 | }; | ||
637 | |||
638 | writel(0, ADC_V1_CLRINTPNDNUP(info->regs)); | ||
639 | |||
640 | return IRQ_HANDLED; | ||
641 | } | ||
642 | |||
518 | static int exynos_adc_reg_access(struct iio_dev *indio_dev, | 643 | static int exynos_adc_reg_access(struct iio_dev *indio_dev, |
519 | unsigned reg, unsigned writeval, | 644 | unsigned reg, unsigned writeval, |
520 | unsigned *readval) | 645 | unsigned *readval) |
@@ -566,18 +691,72 @@ static int exynos_adc_remove_devices(struct device *dev, void *c) | |||
566 | return 0; | 691 | return 0; |
567 | } | 692 | } |
568 | 693 | ||
694 | static int exynos_adc_ts_open(struct input_dev *dev) | ||
695 | { | ||
696 | struct exynos_adc *info = input_get_drvdata(dev); | ||
697 | |||
698 | enable_irq(info->tsirq); | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static void exynos_adc_ts_close(struct input_dev *dev) | ||
704 | { | ||
705 | struct exynos_adc *info = input_get_drvdata(dev); | ||
706 | |||
707 | disable_irq(info->tsirq); | ||
708 | } | ||
709 | |||
710 | static int exynos_adc_ts_init(struct exynos_adc *info) | ||
711 | { | ||
712 | int ret; | ||
713 | |||
714 | if (info->tsirq <= 0) | ||
715 | return -ENODEV; | ||
716 | |||
717 | info->input = input_allocate_device(); | ||
718 | if (!info->input) | ||
719 | return -ENOMEM; | ||
720 | |||
721 | info->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
722 | info->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
723 | |||
724 | input_set_abs_params(info->input, ABS_X, 0, 0x3FF, 0, 0); | ||
725 | input_set_abs_params(info->input, ABS_Y, 0, 0x3FF, 0, 0); | ||
726 | |||
727 | info->input->name = "S3C24xx TouchScreen"; | ||
728 | info->input->id.bustype = BUS_HOST; | ||
729 | info->input->open = exynos_adc_ts_open; | ||
730 | info->input->close = exynos_adc_ts_close; | ||
731 | |||
732 | input_set_drvdata(info->input, info); | ||
733 | |||
734 | ret = input_register_device(info->input); | ||
735 | if (ret) { | ||
736 | input_free_device(info->input); | ||
737 | return ret; | ||
738 | } | ||
739 | |||
740 | disable_irq(info->tsirq); | ||
741 | ret = request_threaded_irq(info->tsirq, NULL, exynos_ts_isr, | ||
742 | IRQF_ONESHOT, "touchscreen", info); | ||
743 | if (ret) | ||
744 | input_unregister_device(info->input); | ||
745 | |||
746 | return ret; | ||
747 | } | ||
748 | |||
569 | static int exynos_adc_probe(struct platform_device *pdev) | 749 | static int exynos_adc_probe(struct platform_device *pdev) |
570 | { | 750 | { |
571 | struct exynos_adc *info = NULL; | 751 | struct exynos_adc *info = NULL; |
572 | struct device_node *np = pdev->dev.of_node; | 752 | struct device_node *np = pdev->dev.of_node; |
753 | struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev); | ||
573 | struct iio_dev *indio_dev = NULL; | 754 | struct iio_dev *indio_dev = NULL; |
574 | struct resource *mem; | 755 | struct resource *mem; |
756 | bool has_ts = false; | ||
575 | int ret = -ENODEV; | 757 | int ret = -ENODEV; |
576 | int irq; | 758 | int irq; |
577 | 759 | ||
578 | if (!np) | ||
579 | return ret; | ||
580 | |||
581 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); | 760 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); |
582 | if (!indio_dev) { | 761 | if (!indio_dev) { |
583 | dev_err(&pdev->dev, "failed allocating iio device\n"); | 762 | dev_err(&pdev->dev, "failed allocating iio device\n"); |
@@ -613,8 +792,14 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
613 | dev_err(&pdev->dev, "no irq resource?\n"); | 792 | dev_err(&pdev->dev, "no irq resource?\n"); |
614 | return irq; | 793 | return irq; |
615 | } | 794 | } |
616 | |||
617 | info->irq = irq; | 795 | info->irq = irq; |
796 | |||
797 | irq = platform_get_irq(pdev, 1); | ||
798 | if (irq == -EPROBE_DEFER) | ||
799 | return irq; | ||
800 | |||
801 | info->tsirq = irq; | ||
802 | |||
618 | info->dev = &pdev->dev; | 803 | info->dev = &pdev->dev; |
619 | 804 | ||
620 | init_completion(&info->completion); | 805 | init_completion(&info->completion); |
@@ -680,6 +865,22 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
680 | if (info->data->init_hw) | 865 | if (info->data->init_hw) |
681 | info->data->init_hw(info); | 866 | info->data->init_hw(info); |
682 | 867 | ||
868 | /* leave out any TS related code if unreachable */ | ||
869 | if (IS_REACHABLE(CONFIG_INPUT)) { | ||
870 | has_ts = of_property_read_bool(pdev->dev.of_node, | ||
871 | "has-touchscreen") || pdata; | ||
872 | } | ||
873 | |||
874 | if (pdata) | ||
875 | info->delay = pdata->delay; | ||
876 | else | ||
877 | info->delay = 10000; | ||
878 | |||
879 | if (has_ts) | ||
880 | ret = exynos_adc_ts_init(info); | ||
881 | if (ret) | ||
882 | goto err_iio; | ||
883 | |||
683 | ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); | 884 | ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); |
684 | if (ret < 0) { | 885 | if (ret < 0) { |
685 | dev_err(&pdev->dev, "failed adding child nodes\n"); | 886 | dev_err(&pdev->dev, "failed adding child nodes\n"); |
@@ -691,6 +892,11 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
691 | err_of_populate: | 892 | err_of_populate: |
692 | device_for_each_child(&indio_dev->dev, NULL, | 893 | device_for_each_child(&indio_dev->dev, NULL, |
693 | exynos_adc_remove_devices); | 894 | exynos_adc_remove_devices); |
895 | if (has_ts) { | ||
896 | input_unregister_device(info->input); | ||
897 | free_irq(info->tsirq, info); | ||
898 | } | ||
899 | err_iio: | ||
694 | iio_device_unregister(indio_dev); | 900 | iio_device_unregister(indio_dev); |
695 | err_irq: | 901 | err_irq: |
696 | free_irq(info->irq, info); | 902 | free_irq(info->irq, info); |
@@ -710,6 +916,10 @@ static int exynos_adc_remove(struct platform_device *pdev) | |||
710 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | 916 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); |
711 | struct exynos_adc *info = iio_priv(indio_dev); | 917 | struct exynos_adc *info = iio_priv(indio_dev); |
712 | 918 | ||
919 | if (IS_REACHABLE(CONFIG_INPUT)) { | ||
920 | free_irq(info->tsirq, info); | ||
921 | input_unregister_device(info->input); | ||
922 | } | ||
713 | device_for_each_child(&indio_dev->dev, NULL, | 923 | device_for_each_child(&indio_dev->dev, NULL, |
714 | exynos_adc_remove_devices); | 924 | exynos_adc_remove_devices); |
715 | iio_device_unregister(indio_dev); | 925 | iio_device_unregister(indio_dev); |