127c6750eSGraeme Gregory /* 227c6750eSGraeme Gregory * tps65910.c -- TI TPS6591x 327c6750eSGraeme Gregory * 427c6750eSGraeme Gregory * Copyright 2010 Texas Instruments Inc. 527c6750eSGraeme Gregory * 627c6750eSGraeme Gregory * Author: Graeme Gregory <gg@slimlogic.co.uk> 727c6750eSGraeme Gregory * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 827c6750eSGraeme Gregory * 927c6750eSGraeme Gregory * This program is free software; you can redistribute it and/or modify it 1027c6750eSGraeme Gregory * under the terms of the GNU General Public License as published by the 1127c6750eSGraeme Gregory * Free Software Foundation; either version 2 of the License, or (at your 1227c6750eSGraeme Gregory * option) any later version. 1327c6750eSGraeme Gregory * 1427c6750eSGraeme Gregory */ 1527c6750eSGraeme Gregory 1627c6750eSGraeme Gregory #include <linux/module.h> 1727c6750eSGraeme Gregory #include <linux/moduleparam.h> 1827c6750eSGraeme Gregory #include <linux/init.h> 1927c6750eSGraeme Gregory #include <linux/slab.h> 2027c6750eSGraeme Gregory #include <linux/i2c.h> 2127c6750eSGraeme Gregory #include <linux/gpio.h> 2227c6750eSGraeme Gregory #include <linux/mfd/core.h> 2327c6750eSGraeme Gregory #include <linux/mfd/tps65910.h> 2427c6750eSGraeme Gregory 2527c6750eSGraeme Gregory static struct mfd_cell tps65910s[] = { 2627c6750eSGraeme Gregory { 2727c6750eSGraeme Gregory .name = "tps65910-pmic", 2827c6750eSGraeme Gregory }, 2927c6750eSGraeme Gregory { 3027c6750eSGraeme Gregory .name = "tps65910-rtc", 3127c6750eSGraeme Gregory }, 3227c6750eSGraeme Gregory { 3327c6750eSGraeme Gregory .name = "tps65910-power", 3427c6750eSGraeme Gregory }, 3527c6750eSGraeme Gregory }; 3627c6750eSGraeme Gregory 3727c6750eSGraeme Gregory 3827c6750eSGraeme Gregory static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, 3927c6750eSGraeme Gregory int bytes, void *dest) 4027c6750eSGraeme Gregory { 4127c6750eSGraeme Gregory struct i2c_client *i2c = tps65910->i2c_client; 4227c6750eSGraeme Gregory struct i2c_msg xfer[2]; 4327c6750eSGraeme Gregory int ret; 4427c6750eSGraeme Gregory 4527c6750eSGraeme Gregory /* Write register */ 4627c6750eSGraeme Gregory xfer[0].addr = i2c->addr; 4727c6750eSGraeme Gregory xfer[0].flags = 0; 4827c6750eSGraeme Gregory xfer[0].len = 1; 4927c6750eSGraeme Gregory xfer[0].buf = ® 5027c6750eSGraeme Gregory 5127c6750eSGraeme Gregory /* Read data */ 5227c6750eSGraeme Gregory xfer[1].addr = i2c->addr; 5327c6750eSGraeme Gregory xfer[1].flags = I2C_M_RD; 5427c6750eSGraeme Gregory xfer[1].len = bytes; 5527c6750eSGraeme Gregory xfer[1].buf = dest; 5627c6750eSGraeme Gregory 5727c6750eSGraeme Gregory ret = i2c_transfer(i2c->adapter, xfer, 2); 5827c6750eSGraeme Gregory if (ret == 2) 5927c6750eSGraeme Gregory ret = 0; 6027c6750eSGraeme Gregory else if (ret >= 0) 6127c6750eSGraeme Gregory ret = -EIO; 6227c6750eSGraeme Gregory 6327c6750eSGraeme Gregory return ret; 6427c6750eSGraeme Gregory } 6527c6750eSGraeme Gregory 6627c6750eSGraeme Gregory static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, 6727c6750eSGraeme Gregory int bytes, void *src) 6827c6750eSGraeme Gregory { 6927c6750eSGraeme Gregory struct i2c_client *i2c = tps65910->i2c_client; 7027c6750eSGraeme Gregory /* we add 1 byte for device register */ 7127c6750eSGraeme Gregory u8 msg[TPS65910_MAX_REGISTER + 1]; 7227c6750eSGraeme Gregory int ret; 7327c6750eSGraeme Gregory 740514e9acSAxel Lin if (bytes > TPS65910_MAX_REGISTER) 7527c6750eSGraeme Gregory return -EINVAL; 7627c6750eSGraeme Gregory 7727c6750eSGraeme Gregory msg[0] = reg; 7827c6750eSGraeme Gregory memcpy(&msg[1], src, bytes); 7927c6750eSGraeme Gregory 8027c6750eSGraeme Gregory ret = i2c_master_send(i2c, msg, bytes + 1); 8127c6750eSGraeme Gregory if (ret < 0) 8227c6750eSGraeme Gregory return ret; 8327c6750eSGraeme Gregory if (ret != bytes + 1) 8427c6750eSGraeme Gregory return -EIO; 8527c6750eSGraeme Gregory return 0; 8627c6750eSGraeme Gregory } 8727c6750eSGraeme Gregory 8827c6750eSGraeme Gregory int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 8927c6750eSGraeme Gregory { 9027c6750eSGraeme Gregory u8 data; 9127c6750eSGraeme Gregory int err; 9227c6750eSGraeme Gregory 9327c6750eSGraeme Gregory mutex_lock(&tps65910->io_mutex); 9427c6750eSGraeme Gregory err = tps65910_i2c_read(tps65910, reg, 1, &data); 9527c6750eSGraeme Gregory if (err) { 9627c6750eSGraeme Gregory dev_err(tps65910->dev, "read from reg %x failed\n", reg); 9727c6750eSGraeme Gregory goto out; 9827c6750eSGraeme Gregory } 9927c6750eSGraeme Gregory 10027c6750eSGraeme Gregory data |= mask; 10127c6750eSGraeme Gregory err = tps65910_i2c_write(tps65910, reg, 1, &data); 10227c6750eSGraeme Gregory if (err) 10327c6750eSGraeme Gregory dev_err(tps65910->dev, "write to reg %x failed\n", reg); 10427c6750eSGraeme Gregory 10527c6750eSGraeme Gregory out: 10627c6750eSGraeme Gregory mutex_unlock(&tps65910->io_mutex); 10727c6750eSGraeme Gregory return err; 10827c6750eSGraeme Gregory } 10927c6750eSGraeme Gregory EXPORT_SYMBOL_GPL(tps65910_set_bits); 11027c6750eSGraeme Gregory 11127c6750eSGraeme Gregory int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) 11227c6750eSGraeme Gregory { 11327c6750eSGraeme Gregory u8 data; 11427c6750eSGraeme Gregory int err; 11527c6750eSGraeme Gregory 11627c6750eSGraeme Gregory mutex_lock(&tps65910->io_mutex); 11727c6750eSGraeme Gregory err = tps65910_i2c_read(tps65910, reg, 1, &data); 11827c6750eSGraeme Gregory if (err) { 11927c6750eSGraeme Gregory dev_err(tps65910->dev, "read from reg %x failed\n", reg); 12027c6750eSGraeme Gregory goto out; 12127c6750eSGraeme Gregory } 12227c6750eSGraeme Gregory 12327c6750eSGraeme Gregory data &= mask; 12427c6750eSGraeme Gregory err = tps65910_i2c_write(tps65910, reg, 1, &data); 12527c6750eSGraeme Gregory if (err) 12627c6750eSGraeme Gregory dev_err(tps65910->dev, "write to reg %x failed\n", reg); 12727c6750eSGraeme Gregory 12827c6750eSGraeme Gregory out: 12927c6750eSGraeme Gregory mutex_unlock(&tps65910->io_mutex); 13027c6750eSGraeme Gregory return err; 13127c6750eSGraeme Gregory } 13227c6750eSGraeme Gregory EXPORT_SYMBOL_GPL(tps65910_clear_bits); 13327c6750eSGraeme Gregory 13427c6750eSGraeme Gregory static int tps65910_i2c_probe(struct i2c_client *i2c, 13527c6750eSGraeme Gregory const struct i2c_device_id *id) 13627c6750eSGraeme Gregory { 13727c6750eSGraeme Gregory struct tps65910 *tps65910; 1382537df72SGraeme Gregory struct tps65910_board *pmic_plat_data; 139e3471bdcSGraeme Gregory struct tps65910_platform_data *init_data; 14027c6750eSGraeme Gregory int ret = 0; 14127c6750eSGraeme Gregory 1422537df72SGraeme Gregory pmic_plat_data = dev_get_platdata(&i2c->dev); 1432537df72SGraeme Gregory if (!pmic_plat_data) 1442537df72SGraeme Gregory return -EINVAL; 1452537df72SGraeme Gregory 146e3471bdcSGraeme Gregory init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); 147e3471bdcSGraeme Gregory if (init_data == NULL) 148e3471bdcSGraeme Gregory return -ENOMEM; 149e3471bdcSGraeme Gregory 15027c6750eSGraeme Gregory tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); 151dc7e412dSJesper Juhl if (tps65910 == NULL) { 152dc7e412dSJesper Juhl kfree(init_data); 15327c6750eSGraeme Gregory return -ENOMEM; 154dc7e412dSJesper Juhl } 15527c6750eSGraeme Gregory 15627c6750eSGraeme Gregory i2c_set_clientdata(i2c, tps65910); 15727c6750eSGraeme Gregory tps65910->dev = &i2c->dev; 15827c6750eSGraeme Gregory tps65910->i2c_client = i2c; 15979557056SJorge Eduardo Candelaria tps65910->id = id->driver_data; 16027c6750eSGraeme Gregory tps65910->read = tps65910_i2c_read; 16127c6750eSGraeme Gregory tps65910->write = tps65910_i2c_write; 16227c6750eSGraeme Gregory mutex_init(&tps65910->io_mutex); 16327c6750eSGraeme Gregory 16427c6750eSGraeme Gregory ret = mfd_add_devices(tps65910->dev, -1, 16527c6750eSGraeme Gregory tps65910s, ARRAY_SIZE(tps65910s), 16627c6750eSGraeme Gregory NULL, 0); 16727c6750eSGraeme Gregory if (ret < 0) 16827c6750eSGraeme Gregory goto err; 16927c6750eSGraeme Gregory 170*b1224cd1SJesper Juhl init_data->irq = pmic_plat_data->irq; 171*b1224cd1SJesper Juhl init_data->irq_base = pmic_plat_data->irq; 172*b1224cd1SJesper Juhl 1732537df72SGraeme Gregory tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); 1742537df72SGraeme Gregory 175e3471bdcSGraeme Gregory ret = tps65910_irq_init(tps65910, init_data->irq, init_data); 176e3471bdcSGraeme Gregory if (ret < 0) 177e3471bdcSGraeme Gregory goto err; 178e3471bdcSGraeme Gregory 179dc7e412dSJesper Juhl kfree(init_data); 18027c6750eSGraeme Gregory return ret; 18127c6750eSGraeme Gregory 18227c6750eSGraeme Gregory err: 18327c6750eSGraeme Gregory mfd_remove_devices(tps65910->dev); 18427c6750eSGraeme Gregory kfree(tps65910); 185dc7e412dSJesper Juhl kfree(init_data); 18627c6750eSGraeme Gregory return ret; 18727c6750eSGraeme Gregory } 18827c6750eSGraeme Gregory 18927c6750eSGraeme Gregory static int tps65910_i2c_remove(struct i2c_client *i2c) 19027c6750eSGraeme Gregory { 19127c6750eSGraeme Gregory struct tps65910 *tps65910 = i2c_get_clientdata(i2c); 19227c6750eSGraeme Gregory 19327c6750eSGraeme Gregory mfd_remove_devices(tps65910->dev); 194ec2328c3SMark Brown tps65910_irq_exit(tps65910); 19527c6750eSGraeme Gregory kfree(tps65910); 19627c6750eSGraeme Gregory 19727c6750eSGraeme Gregory return 0; 19827c6750eSGraeme Gregory } 19927c6750eSGraeme Gregory 20027c6750eSGraeme Gregory static const struct i2c_device_id tps65910_i2c_id[] = { 20179557056SJorge Eduardo Candelaria { "tps65910", TPS65910 }, 20279557056SJorge Eduardo Candelaria { "tps65911", TPS65911 }, 20327c6750eSGraeme Gregory { } 20427c6750eSGraeme Gregory }; 20527c6750eSGraeme Gregory MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id); 20627c6750eSGraeme Gregory 20727c6750eSGraeme Gregory 20827c6750eSGraeme Gregory static struct i2c_driver tps65910_i2c_driver = { 20927c6750eSGraeme Gregory .driver = { 21027c6750eSGraeme Gregory .name = "tps65910", 21127c6750eSGraeme Gregory .owner = THIS_MODULE, 21227c6750eSGraeme Gregory }, 21327c6750eSGraeme Gregory .probe = tps65910_i2c_probe, 21427c6750eSGraeme Gregory .remove = tps65910_i2c_remove, 21527c6750eSGraeme Gregory .id_table = tps65910_i2c_id, 21627c6750eSGraeme Gregory }; 21727c6750eSGraeme Gregory 21827c6750eSGraeme Gregory static int __init tps65910_i2c_init(void) 21927c6750eSGraeme Gregory { 22027c6750eSGraeme Gregory return i2c_add_driver(&tps65910_i2c_driver); 22127c6750eSGraeme Gregory } 22227c6750eSGraeme Gregory /* init early so consumer devices can complete system boot */ 22327c6750eSGraeme Gregory subsys_initcall(tps65910_i2c_init); 22427c6750eSGraeme Gregory 22527c6750eSGraeme Gregory static void __exit tps65910_i2c_exit(void) 22627c6750eSGraeme Gregory { 22727c6750eSGraeme Gregory i2c_del_driver(&tps65910_i2c_driver); 22827c6750eSGraeme Gregory } 22927c6750eSGraeme Gregory module_exit(tps65910_i2c_exit); 23027c6750eSGraeme Gregory 23127c6750eSGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); 23227c6750eSGraeme Gregory MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 23327c6750eSGraeme Gregory MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); 23427c6750eSGraeme Gregory MODULE_LICENSE("GPL"); 235