1*09d6292bSJin Park /* 2*09d6292bSJin Park * linux/drivers/mfd/aat2870-core.c 3*09d6292bSJin Park * 4*09d6292bSJin Park * Copyright (c) 2011, NVIDIA Corporation. 5*09d6292bSJin Park * Author: Jin Park <jinyoungp@nvidia.com> 6*09d6292bSJin Park * 7*09d6292bSJin Park * This program is free software; you can redistribute it and/or 8*09d6292bSJin Park * modify it under the terms of the GNU General Public License 9*09d6292bSJin Park * version 2 as published by the Free Software Foundation. 10*09d6292bSJin Park * 11*09d6292bSJin Park * This program is distributed in the hope that it will be useful, but 12*09d6292bSJin Park * WITHOUT ANY WARRANTY; without even the implied warranty of 13*09d6292bSJin Park * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*09d6292bSJin Park * General Public License for more details. 15*09d6292bSJin Park * 16*09d6292bSJin Park * You should have received a copy of the GNU General Public License 17*09d6292bSJin Park * along with this program; if not, write to the Free Software 18*09d6292bSJin Park * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 19*09d6292bSJin Park * 02110-1301 USA 20*09d6292bSJin Park */ 21*09d6292bSJin Park 22*09d6292bSJin Park #include <linux/kernel.h> 23*09d6292bSJin Park #include <linux/module.h> 24*09d6292bSJin Park #include <linux/init.h> 25*09d6292bSJin Park #include <linux/debugfs.h> 26*09d6292bSJin Park #include <linux/slab.h> 27*09d6292bSJin Park #include <linux/uaccess.h> 28*09d6292bSJin Park #include <linux/i2c.h> 29*09d6292bSJin Park #include <linux/delay.h> 30*09d6292bSJin Park #include <linux/gpio.h> 31*09d6292bSJin Park #include <linux/mfd/core.h> 32*09d6292bSJin Park #include <linux/mfd/aat2870.h> 33*09d6292bSJin Park #include <linux/regulator/machine.h> 34*09d6292bSJin Park 35*09d6292bSJin Park static struct aat2870_register aat2870_regs[AAT2870_REG_NUM] = { 36*09d6292bSJin Park /* readable, writeable, value */ 37*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x00 AAT2870_BL_CH_EN */ 38*09d6292bSJin Park { 0, 1, 0x16 }, /* 0x01 AAT2870_BLM */ 39*09d6292bSJin Park { 0, 1, 0x16 }, /* 0x02 AAT2870_BLS */ 40*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x03 AAT2870_BL1 */ 41*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x04 AAT2870_BL2 */ 42*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x05 AAT2870_BL3 */ 43*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x06 AAT2870_BL4 */ 44*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x07 AAT2870_BL5 */ 45*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x08 AAT2870_BL6 */ 46*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x09 AAT2870_BL7 */ 47*09d6292bSJin Park { 0, 1, 0x56 }, /* 0x0A AAT2870_BL8 */ 48*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x0B AAT2870_FLR */ 49*09d6292bSJin Park { 0, 1, 0x03 }, /* 0x0C AAT2870_FM */ 50*09d6292bSJin Park { 0, 1, 0x03 }, /* 0x0D AAT2870_FS */ 51*09d6292bSJin Park { 0, 1, 0x10 }, /* 0x0E AAT2870_ALS_CFG0 */ 52*09d6292bSJin Park { 0, 1, 0x06 }, /* 0x0F AAT2870_ALS_CFG1 */ 53*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x10 AAT2870_ALS_CFG2 */ 54*09d6292bSJin Park { 1, 0, 0x00 }, /* 0x11 AAT2870_AMB */ 55*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x12 AAT2870_ALS0 */ 56*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x13 AAT2870_ALS1 */ 57*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x14 AAT2870_ALS2 */ 58*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x15 AAT2870_ALS3 */ 59*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x16 AAT2870_ALS4 */ 60*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x17 AAT2870_ALS5 */ 61*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x18 AAT2870_ALS6 */ 62*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x19 AAT2870_ALS7 */ 63*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1A AAT2870_ALS8 */ 64*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1B AAT2870_ALS9 */ 65*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1C AAT2870_ALSA */ 66*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1D AAT2870_ALSB */ 67*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1E AAT2870_ALSC */ 68*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x1F AAT2870_ALSD */ 69*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x20 AAT2870_ALSE */ 70*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x21 AAT2870_ALSF */ 71*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x22 AAT2870_SUB_SET */ 72*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x23 AAT2870_SUB_CTRL */ 73*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x24 AAT2870_LDO_AB */ 74*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x25 AAT2870_LDO_CD */ 75*09d6292bSJin Park { 0, 1, 0x00 }, /* 0x26 AAT2870_LDO_EN */ 76*09d6292bSJin Park }; 77*09d6292bSJin Park 78*09d6292bSJin Park static struct mfd_cell aat2870_devs[] = { 79*09d6292bSJin Park { 80*09d6292bSJin Park .name = "aat2870-backlight", 81*09d6292bSJin Park .id = AAT2870_ID_BL, 82*09d6292bSJin Park .pdata_size = sizeof(struct aat2870_bl_platform_data), 83*09d6292bSJin Park }, 84*09d6292bSJin Park { 85*09d6292bSJin Park .name = "aat2870-regulator", 86*09d6292bSJin Park .id = AAT2870_ID_LDOA, 87*09d6292bSJin Park .pdata_size = sizeof(struct regulator_init_data), 88*09d6292bSJin Park }, 89*09d6292bSJin Park { 90*09d6292bSJin Park .name = "aat2870-regulator", 91*09d6292bSJin Park .id = AAT2870_ID_LDOB, 92*09d6292bSJin Park .pdata_size = sizeof(struct regulator_init_data), 93*09d6292bSJin Park }, 94*09d6292bSJin Park { 95*09d6292bSJin Park .name = "aat2870-regulator", 96*09d6292bSJin Park .id = AAT2870_ID_LDOC, 97*09d6292bSJin Park .pdata_size = sizeof(struct regulator_init_data), 98*09d6292bSJin Park }, 99*09d6292bSJin Park { 100*09d6292bSJin Park .name = "aat2870-regulator", 101*09d6292bSJin Park .id = AAT2870_ID_LDOD, 102*09d6292bSJin Park .pdata_size = sizeof(struct regulator_init_data), 103*09d6292bSJin Park }, 104*09d6292bSJin Park }; 105*09d6292bSJin Park 106*09d6292bSJin Park static int __aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val) 107*09d6292bSJin Park { 108*09d6292bSJin Park int ret; 109*09d6292bSJin Park 110*09d6292bSJin Park if (addr >= AAT2870_REG_NUM) { 111*09d6292bSJin Park dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr); 112*09d6292bSJin Park return -EINVAL; 113*09d6292bSJin Park } 114*09d6292bSJin Park 115*09d6292bSJin Park if (!aat2870->reg_cache[addr].readable) { 116*09d6292bSJin Park *val = aat2870->reg_cache[addr].value; 117*09d6292bSJin Park goto out; 118*09d6292bSJin Park } 119*09d6292bSJin Park 120*09d6292bSJin Park ret = i2c_master_send(aat2870->client, &addr, 1); 121*09d6292bSJin Park if (ret < 0) 122*09d6292bSJin Park return ret; 123*09d6292bSJin Park if (ret != 1) 124*09d6292bSJin Park return -EIO; 125*09d6292bSJin Park 126*09d6292bSJin Park ret = i2c_master_recv(aat2870->client, val, 1); 127*09d6292bSJin Park if (ret < 0) 128*09d6292bSJin Park return ret; 129*09d6292bSJin Park if (ret != 1) 130*09d6292bSJin Park return -EIO; 131*09d6292bSJin Park 132*09d6292bSJin Park out: 133*09d6292bSJin Park dev_dbg(aat2870->dev, "read: addr=0x%02x, val=0x%02x\n", addr, *val); 134*09d6292bSJin Park return 0; 135*09d6292bSJin Park } 136*09d6292bSJin Park 137*09d6292bSJin Park static int __aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val) 138*09d6292bSJin Park { 139*09d6292bSJin Park u8 msg[2]; 140*09d6292bSJin Park int ret; 141*09d6292bSJin Park 142*09d6292bSJin Park if (addr >= AAT2870_REG_NUM) { 143*09d6292bSJin Park dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr); 144*09d6292bSJin Park return -EINVAL; 145*09d6292bSJin Park } 146*09d6292bSJin Park 147*09d6292bSJin Park if (!aat2870->reg_cache[addr].writeable) { 148*09d6292bSJin Park dev_err(aat2870->dev, "Address 0x%02x is not writeable\n", 149*09d6292bSJin Park addr); 150*09d6292bSJin Park return -EINVAL; 151*09d6292bSJin Park } 152*09d6292bSJin Park 153*09d6292bSJin Park msg[0] = addr; 154*09d6292bSJin Park msg[1] = val; 155*09d6292bSJin Park ret = i2c_master_send(aat2870->client, msg, 2); 156*09d6292bSJin Park if (ret < 0) 157*09d6292bSJin Park return ret; 158*09d6292bSJin Park if (ret != 2) 159*09d6292bSJin Park return -EIO; 160*09d6292bSJin Park 161*09d6292bSJin Park aat2870->reg_cache[addr].value = val; 162*09d6292bSJin Park 163*09d6292bSJin Park dev_dbg(aat2870->dev, "write: addr=0x%02x, val=0x%02x\n", addr, val); 164*09d6292bSJin Park return 0; 165*09d6292bSJin Park } 166*09d6292bSJin Park 167*09d6292bSJin Park static int aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val) 168*09d6292bSJin Park { 169*09d6292bSJin Park int ret; 170*09d6292bSJin Park 171*09d6292bSJin Park mutex_lock(&aat2870->io_lock); 172*09d6292bSJin Park ret = __aat2870_read(aat2870, addr, val); 173*09d6292bSJin Park mutex_unlock(&aat2870->io_lock); 174*09d6292bSJin Park 175*09d6292bSJin Park return ret; 176*09d6292bSJin Park } 177*09d6292bSJin Park 178*09d6292bSJin Park static int aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val) 179*09d6292bSJin Park { 180*09d6292bSJin Park int ret; 181*09d6292bSJin Park 182*09d6292bSJin Park mutex_lock(&aat2870->io_lock); 183*09d6292bSJin Park ret = __aat2870_write(aat2870, addr, val); 184*09d6292bSJin Park mutex_unlock(&aat2870->io_lock); 185*09d6292bSJin Park 186*09d6292bSJin Park return ret; 187*09d6292bSJin Park } 188*09d6292bSJin Park 189*09d6292bSJin Park static int aat2870_update(struct aat2870_data *aat2870, u8 addr, u8 mask, 190*09d6292bSJin Park u8 val) 191*09d6292bSJin Park { 192*09d6292bSJin Park int change; 193*09d6292bSJin Park u8 old_val, new_val; 194*09d6292bSJin Park int ret; 195*09d6292bSJin Park 196*09d6292bSJin Park mutex_lock(&aat2870->io_lock); 197*09d6292bSJin Park 198*09d6292bSJin Park ret = __aat2870_read(aat2870, addr, &old_val); 199*09d6292bSJin Park if (ret) 200*09d6292bSJin Park goto out_unlock; 201*09d6292bSJin Park 202*09d6292bSJin Park new_val = (old_val & ~mask) | (val & mask); 203*09d6292bSJin Park change = old_val != new_val; 204*09d6292bSJin Park if (change) 205*09d6292bSJin Park ret = __aat2870_write(aat2870, addr, new_val); 206*09d6292bSJin Park 207*09d6292bSJin Park out_unlock: 208*09d6292bSJin Park mutex_unlock(&aat2870->io_lock); 209*09d6292bSJin Park 210*09d6292bSJin Park return ret; 211*09d6292bSJin Park } 212*09d6292bSJin Park 213*09d6292bSJin Park static inline void aat2870_enable(struct aat2870_data *aat2870) 214*09d6292bSJin Park { 215*09d6292bSJin Park if (aat2870->en_pin >= 0) 216*09d6292bSJin Park gpio_set_value(aat2870->en_pin, 1); 217*09d6292bSJin Park 218*09d6292bSJin Park aat2870->is_enable = 1; 219*09d6292bSJin Park } 220*09d6292bSJin Park 221*09d6292bSJin Park static inline void aat2870_disable(struct aat2870_data *aat2870) 222*09d6292bSJin Park { 223*09d6292bSJin Park if (aat2870->en_pin >= 0) 224*09d6292bSJin Park gpio_set_value(aat2870->en_pin, 0); 225*09d6292bSJin Park 226*09d6292bSJin Park aat2870->is_enable = 0; 227*09d6292bSJin Park } 228*09d6292bSJin Park 229*09d6292bSJin Park #ifdef CONFIG_DEBUG_FS 230*09d6292bSJin Park static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf) 231*09d6292bSJin Park { 232*09d6292bSJin Park u8 addr, val; 233*09d6292bSJin Park ssize_t count = 0; 234*09d6292bSJin Park int ret; 235*09d6292bSJin Park 236*09d6292bSJin Park count += sprintf(buf, "aat2870 registers\n"); 237*09d6292bSJin Park for (addr = 0; addr < AAT2870_REG_NUM; addr++) { 238*09d6292bSJin Park count += sprintf(buf + count, "0x%02x: ", addr); 239*09d6292bSJin Park if (count >= PAGE_SIZE - 1) 240*09d6292bSJin Park break; 241*09d6292bSJin Park 242*09d6292bSJin Park ret = aat2870->read(aat2870, addr, &val); 243*09d6292bSJin Park if (ret == 0) 244*09d6292bSJin Park count += snprintf(buf + count, PAGE_SIZE - count, 245*09d6292bSJin Park "0x%02x", val); 246*09d6292bSJin Park else 247*09d6292bSJin Park count += snprintf(buf + count, PAGE_SIZE - count, 248*09d6292bSJin Park "<read fail: %d>", ret); 249*09d6292bSJin Park 250*09d6292bSJin Park if (count >= PAGE_SIZE - 1) 251*09d6292bSJin Park break; 252*09d6292bSJin Park 253*09d6292bSJin Park count += snprintf(buf + count, PAGE_SIZE - count, "\n"); 254*09d6292bSJin Park if (count >= PAGE_SIZE - 1) 255*09d6292bSJin Park break; 256*09d6292bSJin Park } 257*09d6292bSJin Park 258*09d6292bSJin Park /* Truncate count; min() would cause a warning */ 259*09d6292bSJin Park if (count >= PAGE_SIZE) 260*09d6292bSJin Park count = PAGE_SIZE - 1; 261*09d6292bSJin Park 262*09d6292bSJin Park return count; 263*09d6292bSJin Park } 264*09d6292bSJin Park 265*09d6292bSJin Park static int aat2870_reg_open_file(struct inode *inode, struct file *file) 266*09d6292bSJin Park { 267*09d6292bSJin Park file->private_data = inode->i_private; 268*09d6292bSJin Park 269*09d6292bSJin Park return 0; 270*09d6292bSJin Park } 271*09d6292bSJin Park 272*09d6292bSJin Park static ssize_t aat2870_reg_read_file(struct file *file, char __user *user_buf, 273*09d6292bSJin Park size_t count, loff_t *ppos) 274*09d6292bSJin Park { 275*09d6292bSJin Park struct aat2870_data *aat2870 = file->private_data; 276*09d6292bSJin Park char *buf; 277*09d6292bSJin Park ssize_t ret; 278*09d6292bSJin Park 279*09d6292bSJin Park buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 280*09d6292bSJin Park if (!buf) 281*09d6292bSJin Park return -ENOMEM; 282*09d6292bSJin Park 283*09d6292bSJin Park ret = aat2870_dump_reg(aat2870, buf); 284*09d6292bSJin Park if (ret >= 0) 285*09d6292bSJin Park ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 286*09d6292bSJin Park 287*09d6292bSJin Park kfree(buf); 288*09d6292bSJin Park 289*09d6292bSJin Park return ret; 290*09d6292bSJin Park } 291*09d6292bSJin Park 292*09d6292bSJin Park static ssize_t aat2870_reg_write_file(struct file *file, 293*09d6292bSJin Park const char __user *user_buf, size_t count, 294*09d6292bSJin Park loff_t *ppos) 295*09d6292bSJin Park { 296*09d6292bSJin Park struct aat2870_data *aat2870 = file->private_data; 297*09d6292bSJin Park char buf[32]; 298*09d6292bSJin Park int buf_size; 299*09d6292bSJin Park char *start = buf; 300*09d6292bSJin Park unsigned long addr, val; 301*09d6292bSJin Park int ret; 302*09d6292bSJin Park 303*09d6292bSJin Park buf_size = min(count, (sizeof(buf)-1)); 304*09d6292bSJin Park if (copy_from_user(buf, user_buf, buf_size)) { 305*09d6292bSJin Park dev_err(aat2870->dev, "Failed to copy from user\n"); 306*09d6292bSJin Park return -EFAULT; 307*09d6292bSJin Park } 308*09d6292bSJin Park buf[buf_size] = 0; 309*09d6292bSJin Park 310*09d6292bSJin Park while (*start == ' ') 311*09d6292bSJin Park start++; 312*09d6292bSJin Park 313*09d6292bSJin Park addr = simple_strtoul(start, &start, 16); 314*09d6292bSJin Park if (addr >= AAT2870_REG_NUM) { 315*09d6292bSJin Park dev_err(aat2870->dev, "Invalid address, 0x%lx\n", addr); 316*09d6292bSJin Park return -EINVAL; 317*09d6292bSJin Park } 318*09d6292bSJin Park 319*09d6292bSJin Park while (*start == ' ') 320*09d6292bSJin Park start++; 321*09d6292bSJin Park 322*09d6292bSJin Park if (strict_strtoul(start, 16, &val)) 323*09d6292bSJin Park return -EINVAL; 324*09d6292bSJin Park 325*09d6292bSJin Park ret = aat2870->write(aat2870, (u8)addr, (u8)val); 326*09d6292bSJin Park if (ret) 327*09d6292bSJin Park return ret; 328*09d6292bSJin Park 329*09d6292bSJin Park return buf_size; 330*09d6292bSJin Park } 331*09d6292bSJin Park 332*09d6292bSJin Park static const struct file_operations aat2870_reg_fops = { 333*09d6292bSJin Park .open = aat2870_reg_open_file, 334*09d6292bSJin Park .read = aat2870_reg_read_file, 335*09d6292bSJin Park .write = aat2870_reg_write_file, 336*09d6292bSJin Park }; 337*09d6292bSJin Park 338*09d6292bSJin Park static void aat2870_init_debugfs(struct aat2870_data *aat2870) 339*09d6292bSJin Park { 340*09d6292bSJin Park aat2870->dentry_root = debugfs_create_dir("aat2870", NULL); 341*09d6292bSJin Park if (!aat2870->dentry_root) { 342*09d6292bSJin Park dev_warn(aat2870->dev, 343*09d6292bSJin Park "Failed to create debugfs root directory\n"); 344*09d6292bSJin Park return; 345*09d6292bSJin Park } 346*09d6292bSJin Park 347*09d6292bSJin Park aat2870->dentry_reg = debugfs_create_file("regs", 0644, 348*09d6292bSJin Park aat2870->dentry_root, 349*09d6292bSJin Park aat2870, &aat2870_reg_fops); 350*09d6292bSJin Park if (!aat2870->dentry_reg) 351*09d6292bSJin Park dev_warn(aat2870->dev, 352*09d6292bSJin Park "Failed to create debugfs register file\n"); 353*09d6292bSJin Park } 354*09d6292bSJin Park 355*09d6292bSJin Park static void aat2870_uninit_debugfs(struct aat2870_data *aat2870) 356*09d6292bSJin Park { 357*09d6292bSJin Park debugfs_remove_recursive(aat2870->dentry_root); 358*09d6292bSJin Park } 359*09d6292bSJin Park #else 360*09d6292bSJin Park static inline void aat2870_init_debugfs(struct aat2870_data *aat2870) 361*09d6292bSJin Park { 362*09d6292bSJin Park } 363*09d6292bSJin Park 364*09d6292bSJin Park static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870) 365*09d6292bSJin Park { 366*09d6292bSJin Park } 367*09d6292bSJin Park #endif /* CONFIG_DEBUG_FS */ 368*09d6292bSJin Park 369*09d6292bSJin Park static int aat2870_i2c_probe(struct i2c_client *client, 370*09d6292bSJin Park const struct i2c_device_id *id) 371*09d6292bSJin Park { 372*09d6292bSJin Park struct aat2870_platform_data *pdata = client->dev.platform_data; 373*09d6292bSJin Park struct aat2870_data *aat2870; 374*09d6292bSJin Park int i, j; 375*09d6292bSJin Park int ret = 0; 376*09d6292bSJin Park 377*09d6292bSJin Park aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL); 378*09d6292bSJin Park if (!aat2870) { 379*09d6292bSJin Park dev_err(&client->dev, 380*09d6292bSJin Park "Failed to allocate memory for aat2870\n"); 381*09d6292bSJin Park ret = -ENOMEM; 382*09d6292bSJin Park goto out; 383*09d6292bSJin Park } 384*09d6292bSJin Park 385*09d6292bSJin Park aat2870->dev = &client->dev; 386*09d6292bSJin Park dev_set_drvdata(aat2870->dev, aat2870); 387*09d6292bSJin Park 388*09d6292bSJin Park aat2870->client = client; 389*09d6292bSJin Park i2c_set_clientdata(client, aat2870); 390*09d6292bSJin Park 391*09d6292bSJin Park aat2870->reg_cache = aat2870_regs; 392*09d6292bSJin Park 393*09d6292bSJin Park if (pdata->en_pin < 0) 394*09d6292bSJin Park aat2870->en_pin = -1; 395*09d6292bSJin Park else 396*09d6292bSJin Park aat2870->en_pin = pdata->en_pin; 397*09d6292bSJin Park 398*09d6292bSJin Park aat2870->init = pdata->init; 399*09d6292bSJin Park aat2870->uninit = pdata->uninit; 400*09d6292bSJin Park aat2870->read = aat2870_read; 401*09d6292bSJin Park aat2870->write = aat2870_write; 402*09d6292bSJin Park aat2870->update = aat2870_update; 403*09d6292bSJin Park 404*09d6292bSJin Park mutex_init(&aat2870->io_lock); 405*09d6292bSJin Park 406*09d6292bSJin Park if (aat2870->init) 407*09d6292bSJin Park aat2870->init(aat2870); 408*09d6292bSJin Park 409*09d6292bSJin Park if (aat2870->en_pin >= 0) { 410*09d6292bSJin Park ret = gpio_request(aat2870->en_pin, "aat2870-en"); 411*09d6292bSJin Park if (ret < 0) { 412*09d6292bSJin Park dev_err(&client->dev, 413*09d6292bSJin Park "Failed to request GPIO %d\n", aat2870->en_pin); 414*09d6292bSJin Park goto out_kfree; 415*09d6292bSJin Park } 416*09d6292bSJin Park gpio_direction_output(aat2870->en_pin, 1); 417*09d6292bSJin Park } 418*09d6292bSJin Park 419*09d6292bSJin Park aat2870_enable(aat2870); 420*09d6292bSJin Park 421*09d6292bSJin Park for (i = 0; i < pdata->num_subdevs; i++) { 422*09d6292bSJin Park for (j = 0; j < ARRAY_SIZE(aat2870_devs); j++) { 423*09d6292bSJin Park if ((pdata->subdevs[i].id == aat2870_devs[j].id) && 424*09d6292bSJin Park !strcmp(pdata->subdevs[i].name, 425*09d6292bSJin Park aat2870_devs[j].name)) { 426*09d6292bSJin Park aat2870_devs[j].platform_data = 427*09d6292bSJin Park pdata->subdevs[i].platform_data; 428*09d6292bSJin Park break; 429*09d6292bSJin Park } 430*09d6292bSJin Park } 431*09d6292bSJin Park } 432*09d6292bSJin Park 433*09d6292bSJin Park ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, 434*09d6292bSJin Park ARRAY_SIZE(aat2870_devs), NULL, 0); 435*09d6292bSJin Park if (ret != 0) { 436*09d6292bSJin Park dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); 437*09d6292bSJin Park goto out_disable; 438*09d6292bSJin Park } 439*09d6292bSJin Park 440*09d6292bSJin Park aat2870_init_debugfs(aat2870); 441*09d6292bSJin Park 442*09d6292bSJin Park return 0; 443*09d6292bSJin Park 444*09d6292bSJin Park out_disable: 445*09d6292bSJin Park aat2870_disable(aat2870); 446*09d6292bSJin Park if (aat2870->en_pin >= 0) 447*09d6292bSJin Park gpio_free(aat2870->en_pin); 448*09d6292bSJin Park out_kfree: 449*09d6292bSJin Park kfree(aat2870); 450*09d6292bSJin Park out: 451*09d6292bSJin Park return ret; 452*09d6292bSJin Park } 453*09d6292bSJin Park 454*09d6292bSJin Park static int aat2870_i2c_remove(struct i2c_client *client) 455*09d6292bSJin Park { 456*09d6292bSJin Park struct aat2870_data *aat2870 = i2c_get_clientdata(client); 457*09d6292bSJin Park 458*09d6292bSJin Park aat2870_uninit_debugfs(aat2870); 459*09d6292bSJin Park 460*09d6292bSJin Park mfd_remove_devices(aat2870->dev); 461*09d6292bSJin Park aat2870_disable(aat2870); 462*09d6292bSJin Park if (aat2870->en_pin >= 0) 463*09d6292bSJin Park gpio_free(aat2870->en_pin); 464*09d6292bSJin Park if (aat2870->uninit) 465*09d6292bSJin Park aat2870->uninit(aat2870); 466*09d6292bSJin Park kfree(aat2870); 467*09d6292bSJin Park 468*09d6292bSJin Park return 0; 469*09d6292bSJin Park } 470*09d6292bSJin Park 471*09d6292bSJin Park #ifdef CONFIG_PM 472*09d6292bSJin Park static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state) 473*09d6292bSJin Park { 474*09d6292bSJin Park struct aat2870_data *aat2870 = i2c_get_clientdata(client); 475*09d6292bSJin Park 476*09d6292bSJin Park aat2870_disable(aat2870); 477*09d6292bSJin Park 478*09d6292bSJin Park return 0; 479*09d6292bSJin Park } 480*09d6292bSJin Park 481*09d6292bSJin Park static int aat2870_i2c_resume(struct i2c_client *client) 482*09d6292bSJin Park { 483*09d6292bSJin Park struct aat2870_data *aat2870 = i2c_get_clientdata(client); 484*09d6292bSJin Park struct aat2870_register *reg = NULL; 485*09d6292bSJin Park int i; 486*09d6292bSJin Park 487*09d6292bSJin Park aat2870_enable(aat2870); 488*09d6292bSJin Park 489*09d6292bSJin Park /* restore registers */ 490*09d6292bSJin Park for (i = 0; i < AAT2870_REG_NUM; i++) { 491*09d6292bSJin Park reg = &aat2870->reg_cache[i]; 492*09d6292bSJin Park if (reg->writeable) 493*09d6292bSJin Park aat2870->write(aat2870, i, reg->value); 494*09d6292bSJin Park } 495*09d6292bSJin Park 496*09d6292bSJin Park return 0; 497*09d6292bSJin Park } 498*09d6292bSJin Park #else 499*09d6292bSJin Park #define aat2870_i2c_suspend NULL 500*09d6292bSJin Park #define aat2870_i2c_resume NULL 501*09d6292bSJin Park #endif /* CONFIG_PM */ 502*09d6292bSJin Park 503*09d6292bSJin Park static struct i2c_device_id aat2870_i2c_id_table[] = { 504*09d6292bSJin Park { "aat2870", 0 }, 505*09d6292bSJin Park { } 506*09d6292bSJin Park }; 507*09d6292bSJin Park MODULE_DEVICE_TABLE(i2c, aat2870_i2c_id_table); 508*09d6292bSJin Park 509*09d6292bSJin Park static struct i2c_driver aat2870_i2c_driver = { 510*09d6292bSJin Park .driver = { 511*09d6292bSJin Park .name = "aat2870", 512*09d6292bSJin Park .owner = THIS_MODULE, 513*09d6292bSJin Park }, 514*09d6292bSJin Park .probe = aat2870_i2c_probe, 515*09d6292bSJin Park .remove = aat2870_i2c_remove, 516*09d6292bSJin Park .suspend = aat2870_i2c_suspend, 517*09d6292bSJin Park .resume = aat2870_i2c_resume, 518*09d6292bSJin Park .id_table = aat2870_i2c_id_table, 519*09d6292bSJin Park }; 520*09d6292bSJin Park 521*09d6292bSJin Park static int __init aat2870_init(void) 522*09d6292bSJin Park { 523*09d6292bSJin Park return i2c_add_driver(&aat2870_i2c_driver); 524*09d6292bSJin Park } 525*09d6292bSJin Park subsys_initcall(aat2870_init); 526*09d6292bSJin Park 527*09d6292bSJin Park static void __exit aat2870_exit(void) 528*09d6292bSJin Park { 529*09d6292bSJin Park i2c_del_driver(&aat2870_i2c_driver); 530*09d6292bSJin Park } 531*09d6292bSJin Park module_exit(aat2870_exit); 532*09d6292bSJin Park 533*09d6292bSJin Park MODULE_DESCRIPTION("Core support for the AnalogicTech AAT2870"); 534*09d6292bSJin Park MODULE_LICENSE("GPL"); 535*09d6292bSJin Park MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>"); 536