1*d50f8f33SHaojian Zhuang /* 2*d50f8f33SHaojian Zhuang * I2C driver for Maxim MAX8925 3*d50f8f33SHaojian Zhuang * 4*d50f8f33SHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5*d50f8f33SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6*d50f8f33SHaojian Zhuang * 7*d50f8f33SHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8*d50f8f33SHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9*d50f8f33SHaojian Zhuang * published by the Free Software Foundation. 10*d50f8f33SHaojian Zhuang */ 11*d50f8f33SHaojian Zhuang #include <linux/kernel.h> 12*d50f8f33SHaojian Zhuang #include <linux/module.h> 13*d50f8f33SHaojian Zhuang #include <linux/platform_device.h> 14*d50f8f33SHaojian Zhuang #include <linux/i2c.h> 15*d50f8f33SHaojian Zhuang #include <linux/mfd/max8925.h> 16*d50f8f33SHaojian Zhuang 17*d50f8f33SHaojian Zhuang static inline int max8925_read_device(struct i2c_client *i2c, 18*d50f8f33SHaojian Zhuang int reg, int bytes, void *dest) 19*d50f8f33SHaojian Zhuang { 20*d50f8f33SHaojian Zhuang unsigned char data; 21*d50f8f33SHaojian Zhuang unsigned char *buf; 22*d50f8f33SHaojian Zhuang int ret; 23*d50f8f33SHaojian Zhuang 24*d50f8f33SHaojian Zhuang buf = kzalloc(bytes + 1, GFP_KERNEL); 25*d50f8f33SHaojian Zhuang if (!buf) 26*d50f8f33SHaojian Zhuang return -ENOMEM; 27*d50f8f33SHaojian Zhuang 28*d50f8f33SHaojian Zhuang data = (unsigned char)reg; 29*d50f8f33SHaojian Zhuang ret = i2c_master_send(i2c, &data, 1); 30*d50f8f33SHaojian Zhuang if (ret < 0) 31*d50f8f33SHaojian Zhuang return ret; 32*d50f8f33SHaojian Zhuang 33*d50f8f33SHaojian Zhuang ret = i2c_master_recv(i2c, buf, bytes + 1); 34*d50f8f33SHaojian Zhuang if (ret < 0) 35*d50f8f33SHaojian Zhuang return ret; 36*d50f8f33SHaojian Zhuang memcpy(dest, buf, bytes); 37*d50f8f33SHaojian Zhuang return 0; 38*d50f8f33SHaojian Zhuang } 39*d50f8f33SHaojian Zhuang 40*d50f8f33SHaojian Zhuang static inline int max8925_write_device(struct i2c_client *i2c, 41*d50f8f33SHaojian Zhuang int reg, int bytes, void *src) 42*d50f8f33SHaojian Zhuang { 43*d50f8f33SHaojian Zhuang unsigned char buf[bytes + 1]; 44*d50f8f33SHaojian Zhuang int ret; 45*d50f8f33SHaojian Zhuang 46*d50f8f33SHaojian Zhuang buf[0] = (unsigned char)reg; 47*d50f8f33SHaojian Zhuang memcpy(&buf[1], src, bytes); 48*d50f8f33SHaojian Zhuang 49*d50f8f33SHaojian Zhuang ret = i2c_master_send(i2c, buf, bytes + 1); 50*d50f8f33SHaojian Zhuang if (ret < 0) 51*d50f8f33SHaojian Zhuang return ret; 52*d50f8f33SHaojian Zhuang return 0; 53*d50f8f33SHaojian Zhuang } 54*d50f8f33SHaojian Zhuang 55*d50f8f33SHaojian Zhuang int max8925_reg_read(struct i2c_client *i2c, int reg) 56*d50f8f33SHaojian Zhuang { 57*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 58*d50f8f33SHaojian Zhuang unsigned char data; 59*d50f8f33SHaojian Zhuang int ret; 60*d50f8f33SHaojian Zhuang 61*d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 62*d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, 1, &data); 63*d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 64*d50f8f33SHaojian Zhuang 65*d50f8f33SHaojian Zhuang if (ret < 0) 66*d50f8f33SHaojian Zhuang return ret; 67*d50f8f33SHaojian Zhuang else 68*d50f8f33SHaojian Zhuang return (int)data; 69*d50f8f33SHaojian Zhuang } 70*d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_reg_read); 71*d50f8f33SHaojian Zhuang 72*d50f8f33SHaojian Zhuang int max8925_reg_write(struct i2c_client *i2c, int reg, 73*d50f8f33SHaojian Zhuang unsigned char data) 74*d50f8f33SHaojian Zhuang { 75*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 76*d50f8f33SHaojian Zhuang int ret; 77*d50f8f33SHaojian Zhuang 78*d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 79*d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, 1, &data); 80*d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 81*d50f8f33SHaojian Zhuang 82*d50f8f33SHaojian Zhuang return ret; 83*d50f8f33SHaojian Zhuang } 84*d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_reg_write); 85*d50f8f33SHaojian Zhuang 86*d50f8f33SHaojian Zhuang int max8925_bulk_read(struct i2c_client *i2c, int reg, 87*d50f8f33SHaojian Zhuang int count, unsigned char *buf) 88*d50f8f33SHaojian Zhuang { 89*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 90*d50f8f33SHaojian Zhuang int ret; 91*d50f8f33SHaojian Zhuang 92*d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 93*d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, count, buf); 94*d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 95*d50f8f33SHaojian Zhuang 96*d50f8f33SHaojian Zhuang return ret; 97*d50f8f33SHaojian Zhuang } 98*d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_bulk_read); 99*d50f8f33SHaojian Zhuang 100*d50f8f33SHaojian Zhuang int max8925_bulk_write(struct i2c_client *i2c, int reg, 101*d50f8f33SHaojian Zhuang int count, unsigned char *buf) 102*d50f8f33SHaojian Zhuang { 103*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 104*d50f8f33SHaojian Zhuang int ret; 105*d50f8f33SHaojian Zhuang 106*d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 107*d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, count, buf); 108*d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 109*d50f8f33SHaojian Zhuang 110*d50f8f33SHaojian Zhuang return ret; 111*d50f8f33SHaojian Zhuang } 112*d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_bulk_write); 113*d50f8f33SHaojian Zhuang 114*d50f8f33SHaojian Zhuang int max8925_set_bits(struct i2c_client *i2c, int reg, 115*d50f8f33SHaojian Zhuang unsigned char mask, unsigned char data) 116*d50f8f33SHaojian Zhuang { 117*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(i2c); 118*d50f8f33SHaojian Zhuang unsigned char value; 119*d50f8f33SHaojian Zhuang int ret; 120*d50f8f33SHaojian Zhuang 121*d50f8f33SHaojian Zhuang mutex_lock(&chip->io_lock); 122*d50f8f33SHaojian Zhuang ret = max8925_read_device(i2c, reg, 1, &value); 123*d50f8f33SHaojian Zhuang if (ret < 0) 124*d50f8f33SHaojian Zhuang goto out; 125*d50f8f33SHaojian Zhuang value &= ~mask; 126*d50f8f33SHaojian Zhuang value |= data; 127*d50f8f33SHaojian Zhuang ret = max8925_write_device(i2c, reg, 1, &value); 128*d50f8f33SHaojian Zhuang out: 129*d50f8f33SHaojian Zhuang mutex_unlock(&chip->io_lock); 130*d50f8f33SHaojian Zhuang return ret; 131*d50f8f33SHaojian Zhuang } 132*d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_set_bits); 133*d50f8f33SHaojian Zhuang 134*d50f8f33SHaojian Zhuang 135*d50f8f33SHaojian Zhuang static const struct i2c_device_id max8925_id_table[] = { 136*d50f8f33SHaojian Zhuang { "max8925", 0 }, 137*d50f8f33SHaojian Zhuang {} 138*d50f8f33SHaojian Zhuang }; 139*d50f8f33SHaojian Zhuang MODULE_DEVICE_TABLE(i2c, max8925_id_table); 140*d50f8f33SHaojian Zhuang 141*d50f8f33SHaojian Zhuang static int __devinit max8925_probe(struct i2c_client *client, 142*d50f8f33SHaojian Zhuang const struct i2c_device_id *id) 143*d50f8f33SHaojian Zhuang { 144*d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata = client->dev.platform_data; 145*d50f8f33SHaojian Zhuang struct max8925_chip *chip; 146*d50f8f33SHaojian Zhuang 147*d50f8f33SHaojian Zhuang if (!pdata) { 148*d50f8f33SHaojian Zhuang pr_info("%s: platform data is missing\n", __func__); 149*d50f8f33SHaojian Zhuang return -EINVAL; 150*d50f8f33SHaojian Zhuang } 151*d50f8f33SHaojian Zhuang if ((pdata->chip_id <= MAX8925_INVALID) 152*d50f8f33SHaojian Zhuang || (pdata->chip_id >= MAX8925_MAX)) { 153*d50f8f33SHaojian Zhuang pr_info("#%s: wrong chip identification\n", __func__); 154*d50f8f33SHaojian Zhuang return -EINVAL; 155*d50f8f33SHaojian Zhuang } 156*d50f8f33SHaojian Zhuang 157*d50f8f33SHaojian Zhuang chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL); 158*d50f8f33SHaojian Zhuang if (chip == NULL) 159*d50f8f33SHaojian Zhuang return -ENOMEM; 160*d50f8f33SHaojian Zhuang chip->i2c = client; 161*d50f8f33SHaojian Zhuang chip->chip_id = pdata->chip_id; 162*d50f8f33SHaojian Zhuang i2c_set_clientdata(client, chip); 163*d50f8f33SHaojian Zhuang chip->dev = &client->dev; 164*d50f8f33SHaojian Zhuang mutex_init(&chip->io_lock); 165*d50f8f33SHaojian Zhuang dev_set_drvdata(chip->dev, chip); 166*d50f8f33SHaojian Zhuang max8925_device_init(chip, pdata); 167*d50f8f33SHaojian Zhuang 168*d50f8f33SHaojian Zhuang return 0; 169*d50f8f33SHaojian Zhuang } 170*d50f8f33SHaojian Zhuang 171*d50f8f33SHaojian Zhuang static int __devexit max8925_remove(struct i2c_client *client) 172*d50f8f33SHaojian Zhuang { 173*d50f8f33SHaojian Zhuang struct max8925_chip *chip = i2c_get_clientdata(client); 174*d50f8f33SHaojian Zhuang 175*d50f8f33SHaojian Zhuang max8925_device_exit(chip); 176*d50f8f33SHaojian Zhuang i2c_set_clientdata(client, NULL); 177*d50f8f33SHaojian Zhuang kfree(chip); 178*d50f8f33SHaojian Zhuang return 0; 179*d50f8f33SHaojian Zhuang } 180*d50f8f33SHaojian Zhuang 181*d50f8f33SHaojian Zhuang static struct i2c_driver max8925_driver = { 182*d50f8f33SHaojian Zhuang .driver = { 183*d50f8f33SHaojian Zhuang .name = "max8925", 184*d50f8f33SHaojian Zhuang .owner = THIS_MODULE, 185*d50f8f33SHaojian Zhuang }, 186*d50f8f33SHaojian Zhuang .probe = max8925_probe, 187*d50f8f33SHaojian Zhuang .remove = __devexit_p(max8925_remove), 188*d50f8f33SHaojian Zhuang .id_table = max8925_id_table, 189*d50f8f33SHaojian Zhuang }; 190*d50f8f33SHaojian Zhuang 191*d50f8f33SHaojian Zhuang static int __init max8925_i2c_init(void) 192*d50f8f33SHaojian Zhuang { 193*d50f8f33SHaojian Zhuang int ret; 194*d50f8f33SHaojian Zhuang 195*d50f8f33SHaojian Zhuang ret = i2c_add_driver(&max8925_driver); 196*d50f8f33SHaojian Zhuang if (ret != 0) 197*d50f8f33SHaojian Zhuang pr_err("Failed to register MAX8925 I2C driver: %d\n", ret); 198*d50f8f33SHaojian Zhuang return ret; 199*d50f8f33SHaojian Zhuang } 200*d50f8f33SHaojian Zhuang subsys_initcall(max8925_i2c_init); 201*d50f8f33SHaojian Zhuang 202*d50f8f33SHaojian Zhuang static void __exit max8925_i2c_exit(void) 203*d50f8f33SHaojian Zhuang { 204*d50f8f33SHaojian Zhuang i2c_del_driver(&max8925_driver); 205*d50f8f33SHaojian Zhuang } 206*d50f8f33SHaojian Zhuang module_exit(max8925_i2c_exit); 207*d50f8f33SHaojian Zhuang 208*d50f8f33SHaojian Zhuang MODULE_DESCRIPTION("I2C Driver for Maxim 8925"); 209*d50f8f33SHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 210*d50f8f33SHaojian Zhuang MODULE_LICENSE("GPL"); 211