1e789995dSViresh Kumar /* 2e789995dSViresh Kumar * ST Microelectronics MFD: stmpe's spi client specific driver 3e789995dSViresh Kumar * 4e789995dSViresh Kumar * Copyright (C) ST Microelectronics SA 2011 5e789995dSViresh Kumar * 6e789995dSViresh Kumar * License Terms: GNU General Public License, version 2 710d8935fSViresh Kumar * Author: Viresh Kumar <viresh.linux@gmail.com> for ST Microelectronics 8e789995dSViresh Kumar */ 9e789995dSViresh Kumar 10e789995dSViresh Kumar #include <linux/spi/spi.h> 11e789995dSViresh Kumar #include <linux/interrupt.h> 12e789995dSViresh Kumar #include <linux/kernel.h> 13e789995dSViresh Kumar #include <linux/module.h> 141e955becSJavier Martinez Canillas #include <linux/of.h> 15e789995dSViresh Kumar #include <linux/types.h> 16e789995dSViresh Kumar #include "stmpe.h" 17e789995dSViresh Kumar 18e789995dSViresh Kumar #define READ_CMD (1 << 7) 19e789995dSViresh Kumar 20e789995dSViresh Kumar static int spi_reg_read(struct stmpe *stmpe, u8 reg) 21e789995dSViresh Kumar { 22e789995dSViresh Kumar struct spi_device *spi = stmpe->client; 23e789995dSViresh Kumar int status = spi_w8r16(spi, reg | READ_CMD); 24e789995dSViresh Kumar 25e789995dSViresh Kumar return (status < 0) ? status : status >> 8; 26e789995dSViresh Kumar } 27e789995dSViresh Kumar 28e789995dSViresh Kumar static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val) 29e789995dSViresh Kumar { 30e789995dSViresh Kumar struct spi_device *spi = stmpe->client; 31e789995dSViresh Kumar u16 cmd = (val << 8) | reg; 32e789995dSViresh Kumar 33e789995dSViresh Kumar return spi_write(spi, (const u8 *)&cmd, 2); 34e789995dSViresh Kumar } 35e789995dSViresh Kumar 36e789995dSViresh Kumar static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) 37e789995dSViresh Kumar { 38e789995dSViresh Kumar int ret, i; 39e789995dSViresh Kumar 40e789995dSViresh Kumar for (i = 0; i < length; i++) { 41e789995dSViresh Kumar ret = spi_reg_read(stmpe, reg + i); 42e789995dSViresh Kumar if (ret < 0) 43e789995dSViresh Kumar return ret; 44e789995dSViresh Kumar *(values + i) = ret; 45e789995dSViresh Kumar } 46e789995dSViresh Kumar 47e789995dSViresh Kumar return 0; 48e789995dSViresh Kumar } 49e789995dSViresh Kumar 50e789995dSViresh Kumar static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length, 51e789995dSViresh Kumar const u8 *values) 52e789995dSViresh Kumar { 53e789995dSViresh Kumar int ret = 0, i; 54e789995dSViresh Kumar 55e789995dSViresh Kumar for (i = length; i > 0; i--, reg++) { 56e789995dSViresh Kumar ret = spi_reg_write(stmpe, reg, *(values + i - 1)); 57e789995dSViresh Kumar if (ret < 0) 58e789995dSViresh Kumar return ret; 59e789995dSViresh Kumar } 60e789995dSViresh Kumar 61e789995dSViresh Kumar return ret; 62e789995dSViresh Kumar } 63e789995dSViresh Kumar 64e789995dSViresh Kumar static void spi_init(struct stmpe *stmpe) 65e789995dSViresh Kumar { 66e789995dSViresh Kumar struct spi_device *spi = stmpe->client; 67e789995dSViresh Kumar 68e789995dSViresh Kumar spi->bits_per_word = 8; 69e789995dSViresh Kumar 70e789995dSViresh Kumar /* This register is only present for stmpe811 */ 71e789995dSViresh Kumar if (stmpe->variant->id_val == 0x0811) 72e789995dSViresh Kumar spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode); 73e789995dSViresh Kumar 74e789995dSViresh Kumar if (spi_setup(spi) < 0) 75e789995dSViresh Kumar dev_dbg(&spi->dev, "spi_setup failed\n"); 76e789995dSViresh Kumar } 77e789995dSViresh Kumar 78e789995dSViresh Kumar static struct stmpe_client_info spi_ci = { 79e789995dSViresh Kumar .read_byte = spi_reg_read, 80e789995dSViresh Kumar .write_byte = spi_reg_write, 81e789995dSViresh Kumar .read_block = spi_block_read, 82e789995dSViresh Kumar .write_block = spi_block_write, 83e789995dSViresh Kumar .init = spi_init, 84e789995dSViresh Kumar }; 85e789995dSViresh Kumar 86f791be49SBill Pemberton static int 87e789995dSViresh Kumar stmpe_spi_probe(struct spi_device *spi) 88e789995dSViresh Kumar { 89e789995dSViresh Kumar const struct spi_device_id *id = spi_get_device_id(spi); 90e789995dSViresh Kumar 91e789995dSViresh Kumar /* don't exceed max specified rate - 1MHz - Limitation of STMPE */ 92e789995dSViresh Kumar if (spi->max_speed_hz > 1000000) { 93e789995dSViresh Kumar dev_dbg(&spi->dev, "f(sample) %d KHz?\n", 94e789995dSViresh Kumar (spi->max_speed_hz/1000)); 95e789995dSViresh Kumar return -EINVAL; 96e789995dSViresh Kumar } 97e789995dSViresh Kumar 98e789995dSViresh Kumar spi_ci.irq = spi->irq; 99e789995dSViresh Kumar spi_ci.client = spi; 100e789995dSViresh Kumar spi_ci.dev = &spi->dev; 101e789995dSViresh Kumar 102e789995dSViresh Kumar return stmpe_probe(&spi_ci, id->driver_data); 103e789995dSViresh Kumar } 104e789995dSViresh Kumar 1054740f73fSBill Pemberton static int stmpe_spi_remove(struct spi_device *spi) 106e789995dSViresh Kumar { 107e65ad41eSJingoo Han struct stmpe *stmpe = spi_get_drvdata(spi); 108e789995dSViresh Kumar 109e789995dSViresh Kumar return stmpe_remove(stmpe); 110e789995dSViresh Kumar } 111e789995dSViresh Kumar 1121e955becSJavier Martinez Canillas static const struct of_device_id stmpe_spi_of_match[] = { 1131e955becSJavier Martinez Canillas { .compatible = "st,stmpe610", }, 1141e955becSJavier Martinez Canillas { .compatible = "st,stmpe801", }, 1151e955becSJavier Martinez Canillas { .compatible = "st,stmpe811", }, 1161e955becSJavier Martinez Canillas { .compatible = "st,stmpe1601", }, 1171e955becSJavier Martinez Canillas { .compatible = "st,stmpe2401", }, 1181e955becSJavier Martinez Canillas { .compatible = "st,stmpe2403", }, 1191e955becSJavier Martinez Canillas { /* sentinel */ }, 1201e955becSJavier Martinez Canillas }; 1211e955becSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, stmpe_spi_of_match); 1221e955becSJavier Martinez Canillas 123e789995dSViresh Kumar static const struct spi_device_id stmpe_spi_id[] = { 1241cda2394SViresh Kumar { "stmpe610", STMPE610 }, 1257f7f4ea1SViresh Kumar { "stmpe801", STMPE801 }, 126e789995dSViresh Kumar { "stmpe811", STMPE811 }, 127e789995dSViresh Kumar { "stmpe1601", STMPE1601 }, 128e789995dSViresh Kumar { "stmpe2401", STMPE2401 }, 129e789995dSViresh Kumar { "stmpe2403", STMPE2403 }, 130e789995dSViresh Kumar { } 131e789995dSViresh Kumar }; 132e789995dSViresh Kumar MODULE_DEVICE_TABLE(spi, stmpe_id); 133e789995dSViresh Kumar 134e789995dSViresh Kumar static struct spi_driver stmpe_spi_driver = { 135e789995dSViresh Kumar .driver = { 136e789995dSViresh Kumar .name = "stmpe-spi", 1371e955becSJavier Martinez Canillas .of_match_table = of_match_ptr(stmpe_spi_of_match), 138e789995dSViresh Kumar .owner = THIS_MODULE, 139e789995dSViresh Kumar #ifdef CONFIG_PM 140e789995dSViresh Kumar .pm = &stmpe_dev_pm_ops, 141e789995dSViresh Kumar #endif 142e789995dSViresh Kumar }, 143e789995dSViresh Kumar .probe = stmpe_spi_probe, 14484449216SBill Pemberton .remove = stmpe_spi_remove, 145e789995dSViresh Kumar .id_table = stmpe_spi_id, 146e789995dSViresh Kumar }; 147e789995dSViresh Kumar 148e789995dSViresh Kumar static int __init stmpe_init(void) 149e789995dSViresh Kumar { 150e789995dSViresh Kumar return spi_register_driver(&stmpe_spi_driver); 151e789995dSViresh Kumar } 152e789995dSViresh Kumar subsys_initcall(stmpe_init); 153e789995dSViresh Kumar 154e789995dSViresh Kumar static void __exit stmpe_exit(void) 155e789995dSViresh Kumar { 156e789995dSViresh Kumar spi_unregister_driver(&stmpe_spi_driver); 157e789995dSViresh Kumar } 158e789995dSViresh Kumar module_exit(stmpe_exit); 159e789995dSViresh Kumar 160e789995dSViresh Kumar MODULE_LICENSE("GPL v2"); 161e789995dSViresh Kumar MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); 16210d8935fSViresh Kumar MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>"); 163