cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vf610_dac.c (6516B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Freescale Vybrid vf610 DAC driver
      4 *
      5 * Copyright 2016 Toradex AG
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/err.h>
     10#include <linux/interrupt.h>
     11#include <linux/io.h>
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15#include <linux/regulator/consumer.h>
     16#include <linux/slab.h>
     17
     18#include <linux/iio/iio.h>
     19#include <linux/iio/sysfs.h>
     20
     21#define VF610_DACx_STATCTRL		0x20
     22
     23#define VF610_DAC_DACEN			BIT(15)
     24#define VF610_DAC_DACRFS		BIT(14)
     25#define VF610_DAC_LPEN			BIT(11)
     26
     27#define VF610_DAC_DAT0(x)		((x) & 0xFFF)
     28
     29enum vf610_conversion_mode_sel {
     30	VF610_DAC_CONV_HIGH_POWER,
     31	VF610_DAC_CONV_LOW_POWER,
     32};
     33
     34struct vf610_dac {
     35	struct clk *clk;
     36	struct device *dev;
     37	enum vf610_conversion_mode_sel conv_mode;
     38	void __iomem *regs;
     39	struct mutex lock;
     40};
     41
     42static void vf610_dac_init(struct vf610_dac *info)
     43{
     44	int val;
     45
     46	info->conv_mode = VF610_DAC_CONV_LOW_POWER;
     47	val = VF610_DAC_DACEN | VF610_DAC_DACRFS |
     48		VF610_DAC_LPEN;
     49	writel(val, info->regs + VF610_DACx_STATCTRL);
     50}
     51
     52static void vf610_dac_exit(struct vf610_dac *info)
     53{
     54	int val;
     55
     56	val = readl(info->regs + VF610_DACx_STATCTRL);
     57	val &= ~VF610_DAC_DACEN;
     58	writel(val, info->regs + VF610_DACx_STATCTRL);
     59}
     60
     61static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
     62				const struct iio_chan_spec *chan,
     63				unsigned int mode)
     64{
     65	struct vf610_dac *info = iio_priv(indio_dev);
     66	int val;
     67
     68	mutex_lock(&info->lock);
     69	info->conv_mode = mode;
     70	val = readl(info->regs + VF610_DACx_STATCTRL);
     71	if (mode)
     72		val |= VF610_DAC_LPEN;
     73	else
     74		val &= ~VF610_DAC_LPEN;
     75	writel(val, info->regs + VF610_DACx_STATCTRL);
     76	mutex_unlock(&info->lock);
     77
     78	return 0;
     79}
     80
     81static int vf610_get_conversion_mode(struct iio_dev *indio_dev,
     82				const struct iio_chan_spec *chan)
     83{
     84	struct vf610_dac *info = iio_priv(indio_dev);
     85
     86	return info->conv_mode;
     87}
     88
     89static const char * const vf610_conv_modes[] = { "high-power", "low-power" };
     90
     91static const struct iio_enum vf610_conversion_mode = {
     92	.items = vf610_conv_modes,
     93	.num_items = ARRAY_SIZE(vf610_conv_modes),
     94	.get = vf610_get_conversion_mode,
     95	.set = vf610_set_conversion_mode,
     96};
     97
     98static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
     99	IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR,
    100		&vf610_conversion_mode),
    101	{},
    102};
    103
    104#define VF610_DAC_CHAN(_chan_type) { \
    105	.type = (_chan_type), \
    106	.output = 1, \
    107	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
    108	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
    109	.ext_info = vf610_ext_info, \
    110}
    111
    112static const struct iio_chan_spec vf610_dac_iio_channels[] = {
    113	VF610_DAC_CHAN(IIO_VOLTAGE),
    114};
    115
    116static int vf610_read_raw(struct iio_dev *indio_dev,
    117			struct iio_chan_spec const *chan,
    118			int *val, int *val2,
    119			long mask)
    120{
    121	struct vf610_dac *info = iio_priv(indio_dev);
    122
    123	switch (mask) {
    124	case IIO_CHAN_INFO_RAW:
    125		*val = VF610_DAC_DAT0(readl(info->regs));
    126		return IIO_VAL_INT;
    127	case IIO_CHAN_INFO_SCALE:
    128		/*
    129		 * DACRFS is always 1 for valid reference and typical
    130		 * reference voltage as per Vybrid datasheet is 3.3V
    131		 * from section 9.1.2.1 of Vybrid datasheet
    132		 */
    133		*val = 3300 /* mV */;
    134		*val2 = 12;
    135		return IIO_VAL_FRACTIONAL_LOG2;
    136
    137	default:
    138		return -EINVAL;
    139	}
    140}
    141
    142static int vf610_write_raw(struct iio_dev *indio_dev,
    143			struct iio_chan_spec const *chan,
    144			int val, int val2,
    145			long mask)
    146{
    147	struct vf610_dac *info = iio_priv(indio_dev);
    148
    149	switch (mask) {
    150	case IIO_CHAN_INFO_RAW:
    151		mutex_lock(&info->lock);
    152		writel(VF610_DAC_DAT0(val), info->regs);
    153		mutex_unlock(&info->lock);
    154		return 0;
    155
    156	default:
    157		return -EINVAL;
    158	}
    159}
    160
    161static const struct iio_info vf610_dac_iio_info = {
    162	.read_raw = &vf610_read_raw,
    163	.write_raw = &vf610_write_raw,
    164};
    165
    166static const struct of_device_id vf610_dac_match[] = {
    167	{ .compatible = "fsl,vf610-dac", },
    168	{ /* sentinel */ }
    169};
    170MODULE_DEVICE_TABLE(of, vf610_dac_match);
    171
    172static int vf610_dac_probe(struct platform_device *pdev)
    173{
    174	struct iio_dev *indio_dev;
    175	struct vf610_dac *info;
    176	int ret;
    177
    178	indio_dev = devm_iio_device_alloc(&pdev->dev,
    179					sizeof(struct vf610_dac));
    180	if (!indio_dev) {
    181		dev_err(&pdev->dev, "Failed allocating iio device\n");
    182		return -ENOMEM;
    183	}
    184
    185	info = iio_priv(indio_dev);
    186	info->dev = &pdev->dev;
    187
    188	info->regs = devm_platform_ioremap_resource(pdev, 0);
    189	if (IS_ERR(info->regs))
    190		return PTR_ERR(info->regs);
    191
    192	info->clk = devm_clk_get(&pdev->dev, "dac");
    193	if (IS_ERR(info->clk)) {
    194		dev_err(&pdev->dev, "Failed getting clock, err = %ld\n",
    195			PTR_ERR(info->clk));
    196		return PTR_ERR(info->clk);
    197	}
    198
    199	platform_set_drvdata(pdev, indio_dev);
    200
    201	indio_dev->name = dev_name(&pdev->dev);
    202	indio_dev->info = &vf610_dac_iio_info;
    203	indio_dev->modes = INDIO_DIRECT_MODE;
    204	indio_dev->channels = vf610_dac_iio_channels;
    205	indio_dev->num_channels = ARRAY_SIZE(vf610_dac_iio_channels);
    206
    207	mutex_init(&info->lock);
    208
    209	ret = clk_prepare_enable(info->clk);
    210	if (ret) {
    211		dev_err(&pdev->dev,
    212			"Could not prepare or enable the clock\n");
    213		return ret;
    214	}
    215
    216	vf610_dac_init(info);
    217
    218	ret = iio_device_register(indio_dev);
    219	if (ret) {
    220		dev_err(&pdev->dev, "Couldn't register the device\n");
    221		goto error_iio_device_register;
    222	}
    223
    224	return 0;
    225
    226error_iio_device_register:
    227	vf610_dac_exit(info);
    228	clk_disable_unprepare(info->clk);
    229
    230	return ret;
    231}
    232
    233static int vf610_dac_remove(struct platform_device *pdev)
    234{
    235	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
    236	struct vf610_dac *info = iio_priv(indio_dev);
    237
    238	iio_device_unregister(indio_dev);
    239	vf610_dac_exit(info);
    240	clk_disable_unprepare(info->clk);
    241
    242	return 0;
    243}
    244
    245static int vf610_dac_suspend(struct device *dev)
    246{
    247	struct iio_dev *indio_dev = dev_get_drvdata(dev);
    248	struct vf610_dac *info = iio_priv(indio_dev);
    249
    250	vf610_dac_exit(info);
    251	clk_disable_unprepare(info->clk);
    252
    253	return 0;
    254}
    255
    256static int vf610_dac_resume(struct device *dev)
    257{
    258	struct iio_dev *indio_dev = dev_get_drvdata(dev);
    259	struct vf610_dac *info = iio_priv(indio_dev);
    260	int ret;
    261
    262	ret = clk_prepare_enable(info->clk);
    263	if (ret)
    264		return ret;
    265
    266	vf610_dac_init(info);
    267
    268	return 0;
    269}
    270
    271static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend,
    272				vf610_dac_resume);
    273
    274static struct platform_driver vf610_dac_driver = {
    275	.probe          = vf610_dac_probe,
    276	.remove         = vf610_dac_remove,
    277	.driver         = {
    278		.name   = "vf610-dac",
    279		.of_match_table = vf610_dac_match,
    280		.pm     = pm_sleep_ptr(&vf610_dac_pm_ops),
    281	},
    282};
    283module_platform_driver(vf610_dac_driver);
    284
    285MODULE_AUTHOR("Sanchayan Maity <sanchayan.maity@toradex.com>");
    286MODULE_DESCRIPTION("Freescale VF610 DAC driver");
    287MODULE_LICENSE("GPL v2");