2018-02-01 21:22:20 +03:00
// SPDX-License-Identifier: GPL-2.0
// Melfas MMS114/MMS152 touchscreen device driver
//
// Copyright (c) 2012 Samsung Electronics Co., Ltd.
// Author: Joonyoung Shim <jy0922.shim@samsung.com>
2012-07-13 11:25:45 +04:00
# include <linux/module.h>
# include <linux/delay.h>
2012-10-11 12:03:50 +04:00
# include <linux/of.h>
2018-01-23 23:02:39 +03:00
# include <linux/of_device.h>
2012-07-13 11:25:45 +04:00
# include <linux/i2c.h>
# include <linux/input/mt.h>
2018-01-23 04:45:09 +03:00
# include <linux/input/touchscreen.h>
2012-07-13 11:25:45 +04:00
# include <linux/interrupt.h>
# include <linux/regulator/consumer.h>
# include <linux/slab.h>
/* Write only registers */
# define MMS114_MODE_CONTROL 0x01
# define MMS114_OPERATION_MODE_MASK 0xE
2018-01-29 22:44:44 +03:00
# define MMS114_ACTIVE BIT(1)
2012-07-13 11:25:45 +04:00
# define MMS114_XY_RESOLUTION_H 0x02
# define MMS114_X_RESOLUTION 0x03
# define MMS114_Y_RESOLUTION 0x04
# define MMS114_CONTACT_THRESHOLD 0x05
# define MMS114_MOVING_THRESHOLD 0x06
/* Read only registers */
# define MMS114_PACKET_SIZE 0x0F
2018-01-29 22:46:02 +03:00
# define MMS114_INFORMATION 0x10
2012-07-13 11:25:45 +04:00
# define MMS114_TSP_REV 0xF0
2018-01-23 23:02:39 +03:00
# define MMS152_FW_REV 0xE1
# define MMS152_COMPAT_GROUP 0xF2
2012-07-13 11:25:45 +04:00
/* Minimum delay time is 50us between stop and start signal of i2c */
# define MMS114_I2C_DELAY 50
/* 200ms needs after power on */
# define MMS114_POWERON_DELAY 200
/* Touchscreen absolute values */
# define MMS114_MAX_AREA 0xff
# define MMS114_MAX_TOUCH 10
# define MMS114_PACKET_NUM 8
/* Touch type */
# define MMS114_TYPE_NONE 0
# define MMS114_TYPE_TOUCHSCREEN 1
# define MMS114_TYPE_TOUCHKEY 2
2018-01-23 23:02:39 +03:00
enum mms_type {
TYPE_MMS114 = 114 ,
TYPE_MMS152 = 152 ,
} ;
2012-07-13 11:25:45 +04:00
struct mms114_data {
struct i2c_client * client ;
struct input_dev * input_dev ;
struct regulator * core_reg ;
struct regulator * io_reg ;
2018-01-23 04:45:09 +03:00
struct touchscreen_properties props ;
2018-01-23 23:02:39 +03:00
enum mms_type type ;
2018-01-23 04:45:09 +03:00
unsigned int contact_threshold ;
unsigned int moving_threshold ;
2012-07-13 11:25:45 +04:00
/* Use cache data for mode control register(write only) */
u8 cache_mode_control ;
} ;
struct mms114_touch {
u8 id : 4 , reserved_bit4 : 1 , type : 2 , pressed : 1 ;
u8 x_hi : 4 , y_hi : 4 ;
u8 x_lo ;
u8 y_lo ;
u8 width ;
u8 strength ;
u8 reserved [ 2 ] ;
} __packed ;
static int __mms114_read_reg ( struct mms114_data * data , unsigned int reg ,
unsigned int len , u8 * val )
{
struct i2c_client * client = data - > client ;
struct i2c_msg xfer [ 2 ] ;
u8 buf = reg & 0xff ;
int error ;
if ( reg < = MMS114_MODE_CONTROL & & reg + len > MMS114_MODE_CONTROL )
BUG ( ) ;
/* Write register: use repeated start */
xfer [ 0 ] . addr = client - > addr ;
xfer [ 0 ] . flags = I2C_M_TEN | I2C_M_NOSTART ;
xfer [ 0 ] . len = 1 ;
xfer [ 0 ] . buf = & buf ;
/* Read data */
xfer [ 1 ] . addr = client - > addr ;
xfer [ 1 ] . flags = I2C_M_RD ;
xfer [ 1 ] . len = len ;
xfer [ 1 ] . buf = val ;
error = i2c_transfer ( client - > adapter , xfer , 2 ) ;
if ( error ! = 2 ) {
dev_err ( & client - > dev ,
" %s: i2c transfer failed (%d) \n " , __func__ , error ) ;
return error < 0 ? error : - EIO ;
}
udelay ( MMS114_I2C_DELAY ) ;
return 0 ;
}
static int mms114_read_reg ( struct mms114_data * data , unsigned int reg )
{
u8 val ;
int error ;
if ( reg = = MMS114_MODE_CONTROL )
return data - > cache_mode_control ;
error = __mms114_read_reg ( data , reg , 1 , & val ) ;
return error < 0 ? error : val ;
}
static int mms114_write_reg ( struct mms114_data * data , unsigned int reg ,
unsigned int val )
{
struct i2c_client * client = data - > client ;
u8 buf [ 2 ] ;
int error ;
buf [ 0 ] = reg & 0xff ;
buf [ 1 ] = val & 0xff ;
error = i2c_master_send ( client , buf , 2 ) ;
if ( error ! = 2 ) {
dev_err ( & client - > dev ,
" %s: i2c send failed (%d) \n " , __func__ , error ) ;
return error < 0 ? error : - EIO ;
}
udelay ( MMS114_I2C_DELAY ) ;
if ( reg = = MMS114_MODE_CONTROL )
data - > cache_mode_control = val ;
return 0 ;
}
static void mms114_process_mt ( struct mms114_data * data , struct mms114_touch * touch )
{
struct i2c_client * client = data - > client ;
struct input_dev * input_dev = data - > input_dev ;
unsigned int id ;
unsigned int x ;
unsigned int y ;
if ( touch - > id > MMS114_MAX_TOUCH ) {
dev_err ( & client - > dev , " Wrong touch id (%d) \n " , touch - > id ) ;
return ;
}
if ( touch - > type ! = MMS114_TYPE_TOUCHSCREEN ) {
dev_err ( & client - > dev , " Wrong touch type (%d) \n " , touch - > type ) ;
return ;
}
id = touch - > id - 1 ;
x = touch - > x_lo | touch - > x_hi < < 8 ;
y = touch - > y_lo | touch - > y_hi < < 8 ;
dev_dbg ( & client - > dev ,
" id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d \n " ,
id , touch - > type , touch - > pressed ,
x , y , touch - > width , touch - > strength ) ;
input_mt_slot ( input_dev , id ) ;
input_mt_report_slot_state ( input_dev , MT_TOOL_FINGER , touch - > pressed ) ;
if ( touch - > pressed ) {
2018-01-23 04:45:09 +03:00
touchscreen_report_pos ( input_dev , & data - > props , x , y , true ) ;
2012-07-13 11:25:45 +04:00
input_report_abs ( input_dev , ABS_MT_TOUCH_MAJOR , touch - > width ) ;
input_report_abs ( input_dev , ABS_MT_PRESSURE , touch - > strength ) ;
}
}
static irqreturn_t mms114_interrupt ( int irq , void * dev_id )
{
struct mms114_data * data = dev_id ;
struct input_dev * input_dev = data - > input_dev ;
struct mms114_touch touch [ MMS114_MAX_TOUCH ] ;
int packet_size ;
int touch_size ;
int index ;
int error ;
mutex_lock ( & input_dev - > mutex ) ;
if ( ! input_dev - > users ) {
mutex_unlock ( & input_dev - > mutex ) ;
goto out ;
}
mutex_unlock ( & input_dev - > mutex ) ;
packet_size = mms114_read_reg ( data , MMS114_PACKET_SIZE ) ;
if ( packet_size < = 0 )
goto out ;
touch_size = packet_size / MMS114_PACKET_NUM ;
2018-01-29 22:46:02 +03:00
error = __mms114_read_reg ( data , MMS114_INFORMATION , packet_size ,
2012-07-13 11:25:45 +04:00
( u8 * ) touch ) ;
if ( error < 0 )
goto out ;
for ( index = 0 ; index < touch_size ; index + + )
mms114_process_mt ( data , touch + index ) ;
input_mt_report_pointer_emulation ( data - > input_dev , true ) ;
input_sync ( data - > input_dev ) ;
out :
return IRQ_HANDLED ;
}
static int mms114_set_active ( struct mms114_data * data , bool active )
{
int val ;
val = mms114_read_reg ( data , MMS114_MODE_CONTROL ) ;
if ( val < 0 )
return val ;
val & = ~ MMS114_OPERATION_MODE_MASK ;
/* If active is false, sleep mode */
if ( active )
val | = MMS114_ACTIVE ;
return mms114_write_reg ( data , MMS114_MODE_CONTROL , val ) ;
}
static int mms114_get_version ( struct mms114_data * data )
{
struct device * dev = & data - > client - > dev ;
u8 buf [ 6 ] ;
2018-01-23 23:02:39 +03:00
int group ;
2012-07-13 11:25:45 +04:00
int error ;
2018-01-23 23:02:39 +03:00
switch ( data - > type ) {
case TYPE_MMS152 :
error = __mms114_read_reg ( data , MMS152_FW_REV , 3 , buf ) ;
if ( error )
return error ;
group = i2c_smbus_read_byte_data ( data - > client ,
MMS152_COMPAT_GROUP ) ;
if ( group < 0 )
return group ;
dev_info ( dev , " TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c \n " ,
buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , group ) ;
break ;
case TYPE_MMS114 :
error = __mms114_read_reg ( data , MMS114_TSP_REV , 6 , buf ) ;
if ( error )
return error ;
2012-07-13 11:25:45 +04:00
2018-01-23 23:02:39 +03:00
dev_info ( dev , " TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x \n " ,
buf [ 0 ] , buf [ 1 ] , buf [ 3 ] ) ;
break ;
}
2012-07-13 11:25:45 +04:00
return 0 ;
}
static int mms114_setup_regs ( struct mms114_data * data )
{
2018-01-23 04:45:09 +03:00
const struct touchscreen_properties * props = & data - > props ;
2012-07-13 11:25:45 +04:00
int val ;
int error ;
error = mms114_get_version ( data ) ;
if ( error < 0 )
return error ;
2018-01-23 23:02:39 +03:00
/* MMS152 has no configuration or power on registers */
if ( data - > type = = TYPE_MMS152 )
return 0 ;
2012-07-13 11:25:45 +04:00
error = mms114_set_active ( data , true ) ;
if ( error < 0 )
return error ;
2018-01-23 04:45:09 +03:00
val = ( props - > max_x > > 8 ) & 0xf ;
val | = ( ( props - > max_y > > 8 ) & 0xf ) < < 4 ;
2012-07-13 11:25:45 +04:00
error = mms114_write_reg ( data , MMS114_XY_RESOLUTION_H , val ) ;
if ( error < 0 )
return error ;
2018-01-23 04:45:09 +03:00
val = props - > max_x & 0xff ;
2012-07-13 11:25:45 +04:00
error = mms114_write_reg ( data , MMS114_X_RESOLUTION , val ) ;
if ( error < 0 )
return error ;
2018-01-23 04:45:09 +03:00
val = props - > max_x & 0xff ;
2012-07-13 11:25:45 +04:00
error = mms114_write_reg ( data , MMS114_Y_RESOLUTION , val ) ;
if ( error < 0 )
return error ;
2018-01-23 04:45:09 +03:00
if ( data - > contact_threshold ) {
2012-07-13 11:25:45 +04:00
error = mms114_write_reg ( data , MMS114_CONTACT_THRESHOLD ,
2018-01-23 04:45:09 +03:00
data - > contact_threshold ) ;
2012-07-13 11:25:45 +04:00
if ( error < 0 )
return error ;
}
2018-01-23 04:45:09 +03:00
if ( data - > moving_threshold ) {
2012-07-13 11:25:45 +04:00
error = mms114_write_reg ( data , MMS114_MOVING_THRESHOLD ,
2018-01-23 04:45:09 +03:00
data - > moving_threshold ) ;
2012-07-13 11:25:45 +04:00
if ( error < 0 )
return error ;
}
return 0 ;
}
static int mms114_start ( struct mms114_data * data )
{
struct i2c_client * client = data - > client ;
int error ;
2013-03-04 08:21:30 +04:00
error = regulator_enable ( data - > core_reg ) ;
if ( error ) {
dev_err ( & client - > dev , " Failed to enable avdd: %d \n " , error ) ;
return error ;
}
error = regulator_enable ( data - > io_reg ) ;
if ( error ) {
dev_err ( & client - > dev , " Failed to enable vdd: %d \n " , error ) ;
regulator_disable ( data - > core_reg ) ;
return error ;
}
2018-01-29 22:43:52 +03:00
msleep ( MMS114_POWERON_DELAY ) ;
2012-07-13 11:25:45 +04:00
error = mms114_setup_regs ( data ) ;
2013-03-04 08:21:30 +04:00
if ( error < 0 ) {
regulator_disable ( data - > io_reg ) ;
regulator_disable ( data - > core_reg ) ;
2012-07-13 11:25:45 +04:00
return error ;
2013-03-04 08:21:30 +04:00
}
2012-07-13 11:25:45 +04:00
enable_irq ( client - > irq ) ;
return 0 ;
}
static void mms114_stop ( struct mms114_data * data )
{
struct i2c_client * client = data - > client ;
2013-03-04 08:21:30 +04:00
int error ;
2012-07-13 11:25:45 +04:00
disable_irq ( client - > irq ) ;
2013-03-04 08:21:30 +04:00
error = regulator_disable ( data - > io_reg ) ;
if ( error )
dev_warn ( & client - > dev , " Failed to disable vdd: %d \n " , error ) ;
error = regulator_disable ( data - > core_reg ) ;
if ( error )
dev_warn ( & client - > dev , " Failed to disable avdd: %d \n " , error ) ;
2012-07-13 11:25:45 +04:00
}
static int mms114_input_open ( struct input_dev * dev )
{
struct mms114_data * data = input_get_drvdata ( dev ) ;
return mms114_start ( data ) ;
}
static void mms114_input_close ( struct input_dev * dev )
{
struct mms114_data * data = input_get_drvdata ( dev ) ;
mms114_stop ( data ) ;
}
2018-01-23 04:45:09 +03:00
static int mms114_parse_legacy_bindings ( struct mms114_data * data )
2012-10-11 12:03:50 +04:00
{
2018-01-23 04:45:09 +03:00
struct device * dev = & data - > client - > dev ;
struct touchscreen_properties * props = & data - > props ;
2012-10-11 12:03:50 +04:00
2018-01-23 04:45:09 +03:00
if ( device_property_read_u32 ( dev , " x-size " , & props - > max_x ) ) {
dev_dbg ( dev , " failed to get legacy x-size property \n " ) ;
return - EINVAL ;
2012-10-11 12:03:50 +04:00
}
2018-01-23 04:45:09 +03:00
if ( device_property_read_u32 ( dev , " y-size " , & props - > max_y ) ) {
dev_dbg ( dev , " failed to get legacy y-size property \n " ) ;
return - EINVAL ;
2015-09-14 20:38:39 +03:00
}
2012-10-11 12:03:50 +04:00
2018-01-23 04:45:09 +03:00
device_property_read_u32 ( dev , " contact-threshold " ,
& data - > contact_threshold ) ;
device_property_read_u32 ( dev , " moving-threshold " ,
& data - > moving_threshold ) ;
2012-10-11 12:03:50 +04:00
2018-01-23 04:45:09 +03:00
if ( device_property_read_bool ( dev , " x-invert " ) )
props - > invert_x = true ;
if ( device_property_read_bool ( dev , " y-invert " ) )
props - > invert_y = true ;
2012-10-11 12:03:50 +04:00
2018-01-23 04:45:09 +03:00
props - > swap_x_y = false ;
2012-10-11 12:03:50 +04:00
2018-01-23 04:45:09 +03:00
return 0 ;
2012-10-11 12:03:50 +04:00
}
2012-11-24 09:38:25 +04:00
static int mms114_probe ( struct i2c_client * client ,
2012-07-13 11:25:45 +04:00
const struct i2c_device_id * id )
{
struct mms114_data * data ;
struct input_dev * input_dev ;
2018-01-23 23:02:39 +03:00
const void * match_data ;
2012-07-13 11:25:45 +04:00
int error ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_PROTOCOL_MANGLING ) ) {
dev_err ( & client - > dev ,
" Need i2c bus that supports protocol mangling \n " ) ;
return - ENODEV ;
}
2013-01-09 21:03:27 +04:00
data = devm_kzalloc ( & client - > dev , sizeof ( struct mms114_data ) ,
GFP_KERNEL ) ;
input_dev = devm_input_allocate_device ( & client - > dev ) ;
2012-07-13 11:25:45 +04:00
if ( ! data | | ! input_dev ) {
dev_err ( & client - > dev , " Failed to allocate memory \n " ) ;
2013-01-09 21:03:27 +04:00
return - ENOMEM ;
2012-07-13 11:25:45 +04:00
}
data - > client = client ;
data - > input_dev = input_dev ;
2018-01-23 04:45:09 +03:00
2018-01-23 23:02:39 +03:00
/* FIXME: switch to device_get_match_data() when available */
match_data = of_device_get_match_data ( & client - > dev ) ;
if ( ! match_data )
return - EINVAL ;
data - > type = ( enum mms_type ) match_data ;
2018-01-23 04:45:09 +03:00
input_set_capability ( input_dev , EV_ABS , ABS_MT_POSITION_X ) ;
input_set_capability ( input_dev , EV_ABS , ABS_MT_POSITION_Y ) ;
input_set_abs_params ( input_dev , ABS_MT_PRESSURE , 0 , 255 , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_TOUCH_MAJOR ,
0 , MMS114_MAX_AREA , 0 , 0 ) ;
touchscreen_parse_properties ( input_dev , true , & data - > props ) ;
if ( ! data - > props . max_x | | ! data - > props . max_y ) {
dev_dbg ( & client - > dev ,
" missing X/Y size properties, trying legacy bindings \n " ) ;
error = mms114_parse_legacy_bindings ( data ) ;
if ( error )
return error ;
input_set_abs_params ( input_dev , ABS_MT_POSITION_X ,
0 , data - > props . max_x , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_POSITION_Y ,
0 , data - > props . max_y , 0 , 0 ) ;
}
2018-01-23 23:02:39 +03:00
if ( data - > type = = TYPE_MMS114 ) {
/*
* The firmware handles movement and pressure fuzz , so
* don ' t duplicate that in software .
*/
data - > moving_threshold = input_abs_get_fuzz ( input_dev ,
ABS_MT_POSITION_X ) ;
data - > contact_threshold = input_abs_get_fuzz ( input_dev ,
ABS_MT_PRESSURE ) ;
input_abs_set_fuzz ( input_dev , ABS_MT_POSITION_X , 0 ) ;
input_abs_set_fuzz ( input_dev , ABS_MT_POSITION_Y , 0 ) ;
input_abs_set_fuzz ( input_dev , ABS_MT_PRESSURE , 0 ) ;
}
input_dev - > name = devm_kasprintf ( & client - > dev , GFP_KERNEL ,
" MELFAS MMS%d Touchscreen " ,
data - > type ) ;
if ( ! input_dev - > name )
return - ENOMEM ;
2012-07-13 11:25:45 +04:00
input_dev - > id . bustype = BUS_I2C ;
input_dev - > dev . parent = & client - > dev ;
input_dev - > open = mms114_input_open ;
input_dev - > close = mms114_input_close ;
2018-01-23 22:11:09 +03:00
error = input_mt_init_slots ( input_dev , MMS114_MAX_TOUCH ,
INPUT_MT_DIRECT ) ;
if ( error )
return error ;
2012-07-13 11:25:45 +04:00
input_set_drvdata ( input_dev , data ) ;
i2c_set_clientdata ( client , data ) ;
2013-01-09 21:03:27 +04:00
data - > core_reg = devm_regulator_get ( & client - > dev , " avdd " ) ;
2012-07-13 11:25:45 +04:00
if ( IS_ERR ( data - > core_reg ) ) {
error = PTR_ERR ( data - > core_reg ) ;
dev_err ( & client - > dev ,
" Unable to get the Core regulator (%d) \n " , error ) ;
2013-01-09 21:03:27 +04:00
return error ;
2012-07-13 11:25:45 +04:00
}
2013-01-09 21:03:27 +04:00
data - > io_reg = devm_regulator_get ( & client - > dev , " vdd " ) ;
2012-07-13 11:25:45 +04:00
if ( IS_ERR ( data - > io_reg ) ) {
error = PTR_ERR ( data - > io_reg ) ;
dev_err ( & client - > dev ,
" Unable to get the IO regulator (%d) \n " , error ) ;
2013-01-09 21:03:27 +04:00
return error ;
2012-07-13 11:25:45 +04:00
}
2018-01-23 22:06:56 +03:00
error = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , mms114_interrupt , IRQF_ONESHOT ,
dev_name ( & client - > dev ) , data ) ;
2012-07-13 11:25:45 +04:00
if ( error ) {
dev_err ( & client - > dev , " Failed to register interrupt \n " ) ;
2013-01-09 21:03:27 +04:00
return error ;
2012-07-13 11:25:45 +04:00
}
disable_irq ( client - > irq ) ;
error = input_register_device ( data - > input_dev ) ;
2013-01-09 21:03:27 +04:00
if ( error ) {
dev_err ( & client - > dev , " Failed to register input device \n " ) ;
return error ;
}
2012-07-13 11:25:45 +04:00
return 0 ;
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused mms114_suspend ( struct device * dev )
2012-07-13 11:25:45 +04:00
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct mms114_data * data = i2c_get_clientdata ( client ) ;
struct input_dev * input_dev = data - > input_dev ;
int id ;
/* Release all touch */
for ( id = 0 ; id < MMS114_MAX_TOUCH ; id + + ) {
input_mt_slot ( input_dev , id ) ;
input_mt_report_slot_state ( input_dev , MT_TOOL_FINGER , false ) ;
}
input_mt_report_pointer_emulation ( input_dev , true ) ;
input_sync ( input_dev ) ;
mutex_lock ( & input_dev - > mutex ) ;
if ( input_dev - > users )
mms114_stop ( data ) ;
mutex_unlock ( & input_dev - > mutex ) ;
return 0 ;
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused mms114_resume ( struct device * dev )
2012-07-13 11:25:45 +04:00
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct mms114_data * data = i2c_get_clientdata ( client ) ;
struct input_dev * input_dev = data - > input_dev ;
int error ;
mutex_lock ( & input_dev - > mutex ) ;
if ( input_dev - > users ) {
error = mms114_start ( data ) ;
if ( error < 0 ) {
mutex_unlock ( & input_dev - > mutex ) ;
return error ;
}
}
mutex_unlock ( & input_dev - > mutex ) ;
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( mms114_pm_ops , mms114_suspend , mms114_resume ) ;
static const struct i2c_device_id mms114_id [ ] = {
{ " mms114 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , mms114_id ) ;
2012-10-11 12:03:50 +04:00
# ifdef CONFIG_OF
2014-05-08 00:09:52 +04:00
static const struct of_device_id mms114_dt_match [ ] = {
2018-01-23 23:02:39 +03:00
{
. compatible = " melfas,mms114 " ,
. data = ( void * ) TYPE_MMS114 ,
} , {
. compatible = " melfas,mms152 " ,
. data = ( void * ) TYPE_MMS152 ,
} ,
2012-10-11 12:03:50 +04:00
{ }
} ;
2015-07-30 20:39:28 +03:00
MODULE_DEVICE_TABLE ( of , mms114_dt_match ) ;
2012-10-11 12:03:50 +04:00
# endif
2012-07-13 11:25:45 +04:00
static struct i2c_driver mms114_driver = {
. driver = {
. name = " mms114 " ,
. pm = & mms114_pm_ops ,
2012-10-11 12:03:50 +04:00
. of_match_table = of_match_ptr ( mms114_dt_match ) ,
2012-07-13 11:25:45 +04:00
} ,
. probe = mms114_probe ,
. id_table = mms114_id ,
} ;
module_i2c_driver ( mms114_driver ) ;
/* Module information */
MODULE_AUTHOR ( " Joonyoung Shim <jy0922.shim@samsung.com> " ) ;
MODULE_DESCRIPTION ( " MELFAS mms114 Touchscreen driver " ) ;
2018-02-01 21:18:59 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;