18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * TI Touch Screen / ADC MFD driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 118c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 128c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2ecf20Sopenharmony_ci * GNU General Public License for more details. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/clk.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 238c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 248c2ecf20Sopenharmony_ci#include <linux/of.h> 258c2ecf20Sopenharmony_ci#include <linux/of_device.h> 268c2ecf20Sopenharmony_ci#include <linux/sched.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/mfd/ti_am335x_tscadc.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const struct regmap_config tscadc_regmap_config = { 318c2ecf20Sopenharmony_ci .name = "ti_tscadc", 328c2ecf20Sopenharmony_ci .reg_bits = 32, 338c2ecf20Sopenharmony_ci .reg_stride = 4, 348c2ecf20Sopenharmony_ci .val_bits = 32, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_civoid am335x_tsc_se_set_cache(struct ti_tscadc_dev *tscadc, u32 val) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci unsigned long flags; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci spin_lock_irqsave(&tscadc->reg_lock, flags); 428c2ecf20Sopenharmony_ci tscadc->reg_se_cache |= val; 438c2ecf20Sopenharmony_ci if (tscadc->adc_waiting) 448c2ecf20Sopenharmony_ci wake_up(&tscadc->reg_se_wait); 458c2ecf20Sopenharmony_ci else if (!tscadc->adc_in_use) 468c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tscadc->reg_lock, flags); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(am335x_tsc_se_set_cache); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void am335x_tscadc_need_adc(struct ti_tscadc_dev *tscadc) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 558c2ecf20Sopenharmony_ci u32 reg; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci regmap_read(tscadc->regmap, REG_ADCFSM, ®); 588c2ecf20Sopenharmony_ci if (reg & SEQ_STATUS) { 598c2ecf20Sopenharmony_ci tscadc->adc_waiting = true; 608c2ecf20Sopenharmony_ci prepare_to_wait(&tscadc->reg_se_wait, &wait, 618c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 628c2ecf20Sopenharmony_ci spin_unlock_irq(&tscadc->reg_lock); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci schedule(); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci spin_lock_irq(&tscadc->reg_lock); 678c2ecf20Sopenharmony_ci finish_wait(&tscadc->reg_se_wait, &wait); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * Sequencer should either be idle or 718c2ecf20Sopenharmony_ci * busy applying the charge step. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci regmap_read(tscadc->regmap, REG_ADCFSM, ®); 748c2ecf20Sopenharmony_ci WARN_ON((reg & SEQ_STATUS) && !(reg & CHARGE_STEP)); 758c2ecf20Sopenharmony_ci tscadc->adc_waiting = false; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci tscadc->adc_in_use = true; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid am335x_tsc_se_set_once(struct ti_tscadc_dev *tscadc, u32 val) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci spin_lock_irq(&tscadc->reg_lock); 838c2ecf20Sopenharmony_ci am335x_tscadc_need_adc(tscadc); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, val); 868c2ecf20Sopenharmony_ci spin_unlock_irq(&tscadc->reg_lock); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid am335x_tsc_se_adc_done(struct ti_tscadc_dev *tscadc) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci unsigned long flags; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci spin_lock_irqsave(&tscadc->reg_lock, flags); 958c2ecf20Sopenharmony_ci tscadc->adc_in_use = false; 968c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); 978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tscadc->reg_lock, flags); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid am335x_tsc_se_clr(struct ti_tscadc_dev *tscadc, u32 val) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned long flags; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci spin_lock_irqsave(&tscadc->reg_lock, flags); 1068c2ecf20Sopenharmony_ci tscadc->reg_se_cache &= ~val; 1078c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); 1088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tscadc->reg_lock, flags); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(am335x_tsc_se_clr); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void tscadc_idle_config(struct ti_tscadc_dev *tscadc) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci unsigned int idleconfig; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM | 1178c2ecf20Sopenharmony_ci STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_IDLECONFIG, idleconfig); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int ti_tscadc_probe(struct platform_device *pdev) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct ti_tscadc_dev *tscadc; 1258c2ecf20Sopenharmony_ci struct resource *res; 1268c2ecf20Sopenharmony_ci struct clk *clk; 1278c2ecf20Sopenharmony_ci struct device_node *node; 1288c2ecf20Sopenharmony_ci struct mfd_cell *cell; 1298c2ecf20Sopenharmony_ci struct property *prop; 1308c2ecf20Sopenharmony_ci const __be32 *cur; 1318c2ecf20Sopenharmony_ci u32 val; 1328c2ecf20Sopenharmony_ci int err, ctrl; 1338c2ecf20Sopenharmony_ci int clock_rate; 1348c2ecf20Sopenharmony_ci int tsc_wires = 0, adc_channels = 0, total_channels; 1358c2ecf20Sopenharmony_ci int readouts = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (!pdev->dev.of_node) { 1388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not find valid DT data.\n"); 1398c2ecf20Sopenharmony_ci return -EINVAL; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci node = of_get_child_by_name(pdev->dev.of_node, "tsc"); 1438c2ecf20Sopenharmony_ci of_property_read_u32(node, "ti,wires", &tsc_wires); 1448c2ecf20Sopenharmony_ci of_property_read_u32(node, "ti,coordiante-readouts", &readouts); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci node = of_get_child_by_name(pdev->dev.of_node, "adc"); 1478c2ecf20Sopenharmony_ci of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { 1488c2ecf20Sopenharmony_ci adc_channels++; 1498c2ecf20Sopenharmony_ci if (val > 7) { 1508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n", 1518c2ecf20Sopenharmony_ci val); 1528c2ecf20Sopenharmony_ci return -EINVAL; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci total_channels = tsc_wires + adc_channels; 1568c2ecf20Sopenharmony_ci if (total_channels > 8) { 1578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Number of i/p channels more than 8\n"); 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (total_channels == 0) { 1618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Need atleast one channel.\n"); 1628c2ecf20Sopenharmony_ci return -EINVAL; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (readouts * 2 + 2 + adc_channels > 16) { 1668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Too many step configurations requested\n"); 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Allocate memory for device */ 1718c2ecf20Sopenharmony_ci tscadc = devm_kzalloc(&pdev->dev, sizeof(*tscadc), GFP_KERNEL); 1728c2ecf20Sopenharmony_ci if (!tscadc) 1738c2ecf20Sopenharmony_ci return -ENOMEM; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci tscadc->dev = &pdev->dev; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci err = platform_get_irq(pdev, 0); 1788c2ecf20Sopenharmony_ci if (err < 0) { 1798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no irq ID is specified.\n"); 1808c2ecf20Sopenharmony_ci goto ret; 1818c2ecf20Sopenharmony_ci } else 1828c2ecf20Sopenharmony_ci tscadc->irq = err; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1858c2ecf20Sopenharmony_ci tscadc->tscadc_base = devm_ioremap_resource(&pdev->dev, res); 1868c2ecf20Sopenharmony_ci if (IS_ERR(tscadc->tscadc_base)) 1878c2ecf20Sopenharmony_ci return PTR_ERR(tscadc->tscadc_base); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci tscadc->tscadc_phys_base = res->start; 1908c2ecf20Sopenharmony_ci tscadc->regmap = devm_regmap_init_mmio(&pdev->dev, 1918c2ecf20Sopenharmony_ci tscadc->tscadc_base, &tscadc_regmap_config); 1928c2ecf20Sopenharmony_ci if (IS_ERR(tscadc->regmap)) { 1938c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "regmap init failed\n"); 1948c2ecf20Sopenharmony_ci err = PTR_ERR(tscadc->regmap); 1958c2ecf20Sopenharmony_ci goto ret; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci spin_lock_init(&tscadc->reg_lock); 1998c2ecf20Sopenharmony_ci init_waitqueue_head(&tscadc->reg_se_wait); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 2028c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * The TSC_ADC_Subsystem has 2 clock domains 2068c2ecf20Sopenharmony_ci * OCP_CLK and ADC_CLK. 2078c2ecf20Sopenharmony_ci * The ADC clock is expected to run at target of 3MHz, 2088c2ecf20Sopenharmony_ci * and expected to capture 12-bit data at a rate of 200 KSPS. 2098c2ecf20Sopenharmony_ci * The TSC_ADC_SS controller design assumes the OCP clock is 2108c2ecf20Sopenharmony_ci * at least 6x faster than the ADC clock. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); 2138c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 2148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get TSC fck\n"); 2158c2ecf20Sopenharmony_ci err = PTR_ERR(clk); 2168c2ecf20Sopenharmony_ci goto err_disable_clk; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci clock_rate = clk_get_rate(clk); 2198c2ecf20Sopenharmony_ci tscadc->clk_div = clock_rate / ADC_CLK; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ 2228c2ecf20Sopenharmony_ci tscadc->clk_div--; 2238c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Set the control register bits */ 2268c2ecf20Sopenharmony_ci ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; 2278c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CTRL, ctrl); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Set register bits for Idle Config Mode */ 2308c2ecf20Sopenharmony_ci if (tsc_wires > 0) { 2318c2ecf20Sopenharmony_ci tscadc->tsc_wires = tsc_wires; 2328c2ecf20Sopenharmony_ci if (tsc_wires == 5) 2338c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; 2348c2ecf20Sopenharmony_ci else 2358c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; 2368c2ecf20Sopenharmony_ci tscadc_idle_config(tscadc); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Enable the TSC module enable bit */ 2408c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_TSCSSENB; 2418c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CTRL, ctrl); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci tscadc->used_cells = 0; 2448c2ecf20Sopenharmony_ci tscadc->tsc_cell = -1; 2458c2ecf20Sopenharmony_ci tscadc->adc_cell = -1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* TSC Cell */ 2488c2ecf20Sopenharmony_ci if (tsc_wires > 0) { 2498c2ecf20Sopenharmony_ci tscadc->tsc_cell = tscadc->used_cells; 2508c2ecf20Sopenharmony_ci cell = &tscadc->cells[tscadc->used_cells++]; 2518c2ecf20Sopenharmony_ci cell->name = "TI-am335x-tsc"; 2528c2ecf20Sopenharmony_ci cell->of_compatible = "ti,am3359-tsc"; 2538c2ecf20Sopenharmony_ci cell->platform_data = &tscadc; 2548c2ecf20Sopenharmony_ci cell->pdata_size = sizeof(tscadc); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* ADC Cell */ 2588c2ecf20Sopenharmony_ci if (adc_channels > 0) { 2598c2ecf20Sopenharmony_ci tscadc->adc_cell = tscadc->used_cells; 2608c2ecf20Sopenharmony_ci cell = &tscadc->cells[tscadc->used_cells++]; 2618c2ecf20Sopenharmony_ci cell->name = "TI-am335x-adc"; 2628c2ecf20Sopenharmony_ci cell->of_compatible = "ti,am3359-adc"; 2638c2ecf20Sopenharmony_ci cell->platform_data = &tscadc; 2648c2ecf20Sopenharmony_ci cell->pdata_size = sizeof(tscadc); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, 2688c2ecf20Sopenharmony_ci tscadc->cells, tscadc->used_cells, NULL, 2698c2ecf20Sopenharmony_ci 0, NULL); 2708c2ecf20Sopenharmony_ci if (err < 0) 2718c2ecf20Sopenharmony_ci goto err_disable_clk; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, tscadc); 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cierr_disable_clk: 2778c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 2788c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 2798c2ecf20Sopenharmony_ciret: 2808c2ecf20Sopenharmony_ci return err; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int ti_tscadc_remove(struct platform_device *pdev) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, 0x00); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 2908c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci mfd_remove_devices(tscadc->dev); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci return device_may_wakeup(dev); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int __maybe_unused tscadc_suspend(struct device *dev) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_SE, 0x00); 3078c2ecf20Sopenharmony_ci if (device_for_each_child(dev, NULL, ti_tscadc_can_wakeup)) { 3088c2ecf20Sopenharmony_ci u32 ctrl; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci regmap_read(tscadc->regmap, REG_CTRL, &ctrl); 3118c2ecf20Sopenharmony_ci ctrl &= ~(CNTRLREG_POWERDOWN); 3128c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_TSCSSENB; 3138c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CTRL, ctrl); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int __maybe_unused tscadc_resume(struct device *dev) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); 3238c2ecf20Sopenharmony_ci u32 ctrl; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* context restore */ 3288c2ecf20Sopenharmony_ci ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; 3298c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CTRL, ctrl); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (tscadc->tsc_cell != -1) { 3328c2ecf20Sopenharmony_ci if (tscadc->tsc_wires == 5) 3338c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; 3348c2ecf20Sopenharmony_ci else 3358c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; 3368c2ecf20Sopenharmony_ci tscadc_idle_config(tscadc); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci ctrl |= CNTRLREG_TSCSSENB; 3398c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CTRL, ctrl); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tscadc_pm_ops, tscadc_suspend, tscadc_resume); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic const struct of_device_id ti_tscadc_dt_ids[] = { 3498c2ecf20Sopenharmony_ci { .compatible = "ti,am3359-tscadc", }, 3508c2ecf20Sopenharmony_ci { } 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic struct platform_driver ti_tscadc_driver = { 3558c2ecf20Sopenharmony_ci .driver = { 3568c2ecf20Sopenharmony_ci .name = "ti_am3359-tscadc", 3578c2ecf20Sopenharmony_ci .pm = &tscadc_pm_ops, 3588c2ecf20Sopenharmony_ci .of_match_table = ti_tscadc_dt_ids, 3598c2ecf20Sopenharmony_ci }, 3608c2ecf20Sopenharmony_ci .probe = ti_tscadc_probe, 3618c2ecf20Sopenharmony_ci .remove = ti_tscadc_remove, 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cimodule_platform_driver(ti_tscadc_driver); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver"); 3688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); 3698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 370