2019-05-29 07:17:58 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2011-08-01 23:41:44 -07:00
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*/
# include <linux/errno.h>
# include <linux/input.h>
2017-04-04 16:25:42 -07:00
# include <linux/kernel.h>
# include <linux/module.h>
2017-04-04 16:27:36 -07:00
# include <linux/of.h>
2017-04-04 16:25:57 -07:00
# include <linux/of_device.h>
2017-04-04 16:25:42 -07:00
# include <linux/platform_device.h>
2013-12-15 03:46:21 -08:00
# include <linux/regmap.h>
2017-04-04 16:25:42 -07:00
# include <linux/slab.h>
2011-08-01 23:41:44 -07:00
# define VIB_MAX_LEVEL_mV (3100)
# define VIB_MIN_LEVEL_mV (1200)
# define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
# define MAX_FF_SPEED 0xff
2017-04-04 16:25:57 -07:00
struct pm8xxx_regs {
2017-04-04 16:27:36 -07:00
unsigned int enable_addr ;
unsigned int enable_mask ;
2017-04-04 16:25:57 -07:00
unsigned int drv_addr ;
unsigned int drv_mask ;
unsigned int drv_shift ;
unsigned int drv_en_manual_mask ;
} ;
static const struct pm8xxx_regs pm8058_regs = {
. drv_addr = 0x4A ,
. drv_mask = 0xf8 ,
. drv_shift = 3 ,
. drv_en_manual_mask = 0xfc ,
} ;
2017-04-04 16:29:59 -07:00
static struct pm8xxx_regs pm8916_regs = {
. enable_addr = 0xc046 ,
. enable_mask = BIT ( 7 ) ,
. drv_addr = 0xc041 ,
. drv_mask = 0x1F ,
. drv_shift = 0 ,
. drv_en_manual_mask = 0 ,
} ;
2011-08-01 23:41:44 -07:00
/**
* struct pm8xxx_vib - structure to hold vibrator data
* @ vib_input_dev : input device supporting force feedback
* @ work : work structure to set the vibration parameters
2013-12-15 03:46:21 -08:00
* @ regmap : regmap for register read / write
2017-04-04 16:25:57 -07:00
* @ regs : registers ' info
2011-08-01 23:41:44 -07:00
* @ speed : speed of vibration set from userland
* @ active : state of vibrator
* @ level : level of vibration to set in the chip
2017-04-04 16:25:57 -07:00
* @ reg_vib_drv : regs - > drv_addr register value
2011-08-01 23:41:44 -07:00
*/
struct pm8xxx_vib {
struct input_dev * vib_input_dev ;
struct work_struct work ;
2013-12-15 03:46:21 -08:00
struct regmap * regmap ;
2017-04-04 16:25:57 -07:00
const struct pm8xxx_regs * regs ;
2011-08-01 23:41:44 -07:00
int speed ;
int level ;
bool active ;
u8 reg_vib_drv ;
} ;
/**
* pm8xxx_vib_set - handler to start / stop vibration
* @ vib : pointer to vibrator structure
* @ on : state to set
*/
static int pm8xxx_vib_set ( struct pm8xxx_vib * vib , bool on )
{
int rc ;
2013-12-15 03:46:21 -08:00
unsigned int val = vib - > reg_vib_drv ;
2017-04-04 16:25:57 -07:00
const struct pm8xxx_regs * regs = vib - > regs ;
2011-08-01 23:41:44 -07:00
if ( on )
2017-04-04 16:25:57 -07:00
val | = ( vib - > level < < regs - > drv_shift ) & regs - > drv_mask ;
2011-08-01 23:41:44 -07:00
else
2017-04-04 16:25:57 -07:00
val & = ~ regs - > drv_mask ;
2011-08-01 23:41:44 -07:00
2017-04-04 16:25:57 -07:00
rc = regmap_write ( vib - > regmap , regs - > drv_addr , val ) ;
2011-08-01 23:41:44 -07:00
if ( rc < 0 )
return rc ;
vib - > reg_vib_drv = val ;
2017-04-04 16:27:36 -07:00
if ( regs - > enable_mask )
rc = regmap_update_bits ( vib - > regmap , regs - > enable_addr ,
on ? regs - > enable_mask : 0 , val ) ;
return rc ;
2011-08-01 23:41:44 -07:00
}
/**
* pm8xxx_work_handler - worker to set vibration level
* @ work : pointer to work_struct
*/
static void pm8xxx_work_handler ( struct work_struct * work )
{
struct pm8xxx_vib * vib = container_of ( work , struct pm8xxx_vib , work ) ;
2017-04-04 16:25:57 -07:00
const struct pm8xxx_regs * regs = vib - > regs ;
2011-08-01 23:41:44 -07:00
int rc ;
2013-12-15 03:46:21 -08:00
unsigned int val ;
2011-08-01 23:41:44 -07:00
2017-04-04 16:25:57 -07:00
rc = regmap_read ( vib - > regmap , regs - > drv_addr , & val ) ;
2011-08-01 23:41:44 -07:00
if ( rc < 0 )
return ;
/*
* pmic vibrator supports voltage ranges from 1.2 to 3.1 V , so
* scale the level to fit into these ranges .
*/
if ( vib - > speed ) {
vib - > active = true ;
vib - > level = ( ( VIB_MAX_LEVELS * vib - > speed ) / MAX_FF_SPEED ) +
VIB_MIN_LEVEL_mV ;
vib - > level / = 100 ;
} else {
vib - > active = false ;
vib - > level = VIB_MIN_LEVEL_mV / 100 ;
}
pm8xxx_vib_set ( vib , vib - > active ) ;
}
/**
* pm8xxx_vib_close - callback of input close callback
* @ dev : input device pointer
*
* Turns off the vibrator .
*/
static void pm8xxx_vib_close ( struct input_dev * dev )
{
struct pm8xxx_vib * vib = input_get_drvdata ( dev ) ;
cancel_work_sync ( & vib - > work ) ;
if ( vib - > active )
pm8xxx_vib_set ( vib , false ) ;
}
/**
* pm8xxx_vib_play_effect - function to handle vib effects .
* @ dev : input device pointer
* @ data : data of effect
* @ effect : effect to play
*
* Currently this driver supports only rumble effects .
*/
static int pm8xxx_vib_play_effect ( struct input_dev * dev , void * data ,
struct ff_effect * effect )
{
struct pm8xxx_vib * vib = input_get_drvdata ( dev ) ;
vib - > speed = effect - > u . rumble . strong_magnitude > > 8 ;
if ( ! vib - > speed )
vib - > speed = effect - > u . rumble . weak_magnitude > > 9 ;
schedule_work ( & vib - > work ) ;
return 0 ;
}
2012-11-23 21:38:25 -08:00
static int pm8xxx_vib_probe ( struct platform_device * pdev )
2011-08-01 23:41:44 -07:00
{
struct pm8xxx_vib * vib ;
struct input_dev * input_dev ;
int error ;
2013-12-15 03:46:21 -08:00
unsigned int val ;
2017-04-04 16:25:57 -07:00
const struct pm8xxx_regs * regs ;
2011-08-01 23:41:44 -07:00
2013-12-15 03:43:06 -08:00
vib = devm_kzalloc ( & pdev - > dev , sizeof ( * vib ) , GFP_KERNEL ) ;
if ( ! vib )
return - ENOMEM ;
2013-12-15 03:46:21 -08:00
vib - > regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
if ( ! vib - > regmap )
return - ENODEV ;
2013-12-15 03:43:06 -08:00
input_dev = devm_input_allocate_device ( & pdev - > dev ) ;
if ( ! input_dev )
return - ENOMEM ;
2011-08-01 23:41:44 -07:00
INIT_WORK ( & vib - > work , pm8xxx_work_handler ) ;
vib - > vib_input_dev = input_dev ;
2017-04-04 16:25:57 -07:00
regs = of_device_get_match_data ( & pdev - > dev ) ;
2011-08-01 23:41:44 -07:00
/* operate in manual mode */
2017-04-04 16:25:57 -07:00
error = regmap_read ( vib - > regmap , regs - > drv_addr , & val ) ;
2011-08-01 23:41:44 -07:00
if ( error < 0 )
2013-12-15 03:43:06 -08:00
return error ;
2017-04-04 16:25:57 -07:00
val & = regs - > drv_en_manual_mask ;
error = regmap_write ( vib - > regmap , regs - > drv_addr , val ) ;
2011-08-01 23:41:44 -07:00
if ( error < 0 )
2013-12-15 03:43:06 -08:00
return error ;
2011-08-01 23:41:44 -07:00
2017-04-04 16:25:57 -07:00
vib - > regs = regs ;
2011-08-01 23:41:44 -07:00
vib - > reg_vib_drv = val ;
input_dev - > name = " pm8xxx_vib_ffmemless " ;
input_dev - > id . version = 1 ;
input_dev - > close = pm8xxx_vib_close ;
input_set_drvdata ( input_dev , vib ) ;
input_set_capability ( vib - > vib_input_dev , EV_FF , FF_RUMBLE ) ;
error = input_ff_create_memless ( input_dev , NULL ,
pm8xxx_vib_play_effect ) ;
if ( error ) {
dev_err ( & pdev - > dev ,
" couldn't register vibrator as FF device \n " ) ;
2013-12-15 03:43:06 -08:00
return error ;
2011-08-01 23:41:44 -07:00
}
error = input_register_device ( input_dev ) ;
if ( error ) {
dev_err ( & pdev - > dev , " couldn't register input device \n " ) ;
2013-12-15 03:43:06 -08:00
return error ;
2011-08-01 23:41:44 -07:00
}
platform_set_drvdata ( pdev , vib ) ;
return 0 ;
}
2014-11-02 00:02:46 -07:00
static int __maybe_unused pm8xxx_vib_suspend ( struct device * dev )
2011-08-01 23:41:44 -07:00
{
struct pm8xxx_vib * vib = dev_get_drvdata ( dev ) ;
/* Turn off the vibrator */
pm8xxx_vib_set ( vib , false ) ;
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( pm8xxx_vib_pm_ops , pm8xxx_vib_suspend , NULL ) ;
2014-03-29 12:44:14 -07:00
static const struct of_device_id pm8xxx_vib_id_table [ ] = {
2017-04-04 16:25:57 -07:00
{ . compatible = " qcom,pm8058-vib " , . data = & pm8058_regs } ,
{ . compatible = " qcom,pm8921-vib " , . data = & pm8058_regs } ,
2017-04-04 16:29:59 -07:00
{ . compatible = " qcom,pm8916-vib " , . data = & pm8916_regs } ,
2014-03-29 12:44:14 -07:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , pm8xxx_vib_id_table ) ;
2011-08-01 23:41:44 -07:00
static struct platform_driver pm8xxx_vib_driver = {
. probe = pm8xxx_vib_probe ,
. driver = {
. name = " pm8xxx-vib " ,
. pm = & pm8xxx_vib_pm_ops ,
2014-03-29 12:44:14 -07:00
. of_match_table = pm8xxx_vib_id_table ,
2011-08-01 23:41:44 -07:00
} ,
} ;
2011-11-29 11:08:40 -08:00
module_platform_driver ( pm8xxx_vib_driver ) ;
2011-08-01 23:41:44 -07:00
MODULE_ALIAS ( " platform:pm8xxx_vib " ) ;
MODULE_DESCRIPTION ( " PMIC8xxx vibrator driver based on ff-memless framework " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Amy Maloche <amaloche@codeaurora.org> " ) ;