1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/interrupt.h> 8 #include <linux/irqchip/chained_irq.h> 9 #include <linux/irqdesc.h> 10 #include <linux/irqdomain.h> 11 #include <linux/irq.h> 12 #include <linux/mfd/imx25-tsadc.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/of_platform.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 19 static const struct regmap_config mx25_tsadc_regmap_config = { 20 .max_register = 8, 21 .reg_bits = 32, 22 .val_bits = 32, 23 .reg_stride = 4, 24 }; 25 26 static void mx25_tsadc_irq_handler(struct irq_desc *desc) 27 { 28 struct mx25_tsadc *tsadc = irq_desc_get_handler_data(desc); 29 struct irq_chip *chip = irq_desc_get_chip(desc); 30 u32 status; 31 32 chained_irq_enter(chip, desc); 33 34 regmap_read(tsadc->regs, MX25_TSC_TGSR, &status); 35 36 if (status & MX25_TGSR_GCQ_INT) 37 generic_handle_domain_irq(tsadc->domain, 1); 38 39 if (status & MX25_TGSR_TCQ_INT) 40 generic_handle_domain_irq(tsadc->domain, 0); 41 42 chained_irq_exit(chip, desc); 43 } 44 45 static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq, 46 irq_hw_number_t hwirq) 47 { 48 struct mx25_tsadc *tsadc = d->host_data; 49 50 irq_set_chip_data(irq, tsadc); 51 irq_set_chip_and_handler(irq, &dummy_irq_chip, 52 handle_level_irq); 53 irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE); 54 55 return 0; 56 } 57 58 static const struct irq_domain_ops mx25_tsadc_domain_ops = { 59 .map = mx25_tsadc_domain_map, 60 .xlate = irq_domain_xlate_onecell, 61 }; 62 63 static int mx25_tsadc_setup_irq(struct platform_device *pdev, 64 struct mx25_tsadc *tsadc) 65 { 66 struct device *dev = &pdev->dev; 67 int irq; 68 69 irq = platform_get_irq(pdev, 0); 70 if (irq < 0) 71 return irq; 72 73 tsadc->domain = irq_domain_create_simple(dev_fwnode(dev), 2, 0, &mx25_tsadc_domain_ops, 74 tsadc); 75 if (!tsadc->domain) { 76 dev_err(dev, "Failed to add irq domain\n"); 77 return -ENOMEM; 78 } 79 80 irq_set_chained_handler_and_data(irq, mx25_tsadc_irq_handler, tsadc); 81 82 return 0; 83 } 84 85 static int mx25_tsadc_unset_irq(struct platform_device *pdev) 86 { 87 struct mx25_tsadc *tsadc = platform_get_drvdata(pdev); 88 int irq = platform_get_irq(pdev, 0); 89 90 if (irq >= 0) { 91 irq_set_chained_handler_and_data(irq, NULL, NULL); 92 irq_domain_remove(tsadc->domain); 93 } 94 95 return 0; 96 } 97 98 static void mx25_tsadc_setup_clk(struct platform_device *pdev, 99 struct mx25_tsadc *tsadc) 100 { 101 unsigned clk_div; 102 103 /* 104 * According to the datasheet the ADC clock should never 105 * exceed 1,75 MHz. Base clock is the IPG and the ADC unit uses 106 * a funny clock divider. To keep the ADC conversion time constant 107 * adapt the ADC internal clock divider to the IPG clock rate. 108 */ 109 110 dev_dbg(&pdev->dev, "Found master clock at %lu Hz\n", 111 clk_get_rate(tsadc->clk)); 112 113 clk_div = DIV_ROUND_UP(clk_get_rate(tsadc->clk), 1750000); 114 dev_dbg(&pdev->dev, "Setting up ADC clock divider to %u\n", clk_div); 115 116 /* adc clock = IPG clock / (2 * div + 2) */ 117 clk_div -= 2; 118 clk_div /= 2; 119 120 /* 121 * the ADC clock divider changes its behaviour when values below 4 122 * are used: it is fixed to "/ 10" in this case 123 */ 124 clk_div = max_t(unsigned, 4, clk_div); 125 126 dev_dbg(&pdev->dev, "Resulting ADC conversion clock at %lu Hz\n", 127 clk_get_rate(tsadc->clk) / (2 * clk_div + 2)); 128 129 regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, 130 MX25_TGCR_ADCCLKCFG(0x1f), 131 MX25_TGCR_ADCCLKCFG(clk_div)); 132 } 133 134 static int mx25_tsadc_probe(struct platform_device *pdev) 135 { 136 struct device *dev = &pdev->dev; 137 struct mx25_tsadc *tsadc; 138 int ret; 139 void __iomem *iomem; 140 141 tsadc = devm_kzalloc(dev, sizeof(*tsadc), GFP_KERNEL); 142 if (!tsadc) 143 return -ENOMEM; 144 145 iomem = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 146 if (IS_ERR(iomem)) 147 return PTR_ERR(iomem); 148 149 tsadc->regs = devm_regmap_init_mmio(dev, iomem, 150 &mx25_tsadc_regmap_config); 151 if (IS_ERR(tsadc->regs)) { 152 dev_err(dev, "Failed to initialize regmap\n"); 153 return PTR_ERR(tsadc->regs); 154 } 155 156 tsadc->clk = devm_clk_get(dev, "ipg"); 157 if (IS_ERR(tsadc->clk)) { 158 dev_err(dev, "Failed to get ipg clock\n"); 159 return PTR_ERR(tsadc->clk); 160 } 161 162 /* setup clock according to the datasheet */ 163 mx25_tsadc_setup_clk(pdev, tsadc); 164 165 /* Enable clock and reset the component */ 166 regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_CLK_EN, 167 MX25_TGCR_CLK_EN); 168 regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_TSC_RST, 169 MX25_TGCR_TSC_RST); 170 171 /* Setup powersaving mode, but enable internal reference voltage */ 172 regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_POWERMODE_MASK, 173 MX25_TGCR_POWERMODE_SAVE); 174 regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_INTREFEN, 175 MX25_TGCR_INTREFEN); 176 177 ret = mx25_tsadc_setup_irq(pdev, tsadc); 178 if (ret) 179 return ret; 180 181 platform_set_drvdata(pdev, tsadc); 182 183 ret = devm_of_platform_populate(dev); 184 if (ret) 185 goto err_irq; 186 187 return 0; 188 189 err_irq: 190 mx25_tsadc_unset_irq(pdev); 191 192 return ret; 193 } 194 195 static void mx25_tsadc_remove(struct platform_device *pdev) 196 { 197 mx25_tsadc_unset_irq(pdev); 198 } 199 200 static const struct of_device_id mx25_tsadc_ids[] = { 201 { .compatible = "fsl,imx25-tsadc" }, 202 { /* Sentinel */ } 203 }; 204 MODULE_DEVICE_TABLE(of, mx25_tsadc_ids); 205 206 static struct platform_driver mx25_tsadc_driver = { 207 .driver = { 208 .name = "mx25-tsadc", 209 .of_match_table = mx25_tsadc_ids, 210 }, 211 .probe = mx25_tsadc_probe, 212 .remove = mx25_tsadc_remove, 213 }; 214 module_platform_driver(mx25_tsadc_driver); 215 216 MODULE_DESCRIPTION("MFD for ADC/TSC for Freescale mx25"); 217 MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); 218 MODULE_LICENSE("GPL v2"); 219 MODULE_ALIAS("platform:mx25-tsadc"); 220