From 1455f37b24451822cb686f0ce9309938897f76a2 Mon Sep 17 00:00:00 2001 From: Simon Xue Date: Thu, 18 Nov 2021 16:58:28 +0800 Subject: [PATCH] iio: adc: rockchip_saradc: fix RK3588 saradc panic RK3588 saradc will usleep before start, so if start call from timer will panic. fix it by using delayed_work instead. Change-Id: I7f98266659f5f2d8968a901bd6423efaa50839b5 Signed-off-by: Simon Xue --- drivers/iio/adc/rockchip_saradc.c | 42 ++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index aa2ecae54188..03cc336bf463 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -75,10 +75,11 @@ struct rockchip_saradc { const struct iio_chan_spec *last_chan; bool suspended; #ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN - struct timer_list timer; bool test; u32 chn; spinlock_t lock; + struct workqueue_struct *wq; + struct delayed_work work; #endif }; @@ -228,7 +229,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) spin_lock_irqsave(&info->lock, flags); if (info->test) { pr_info("chn[%d] val = %d\n", info->chn, info->last_val); - mod_timer(&info->timer, jiffies + HZ/1000); + mod_delayed_work(info->wq, &info->work, msecs_to_jiffies(100)); } spin_unlock_irqrestore(&info->lock, flags); #endif @@ -434,13 +435,6 @@ out: } #ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN -static void rockchip_saradc_timer(struct timer_list *t) -{ - struct rockchip_saradc *info = from_timer(info, t, timer); - - rockchip_saradc_start(info, info->chn); -} - static ssize_t saradc_test_chn_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -459,15 +453,15 @@ static ssize_t saradc_test_chn_store(struct device *dev, if (val > SARADC_CTRL_CHN_MASK && info->test) { info->test = false; - del_timer_sync(&info->timer); spin_unlock_irqrestore(&info->lock, flags); + cancel_delayed_work_sync(&info->work); return size; } if (!info->test && val < SARADC_CTRL_CHN_MASK) { info->test = true; info->chn = val; - mod_timer(&info->timer, jiffies + HZ/1000); + mod_delayed_work(info->wq, &info->work, msecs_to_jiffies(100)); } spin_unlock_irqrestore(&info->lock, flags); @@ -492,6 +486,21 @@ static void rockchip_saradc_remove_sysgroup(void *data) sysfs_remove_group(&pdev->dev.kobj, &rockchip_saradc_attr_group); } + +static void rockchip_saradc_destroy_wq(void *data) +{ + struct rockchip_saradc *info = data; + + destroy_workqueue(info->wq); +} + +static void rockchip_saradc_test_work(struct work_struct *work) +{ + struct rockchip_saradc *info = container_of(work, + struct rockchip_saradc, work.work); + + rockchip_saradc_start(info, info->chn); +} #endif static int rockchip_saradc_probe(struct platform_device *pdev) @@ -654,8 +663,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev) return ret; #ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN + info->wq = create_singlethread_workqueue("adc_wq"); + INIT_DELAYED_WORK(&info->work, rockchip_saradc_test_work); spin_lock_init(&info->lock); - timer_setup(&info->timer, rockchip_saradc_timer, 0); ret = sysfs_create_group(&pdev->dev.kobj, &rockchip_saradc_attr_group); if (ret) return ret; @@ -667,6 +677,14 @@ static int rockchip_saradc_probe(struct platform_device *pdev) ret); return ret; } + + ret = devm_add_action_or_reset(&pdev->dev, + rockchip_saradc_destroy_wq, info); + if (ret) { + dev_err(&pdev->dev, "failed to register destroy_wq, %d\n", + ret); + return ret; + } #endif return devm_iio_device_register(&pdev->dev, indio_dev); }