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

arizona-haptics.c (5283B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Arizona haptics driver
      4 *
      5 * Copyright 2012 Wolfson Microelectronics plc
      6 *
      7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/input.h>
     13#include <linux/slab.h>
     14
     15#include <sound/soc.h>
     16#include <sound/soc-dapm.h>
     17
     18#include <linux/mfd/arizona/core.h>
     19#include <linux/mfd/arizona/pdata.h>
     20#include <linux/mfd/arizona/registers.h>
     21
     22struct arizona_haptics {
     23	struct arizona *arizona;
     24	struct input_dev *input_dev;
     25	struct work_struct work;
     26
     27	struct mutex mutex;
     28	u8 intensity;
     29};
     30
     31static void arizona_haptics_work(struct work_struct *work)
     32{
     33	struct arizona_haptics *haptics = container_of(work,
     34						       struct arizona_haptics,
     35						       work);
     36	struct arizona *arizona = haptics->arizona;
     37	struct snd_soc_component *component =
     38		snd_soc_dapm_to_component(arizona->dapm);
     39	int ret;
     40
     41	if (!haptics->arizona->dapm) {
     42		dev_err(arizona->dev, "No DAPM context\n");
     43		return;
     44	}
     45
     46	if (haptics->intensity) {
     47		ret = regmap_update_bits(arizona->regmap,
     48					 ARIZONA_HAPTICS_PHASE_2_INTENSITY,
     49					 ARIZONA_PHASE2_INTENSITY_MASK,
     50					 haptics->intensity);
     51		if (ret != 0) {
     52			dev_err(arizona->dev, "Failed to set intensity: %d\n",
     53				ret);
     54			return;
     55		}
     56
     57		/* This enable sequence will be a noop if already enabled */
     58		ret = regmap_update_bits(arizona->regmap,
     59					 ARIZONA_HAPTICS_CONTROL_1,
     60					 ARIZONA_HAP_CTRL_MASK,
     61					 1 << ARIZONA_HAP_CTRL_SHIFT);
     62		if (ret != 0) {
     63			dev_err(arizona->dev, "Failed to start haptics: %d\n",
     64				ret);
     65			return;
     66		}
     67
     68		ret = snd_soc_component_enable_pin(component, "HAPTICS");
     69		if (ret != 0) {
     70			dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
     71				ret);
     72			return;
     73		}
     74
     75		ret = snd_soc_dapm_sync(arizona->dapm);
     76		if (ret != 0) {
     77			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
     78				ret);
     79			return;
     80		}
     81	} else {
     82		/* This disable sequence will be a noop if already enabled */
     83		ret = snd_soc_component_disable_pin(component, "HAPTICS");
     84		if (ret != 0) {
     85			dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
     86				ret);
     87			return;
     88		}
     89
     90		ret = snd_soc_dapm_sync(arizona->dapm);
     91		if (ret != 0) {
     92			dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
     93				ret);
     94			return;
     95		}
     96
     97		ret = regmap_update_bits(arizona->regmap,
     98					 ARIZONA_HAPTICS_CONTROL_1,
     99					 ARIZONA_HAP_CTRL_MASK, 0);
    100		if (ret != 0) {
    101			dev_err(arizona->dev, "Failed to stop haptics: %d\n",
    102				ret);
    103			return;
    104		}
    105	}
    106}
    107
    108static int arizona_haptics_play(struct input_dev *input, void *data,
    109				struct ff_effect *effect)
    110{
    111	struct arizona_haptics *haptics = input_get_drvdata(input);
    112	struct arizona *arizona = haptics->arizona;
    113
    114	if (!arizona->dapm) {
    115		dev_err(arizona->dev, "No DAPM context\n");
    116		return -EBUSY;
    117	}
    118
    119	if (effect->u.rumble.strong_magnitude) {
    120		/* Scale the magnitude into the range the device supports */
    121		if (arizona->pdata.hap_act) {
    122			haptics->intensity =
    123				effect->u.rumble.strong_magnitude >> 9;
    124			if (effect->direction < 0x8000)
    125				haptics->intensity += 0x7f;
    126		} else {
    127			haptics->intensity =
    128				effect->u.rumble.strong_magnitude >> 8;
    129		}
    130	} else {
    131		haptics->intensity = 0;
    132	}
    133
    134	schedule_work(&haptics->work);
    135
    136	return 0;
    137}
    138
    139static void arizona_haptics_close(struct input_dev *input)
    140{
    141	struct arizona_haptics *haptics = input_get_drvdata(input);
    142	struct snd_soc_component *component;
    143
    144	cancel_work_sync(&haptics->work);
    145
    146	if (haptics->arizona->dapm) {
    147		component = snd_soc_dapm_to_component(haptics->arizona->dapm);
    148		snd_soc_component_disable_pin(component, "HAPTICS");
    149	}
    150}
    151
    152static int arizona_haptics_probe(struct platform_device *pdev)
    153{
    154	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
    155	struct arizona_haptics *haptics;
    156	int ret;
    157
    158	haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
    159	if (!haptics)
    160		return -ENOMEM;
    161
    162	haptics->arizona = arizona;
    163
    164	ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1,
    165				 ARIZONA_HAP_ACT, arizona->pdata.hap_act);
    166	if (ret != 0) {
    167		dev_err(arizona->dev, "Failed to set haptics actuator: %d\n",
    168			ret);
    169		return ret;
    170	}
    171
    172	INIT_WORK(&haptics->work, arizona_haptics_work);
    173
    174	haptics->input_dev = devm_input_allocate_device(&pdev->dev);
    175	if (!haptics->input_dev) {
    176		dev_err(arizona->dev, "Failed to allocate input device\n");
    177		return -ENOMEM;
    178	}
    179
    180	input_set_drvdata(haptics->input_dev, haptics);
    181
    182	haptics->input_dev->name = "arizona:haptics";
    183	haptics->input_dev->close = arizona_haptics_close;
    184	__set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
    185
    186	ret = input_ff_create_memless(haptics->input_dev, NULL,
    187				      arizona_haptics_play);
    188	if (ret < 0) {
    189		dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
    190			ret);
    191		return ret;
    192	}
    193
    194	ret = input_register_device(haptics->input_dev);
    195	if (ret < 0) {
    196		dev_err(arizona->dev, "couldn't register input device: %d\n",
    197			ret);
    198		return ret;
    199	}
    200
    201	return 0;
    202}
    203
    204static struct platform_driver arizona_haptics_driver = {
    205	.probe		= arizona_haptics_probe,
    206	.driver		= {
    207		.name	= "arizona-haptics",
    208	},
    209};
    210module_platform_driver(arizona_haptics_driver);
    211
    212MODULE_ALIAS("platform:arizona-haptics");
    213MODULE_DESCRIPTION("Arizona haptics driver");
    214MODULE_LICENSE("GPL");
    215MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");