Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Freescale Vybrid vf610 DAC driver
0004  *
0005  * Copyright 2016 Toradex AG
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/err.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013 #include <linux/mod_devicetable.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/regulator/consumer.h>
0017 #include <linux/slab.h>
0018 
0019 #include <linux/iio/iio.h>
0020 #include <linux/iio/sysfs.h>
0021 
0022 #define VF610_DACx_STATCTRL     0x20
0023 
0024 #define VF610_DAC_DACEN         BIT(15)
0025 #define VF610_DAC_DACRFS        BIT(14)
0026 #define VF610_DAC_LPEN          BIT(11)
0027 
0028 #define VF610_DAC_DAT0(x)       ((x) & 0xFFF)
0029 
0030 enum vf610_conversion_mode_sel {
0031     VF610_DAC_CONV_HIGH_POWER,
0032     VF610_DAC_CONV_LOW_POWER,
0033 };
0034 
0035 struct vf610_dac {
0036     struct clk *clk;
0037     struct device *dev;
0038     enum vf610_conversion_mode_sel conv_mode;
0039     void __iomem *regs;
0040     struct mutex lock;
0041 };
0042 
0043 static void vf610_dac_init(struct vf610_dac *info)
0044 {
0045     int val;
0046 
0047     info->conv_mode = VF610_DAC_CONV_LOW_POWER;
0048     val = VF610_DAC_DACEN | VF610_DAC_DACRFS |
0049         VF610_DAC_LPEN;
0050     writel(val, info->regs + VF610_DACx_STATCTRL);
0051 }
0052 
0053 static void vf610_dac_exit(struct vf610_dac *info)
0054 {
0055     int val;
0056 
0057     val = readl(info->regs + VF610_DACx_STATCTRL);
0058     val &= ~VF610_DAC_DACEN;
0059     writel(val, info->regs + VF610_DACx_STATCTRL);
0060 }
0061 
0062 static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
0063                 const struct iio_chan_spec *chan,
0064                 unsigned int mode)
0065 {
0066     struct vf610_dac *info = iio_priv(indio_dev);
0067     int val;
0068 
0069     mutex_lock(&info->lock);
0070     info->conv_mode = mode;
0071     val = readl(info->regs + VF610_DACx_STATCTRL);
0072     if (mode)
0073         val |= VF610_DAC_LPEN;
0074     else
0075         val &= ~VF610_DAC_LPEN;
0076     writel(val, info->regs + VF610_DACx_STATCTRL);
0077     mutex_unlock(&info->lock);
0078 
0079     return 0;
0080 }
0081 
0082 static int vf610_get_conversion_mode(struct iio_dev *indio_dev,
0083                 const struct iio_chan_spec *chan)
0084 {
0085     struct vf610_dac *info = iio_priv(indio_dev);
0086 
0087     return info->conv_mode;
0088 }
0089 
0090 static const char * const vf610_conv_modes[] = { "high-power", "low-power" };
0091 
0092 static const struct iio_enum vf610_conversion_mode = {
0093     .items = vf610_conv_modes,
0094     .num_items = ARRAY_SIZE(vf610_conv_modes),
0095     .get = vf610_get_conversion_mode,
0096     .set = vf610_set_conversion_mode,
0097 };
0098 
0099 static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
0100     IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR,
0101         &vf610_conversion_mode),
0102     {},
0103 };
0104 
0105 #define VF610_DAC_CHAN(_chan_type) { \
0106     .type = (_chan_type), \
0107     .output = 1, \
0108     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0109     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
0110     .ext_info = vf610_ext_info, \
0111 }
0112 
0113 static const struct iio_chan_spec vf610_dac_iio_channels[] = {
0114     VF610_DAC_CHAN(IIO_VOLTAGE),
0115 };
0116 
0117 static int vf610_read_raw(struct iio_dev *indio_dev,
0118             struct iio_chan_spec const *chan,
0119             int *val, int *val2,
0120             long mask)
0121 {
0122     struct vf610_dac *info = iio_priv(indio_dev);
0123 
0124     switch (mask) {
0125     case IIO_CHAN_INFO_RAW:
0126         *val = VF610_DAC_DAT0(readl(info->regs));
0127         return IIO_VAL_INT;
0128     case IIO_CHAN_INFO_SCALE:
0129         /*
0130          * DACRFS is always 1 for valid reference and typical
0131          * reference voltage as per Vybrid datasheet is 3.3V
0132          * from section 9.1.2.1 of Vybrid datasheet
0133          */
0134         *val = 3300 /* mV */;
0135         *val2 = 12;
0136         return IIO_VAL_FRACTIONAL_LOG2;
0137 
0138     default:
0139         return -EINVAL;
0140     }
0141 }
0142 
0143 static int vf610_write_raw(struct iio_dev *indio_dev,
0144             struct iio_chan_spec const *chan,
0145             int val, int val2,
0146             long mask)
0147 {
0148     struct vf610_dac *info = iio_priv(indio_dev);
0149 
0150     switch (mask) {
0151     case IIO_CHAN_INFO_RAW:
0152         mutex_lock(&info->lock);
0153         writel(VF610_DAC_DAT0(val), info->regs);
0154         mutex_unlock(&info->lock);
0155         return 0;
0156 
0157     default:
0158         return -EINVAL;
0159     }
0160 }
0161 
0162 static const struct iio_info vf610_dac_iio_info = {
0163     .read_raw = &vf610_read_raw,
0164     .write_raw = &vf610_write_raw,
0165 };
0166 
0167 static const struct of_device_id vf610_dac_match[] = {
0168     { .compatible = "fsl,vf610-dac", },
0169     { /* sentinel */ }
0170 };
0171 MODULE_DEVICE_TABLE(of, vf610_dac_match);
0172 
0173 static int vf610_dac_probe(struct platform_device *pdev)
0174 {
0175     struct iio_dev *indio_dev;
0176     struct vf610_dac *info;
0177     int ret;
0178 
0179     indio_dev = devm_iio_device_alloc(&pdev->dev,
0180                     sizeof(struct vf610_dac));
0181     if (!indio_dev) {
0182         dev_err(&pdev->dev, "Failed allocating iio device\n");
0183         return -ENOMEM;
0184     }
0185 
0186     info = iio_priv(indio_dev);
0187     info->dev = &pdev->dev;
0188 
0189     info->regs = devm_platform_ioremap_resource(pdev, 0);
0190     if (IS_ERR(info->regs))
0191         return PTR_ERR(info->regs);
0192 
0193     info->clk = devm_clk_get(&pdev->dev, "dac");
0194     if (IS_ERR(info->clk)) {
0195         dev_err(&pdev->dev, "Failed getting clock, err = %ld\n",
0196             PTR_ERR(info->clk));
0197         return PTR_ERR(info->clk);
0198     }
0199 
0200     platform_set_drvdata(pdev, indio_dev);
0201 
0202     indio_dev->name = dev_name(&pdev->dev);
0203     indio_dev->info = &vf610_dac_iio_info;
0204     indio_dev->modes = INDIO_DIRECT_MODE;
0205     indio_dev->channels = vf610_dac_iio_channels;
0206     indio_dev->num_channels = ARRAY_SIZE(vf610_dac_iio_channels);
0207 
0208     mutex_init(&info->lock);
0209 
0210     ret = clk_prepare_enable(info->clk);
0211     if (ret) {
0212         dev_err(&pdev->dev,
0213             "Could not prepare or enable the clock\n");
0214         return ret;
0215     }
0216 
0217     vf610_dac_init(info);
0218 
0219     ret = iio_device_register(indio_dev);
0220     if (ret) {
0221         dev_err(&pdev->dev, "Couldn't register the device\n");
0222         goto error_iio_device_register;
0223     }
0224 
0225     return 0;
0226 
0227 error_iio_device_register:
0228     vf610_dac_exit(info);
0229     clk_disable_unprepare(info->clk);
0230 
0231     return ret;
0232 }
0233 
0234 static int vf610_dac_remove(struct platform_device *pdev)
0235 {
0236     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0237     struct vf610_dac *info = iio_priv(indio_dev);
0238 
0239     iio_device_unregister(indio_dev);
0240     vf610_dac_exit(info);
0241     clk_disable_unprepare(info->clk);
0242 
0243     return 0;
0244 }
0245 
0246 static int vf610_dac_suspend(struct device *dev)
0247 {
0248     struct iio_dev *indio_dev = dev_get_drvdata(dev);
0249     struct vf610_dac *info = iio_priv(indio_dev);
0250 
0251     vf610_dac_exit(info);
0252     clk_disable_unprepare(info->clk);
0253 
0254     return 0;
0255 }
0256 
0257 static int vf610_dac_resume(struct device *dev)
0258 {
0259     struct iio_dev *indio_dev = dev_get_drvdata(dev);
0260     struct vf610_dac *info = iio_priv(indio_dev);
0261     int ret;
0262 
0263     ret = clk_prepare_enable(info->clk);
0264     if (ret)
0265         return ret;
0266 
0267     vf610_dac_init(info);
0268 
0269     return 0;
0270 }
0271 
0272 static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
0273                 vf610_dac_resume);
0274 
0275 static struct platform_driver vf610_dac_driver = {
0276     .probe          = vf610_dac_probe,
0277     .remove         = vf610_dac_remove,
0278     .driver         = {
0279         .name   = "vf610-dac",
0280         .of_match_table = vf610_dac_match,
0281         .pm     = pm_sleep_ptr(&vf610_dac_pm_ops),
0282     },
0283 };
0284 module_platform_driver(vf610_dac_driver);
0285 
0286 MODULE_AUTHOR("Sanchayan Maity <sanchayan.maity@toradex.com>");
0287 MODULE_DESCRIPTION("Freescale VF610 DAC driver");
0288 MODULE_LICENSE("GPL v2");