diff options
| author | Linus Walleij <linus.walleij@linaro.org> | 2016-03-09 05:40:37 -0500 |
|---|---|---|
| committer | Linus Walleij <linus.walleij@linaro.org> | 2016-03-09 05:40:37 -0500 |
| commit | 0bae2f17323a4630c487a9b77c37bebf407424af (patch) | |
| tree | fc1f71a0209ec61841a5acb65d59d147af3cc4fa /drivers/mfd | |
| parent | adf32eaa05323449b74b36f25b918583e2bdb6f1 (diff) | |
| parent | ca801a22f465eae39fadc770e15b5b7e82595f81 (diff) | |
Merge branch 'ib-mfd-regulator-gpio-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into devel
Diffstat (limited to 'drivers/mfd')
| -rw-r--r-- | drivers/mfd/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/mfd/Makefile | 3 | ||||
| -rw-r--r-- | drivers/mfd/tps65912-core.c | 240 | ||||
| -rw-r--r-- | drivers/mfd/tps65912-i2c.c | 162 | ||||
| -rw-r--r-- | drivers/mfd/tps65912-irq.c | 217 | ||||
| -rw-r--r-- | drivers/mfd/tps65912-spi.c | 160 |
6 files changed, 198 insertions, 604 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9ca66de0c1c1..1bc97c2761e4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -1181,27 +1181,25 @@ config MFD_TPS65910 | |||
| 1181 | Power Management chips. | 1181 | Power Management chips. |
| 1182 | 1182 | ||
| 1183 | config MFD_TPS65912 | 1183 | config MFD_TPS65912 |
| 1184 | bool "TI TPS65912 Power Management chip" | 1184 | tristate |
| 1185 | depends on GPIOLIB | ||
| 1186 | select MFD_CORE | 1185 | select MFD_CORE |
| 1187 | help | 1186 | select REGMAP |
| 1188 | If you say yes here you get support for the TPS65912 series of | 1187 | select REGMAP_IRQ |
| 1189 | PM chips. | ||
| 1190 | 1188 | ||
| 1191 | config MFD_TPS65912_I2C | 1189 | config MFD_TPS65912_I2C |
| 1192 | bool "TI TPS65912 Power Management chip with I2C" | 1190 | tristate "TI TPS65912 Power Management chip with I2C" |
| 1193 | select MFD_CORE | ||
| 1194 | select MFD_TPS65912 | 1191 | select MFD_TPS65912 |
| 1195 | depends on I2C=y && GPIOLIB | 1192 | select REGMAP_I2C |
| 1193 | depends on I2C | ||
| 1196 | help | 1194 | help |
| 1197 | If you say yes here you get support for the TPS65912 series of | 1195 | If you say yes here you get support for the TPS65912 series of |
| 1198 | PM chips with I2C interface. | 1196 | PM chips with I2C interface. |
| 1199 | 1197 | ||
| 1200 | config MFD_TPS65912_SPI | 1198 | config MFD_TPS65912_SPI |
| 1201 | bool "TI TPS65912 Power Management chip with SPI" | 1199 | tristate "TI TPS65912 Power Management chip with SPI" |
| 1202 | select MFD_CORE | ||
| 1203 | select MFD_TPS65912 | 1200 | select MFD_TPS65912 |
| 1204 | depends on SPI_MASTER && GPIOLIB | 1201 | select REGMAP_SPI |
| 1202 | depends on SPI_MASTER | ||
| 1205 | help | 1203 | help |
| 1206 | If you say yes here you get support for the TPS65912 series of | 1204 | If you say yes here you get support for the TPS65912 series of |
| 1207 | PM chips with SPI interface. | 1205 | PM chips with SPI interface. |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0f230a6103f8..1811202cee19 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
| @@ -73,8 +73,7 @@ obj-$(CONFIG_TPS6507X) += tps6507x.o | |||
| 73 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o | 73 | obj-$(CONFIG_MFD_TPS65217) += tps65217.o |
| 74 | obj-$(CONFIG_MFD_TPS65218) += tps65218.o | 74 | obj-$(CONFIG_MFD_TPS65218) += tps65218.o |
| 75 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o | 75 | obj-$(CONFIG_MFD_TPS65910) += tps65910.o |
| 76 | tps65912-objs := tps65912-core.o tps65912-irq.o | 76 | obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o |
| 77 | obj-$(CONFIG_MFD_TPS65912) += tps65912.o | ||
| 78 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o | 77 | obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o |
| 79 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o | 78 | obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o |
| 80 | obj-$(CONFIG_MFD_TPS80031) += tps80031.o | 79 | obj-$(CONFIG_MFD_TPS80031) += tps80031.o |
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 1f82d60b1d0f..a88cfa80dbc4 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c | |||
| @@ -1,175 +1,111 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * tps65912-core.c -- TI TPS65912x | 2 | * Core functions for TI TPS65912x PMICs |
| 3 | * | 3 | * |
| 4 | * Copyright 2011 Texas Instruments Inc. | 4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ |
| 5 | * Andrew F. Davis <afd@ti.com> | ||
| 5 | * | 6 | * |
| 6 | * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk> | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 7 | * | 10 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| 9 | * under the terms of the GNU General Public License as published by the | 12 | * kind, whether expressed or implied; without even the implied warranty |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * option) any later version. | 14 | * GNU General Public License version 2 for more details. |
| 12 | * | 15 | * |
| 13 | * This driver is based on wm8350 implementation. | 16 | * Based on the TPS65218 driver and the previous TPS65912 driver by |
| 17 | * Margarita Olaya Cabrera <magi@slimlogic.co.uk> | ||
| 14 | */ | 18 | */ |
| 15 | 19 | ||
| 16 | #include <linux/module.h> | 20 | #include <linux/interrupt.h> |
| 17 | #include <linux/moduleparam.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/gpio.h> | ||
| 20 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
| 22 | #include <linux/module.h> | ||
| 23 | |||
| 21 | #include <linux/mfd/tps65912.h> | 24 | #include <linux/mfd/tps65912.h> |
| 22 | 25 | ||
| 23 | static const struct mfd_cell tps65912s[] = { | 26 | static const struct mfd_cell tps65912_cells[] = { |
| 24 | { | 27 | { .name = "tps65912-regulator", }, |
| 25 | .name = "tps65912-pmic", | 28 | { .name = "tps65912-gpio", }, |
| 26 | }, | ||
| 27 | }; | 29 | }; |
| 28 | 30 | ||
| 29 | int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask) | 31 | static const struct regmap_irq tps65912_irqs[] = { |
| 30 | { | 32 | /* INT_STS IRQs */ |
| 31 | u8 data; | 33 | REGMAP_IRQ_REG(TPS65912_IRQ_PWRHOLD_F, 0, TPS65912_INT_STS_PWRHOLD_F), |
| 32 | int err; | 34 | REGMAP_IRQ_REG(TPS65912_IRQ_VMON, 0, TPS65912_INT_STS_VMON), |
| 33 | 35 | REGMAP_IRQ_REG(TPS65912_IRQ_PWRON, 0, TPS65912_INT_STS_PWRON), | |
| 34 | mutex_lock(&tps65912->io_mutex); | 36 | REGMAP_IRQ_REG(TPS65912_IRQ_PWRON_LP, 0, TPS65912_INT_STS_PWRON_LP), |
| 35 | 37 | REGMAP_IRQ_REG(TPS65912_IRQ_PWRHOLD_R, 0, TPS65912_INT_STS_PWRHOLD_R), | |
| 36 | err = tps65912->read(tps65912, reg, 1, &data); | 38 | REGMAP_IRQ_REG(TPS65912_IRQ_HOTDIE, 0, TPS65912_INT_STS_HOTDIE), |
| 37 | if (err) { | 39 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO1_R, 0, TPS65912_INT_STS_GPIO1_R), |
| 38 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | 40 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO1_F, 0, TPS65912_INT_STS_GPIO1_F), |
| 39 | goto out; | 41 | /* INT_STS2 IRQs */ |
| 40 | } | 42 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO2_R, 1, TPS65912_INT_STS2_GPIO2_R), |
| 41 | 43 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO2_F, 1, TPS65912_INT_STS2_GPIO2_F), | |
| 42 | data |= mask; | 44 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO3_R, 1, TPS65912_INT_STS2_GPIO3_R), |
| 43 | err = tps65912->write(tps65912, reg, 1, &data); | 45 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO3_F, 1, TPS65912_INT_STS2_GPIO3_F), |
| 44 | if (err) | 46 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO4_R, 1, TPS65912_INT_STS2_GPIO4_R), |
| 45 | dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg); | 47 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO4_F, 1, TPS65912_INT_STS2_GPIO4_F), |
| 48 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO5_R, 1, TPS65912_INT_STS2_GPIO5_R), | ||
| 49 | REGMAP_IRQ_REG(TPS65912_IRQ_GPIO5_F, 1, TPS65912_INT_STS2_GPIO5_F), | ||
| 50 | /* INT_STS3 IRQs */ | ||
| 51 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_DCDC1, 2, TPS65912_INT_STS3_PGOOD_DCDC1), | ||
| 52 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_DCDC2, 2, TPS65912_INT_STS3_PGOOD_DCDC2), | ||
| 53 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_DCDC3, 2, TPS65912_INT_STS3_PGOOD_DCDC3), | ||
| 54 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_DCDC4, 2, TPS65912_INT_STS3_PGOOD_DCDC4), | ||
| 55 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO1, 2, TPS65912_INT_STS3_PGOOD_LDO1), | ||
| 56 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO2, 2, TPS65912_INT_STS3_PGOOD_LDO2), | ||
| 57 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO3, 2, TPS65912_INT_STS3_PGOOD_LDO3), | ||
| 58 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO4, 2, TPS65912_INT_STS3_PGOOD_LDO4), | ||
| 59 | /* INT_STS4 IRQs */ | ||
| 60 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO5, 3, TPS65912_INT_STS4_PGOOD_LDO5), | ||
| 61 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO6, 3, TPS65912_INT_STS4_PGOOD_LDO6), | ||
| 62 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO7, 3, TPS65912_INT_STS4_PGOOD_LDO7), | ||
| 63 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO8, 3, TPS65912_INT_STS4_PGOOD_LDO8), | ||
| 64 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO9, 3, TPS65912_INT_STS4_PGOOD_LDO9), | ||
| 65 | REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO10, 3, TPS65912_INT_STS4_PGOOD_LDO10), | ||
| 66 | }; | ||
| 46 | 67 | ||
| 47 | out: | 68 | static struct regmap_irq_chip tps65912_irq_chip = { |
| 48 | mutex_unlock(&tps65912->io_mutex); | 69 | .name = "tps65912", |
| 49 | return err; | 70 | .irqs = tps65912_irqs, |
| 50 | } | 71 | .num_irqs = ARRAY_SIZE(tps65912_irqs), |
| 51 | EXPORT_SYMBOL_GPL(tps65912_set_bits); | 72 | .num_regs = 4, |
| 73 | .irq_reg_stride = 2, | ||
| 74 | .mask_base = TPS65912_INT_MSK, | ||
| 75 | .status_base = TPS65912_INT_STS, | ||
| 76 | .ack_base = TPS65912_INT_STS, | ||
| 77 | .init_ack_masked = true, | ||
| 78 | }; | ||
| 52 | 79 | ||
| 53 | int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask) | 80 | int tps65912_device_init(struct tps65912 *tps) |
| 54 | { | 81 | { |
| 55 | u8 data; | 82 | int ret; |
| 56 | int err; | 83 | |
| 57 | 84 | ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0, | |
| 58 | mutex_lock(&tps65912->io_mutex); | 85 | &tps65912_irq_chip, &tps->irq_data); |
| 59 | err = tps65912->read(tps65912, reg, 1, &data); | 86 | if (ret) |
| 60 | if (err) { | 87 | return ret; |
| 61 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | 88 | |
| 62 | goto out; | 89 | ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65912_cells, |
| 90 | ARRAY_SIZE(tps65912_cells), NULL, 0, | ||
| 91 | regmap_irq_get_domain(tps->irq_data)); | ||
| 92 | if (ret) { | ||
| 93 | regmap_del_irq_chip(tps->irq, tps->irq_data); | ||
| 94 | return ret; | ||
| 63 | } | 95 | } |
| 64 | 96 | ||
| 65 | data &= ~mask; | 97 | return 0; |
| 66 | err = tps65912->write(tps65912, reg, 1, &data); | ||
| 67 | if (err) | ||
| 68 | dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg); | ||
| 69 | |||
| 70 | out: | ||
| 71 | mutex_unlock(&tps65912->io_mutex); | ||
| 72 | return err; | ||
| 73 | } | 98 | } |
| 74 | EXPORT_SYMBOL_GPL(tps65912_clear_bits); | 99 | EXPORT_SYMBOL_GPL(tps65912_device_init); |
| 75 | 100 | ||
| 76 | static inline int tps65912_read(struct tps65912 *tps65912, u8 reg) | 101 | int tps65912_device_exit(struct tps65912 *tps) |
| 77 | { | 102 | { |
| 78 | u8 val; | 103 | regmap_del_irq_chip(tps->irq, tps->irq_data); |
| 79 | int err; | ||
| 80 | |||
| 81 | err = tps65912->read(tps65912, reg, 1, &val); | ||
| 82 | if (err < 0) | ||
| 83 | return err; | ||
| 84 | |||
| 85 | return val; | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline int tps65912_write(struct tps65912 *tps65912, u8 reg, u8 val) | ||
| 89 | { | ||
| 90 | return tps65912->write(tps65912, reg, 1, &val); | ||
| 91 | } | ||
| 92 | |||
| 93 | int tps65912_reg_read(struct tps65912 *tps65912, u8 reg) | ||
| 94 | { | ||
| 95 | int data; | ||
| 96 | |||
| 97 | mutex_lock(&tps65912->io_mutex); | ||
| 98 | 104 | ||
| 99 | data = tps65912_read(tps65912, reg); | 105 | return 0; |
| 100 | if (data < 0) | ||
| 101 | dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg); | ||
| 102 | |||
| 103 | mutex_unlock(&tps65912->io_mutex); | ||
| 104 | return data; | ||
| 105 | } | ||
| 106 | EXPORT_SYMBOL_GPL(tps65912_reg_read); | ||
| 107 | |||
| 108 | int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val) | ||
| 109 | { | ||
| 110 | int err; | ||
| 111 | |||
| 112 | mutex_lock(&tps65912->io_mutex); | ||
| 113 | |||
| 114 | err = tps65912_write(tps65912, reg, val); | ||
| 115 | if (err < 0) | ||
| 116 | dev_err(tps65912->dev, "Write for reg 0x%x failed\n", reg); | ||
| 117 | |||
| 118 | mutex_unlock(&tps65912->io_mutex); | ||
| 119 | return err; | ||
| 120 | } | ||
| 121 | EXPORT_SYMBOL_GPL(tps65912_reg_write); | ||
| 122 | |||
| 123 | int tps65912_device_init(struct tps65912 *tps65912) | ||
| 124 | { | ||
| 125 | struct tps65912_board *pmic_plat_data = dev_get_platdata(tps65912->dev); | ||
| 126 | struct tps65912_platform_data *init_data; | ||
| 127 | int ret, dcdc_avs, value; | ||
| 128 | |||
| 129 | init_data = kzalloc(sizeof(struct tps65912_platform_data), GFP_KERNEL); | ||
| 130 | if (init_data == NULL) | ||
| 131 | return -ENOMEM; | ||
| 132 | |||
| 133 | mutex_init(&tps65912->io_mutex); | ||
| 134 | dev_set_drvdata(tps65912->dev, tps65912); | ||
| 135 | |||
| 136 | dcdc_avs = (pmic_plat_data->is_dcdc1_avs << 0 | | ||
| 137 | pmic_plat_data->is_dcdc2_avs << 1 | | ||
| 138 | pmic_plat_data->is_dcdc3_avs << 2 | | ||
| 139 | pmic_plat_data->is_dcdc4_avs << 3); | ||
| 140 | if (dcdc_avs) { | ||
| 141 | tps65912->read(tps65912, TPS65912_I2C_SPI_CFG, 1, &value); | ||
| 142 | dcdc_avs |= value; | ||
| 143 | tps65912->write(tps65912, TPS65912_I2C_SPI_CFG, 1, &dcdc_avs); | ||
| 144 | } | ||
| 145 | |||
| 146 | ret = mfd_add_devices(tps65912->dev, -1, | ||
| 147 | tps65912s, ARRAY_SIZE(tps65912s), | ||
| 148 | NULL, 0, NULL); | ||
| 149 | if (ret < 0) | ||
| 150 | goto err; | ||
| 151 | |||
| 152 | init_data->irq = pmic_plat_data->irq; | ||
| 153 | init_data->irq_base = pmic_plat_data->irq_base; | ||
| 154 | ret = tps65912_irq_init(tps65912, init_data->irq, init_data); | ||
| 155 | if (ret < 0) | ||
| 156 | goto err; | ||
| 157 | |||
| 158 | kfree(init_data); | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | err: | ||
| 162 | kfree(init_data); | ||
| 163 | mfd_remove_devices(tps65912->dev); | ||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | void tps65912_device_exit(struct tps65912 *tps65912) | ||
| 168 | { | ||
| 169 | mfd_remove_devices(tps65912->dev); | ||
| 170 | tps65912_irq_exit(tps65912); | ||
| 171 | } | 106 | } |
| 107 | EXPORT_SYMBOL_GPL(tps65912_device_exit); | ||
| 172 | 108 | ||
| 173 | MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>"); | 109 | MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); |
| 174 | MODULE_DESCRIPTION("TPS65912x chip family multi-function driver"); | 110 | MODULE_DESCRIPTION("TPS65912x MFD Driver"); |
| 175 | MODULE_LICENSE("GPL"); | 111 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 7e55640b3ed5..45871403f995 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c | |||
| @@ -1,139 +1,79 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * tps65912-i2c.c -- I2C access for TI TPS65912x PMIC | 2 | * I2C access driver for TI TPS65912x PMICs |
| 3 | * | 3 | * |
| 4 | * Copyright 2011 Texas Instruments Inc. | 4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ |
| 5 | * Andrew F. Davis <afd@ti.com> | ||
| 5 | * | 6 | * |
| 6 | * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk> | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 7 | * | 10 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| 9 | * under the terms of the GNU General Public License as published by the | 12 | * kind, whether expressed or implied; without even the implied warranty |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * option) any later version. | 14 | * GNU General Public License version 2 for more details. |
| 12 | * | 15 | * |
| 13 | * This driver is based on wm8350 implementation. | 16 | * Based on the TPS65218 driver and the previous TPS65912 driver by |
| 17 | * Margarita Olaya Cabrera <magi@slimlogic.co.uk> | ||
| 14 | */ | 18 | */ |
| 15 | 19 | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/moduleparam.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/gpio.h> | ||
| 21 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 22 | #include <linux/mfd/core.h> | 21 | #include <linux/module.h> |
| 23 | #include <linux/mfd/tps65912.h> | 22 | #include <linux/regmap.h> |
| 24 | |||
| 25 | static int tps65912_i2c_read(struct tps65912 *tps65912, u8 reg, | ||
| 26 | int bytes, void *dest) | ||
| 27 | { | ||
| 28 | struct i2c_client *i2c = tps65912->control_data; | ||
| 29 | struct i2c_msg xfer[2]; | ||
| 30 | int ret; | ||
| 31 | |||
| 32 | /* Write register */ | ||
| 33 | xfer[0].addr = i2c->addr; | ||
| 34 | xfer[0].flags = 0; | ||
| 35 | xfer[0].len = 1; | ||
| 36 | xfer[0].buf = ® | ||
| 37 | |||
| 38 | /* Read data */ | ||
| 39 | xfer[1].addr = i2c->addr; | ||
| 40 | xfer[1].flags = I2C_M_RD; | ||
| 41 | xfer[1].len = bytes; | ||
| 42 | xfer[1].buf = dest; | ||
| 43 | |||
| 44 | ret = i2c_transfer(i2c->adapter, xfer, 2); | ||
| 45 | if (ret == 2) | ||
| 46 | ret = 0; | ||
| 47 | else if (ret >= 0) | ||
| 48 | ret = -EIO; | ||
| 49 | return ret; | ||
| 50 | } | ||
| 51 | |||
| 52 | static int tps65912_i2c_write(struct tps65912 *tps65912, u8 reg, | ||
| 53 | int bytes, void *src) | ||
| 54 | { | ||
| 55 | struct i2c_client *i2c = tps65912->control_data; | ||
| 56 | /* we add 1 byte for device register */ | ||
| 57 | u8 msg[TPS6591X_MAX_REGISTER + 1]; | ||
| 58 | int ret; | ||
| 59 | |||
| 60 | if (bytes > TPS6591X_MAX_REGISTER) | ||
| 61 | return -EINVAL; | ||
| 62 | |||
| 63 | msg[0] = reg; | ||
| 64 | memcpy(&msg[1], src, bytes); | ||
| 65 | 23 | ||
| 66 | ret = i2c_master_send(i2c, msg, bytes + 1); | 24 | #include <linux/mfd/tps65912.h> |
| 67 | if (ret < 0) | ||
| 68 | return ret; | ||
| 69 | if (ret != bytes + 1) | ||
| 70 | return -EIO; | ||
| 71 | 25 | ||
| 72 | return 0; | 26 | static const struct of_device_id tps65912_i2c_of_match_table[] = { |
| 73 | } | 27 | { .compatible = "ti,tps65912", }, |
| 28 | { /* sentinel */ } | ||
| 29 | }; | ||
| 74 | 30 | ||
| 75 | static int tps65912_i2c_probe(struct i2c_client *i2c, | 31 | static int tps65912_i2c_probe(struct i2c_client *client, |
| 76 | const struct i2c_device_id *id) | 32 | const struct i2c_device_id *ids) |
| 77 | { | 33 | { |
| 78 | struct tps65912 *tps65912; | 34 | struct tps65912 *tps; |
| 79 | 35 | ||
| 80 | tps65912 = devm_kzalloc(&i2c->dev, | 36 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); |
| 81 | sizeof(struct tps65912), GFP_KERNEL); | 37 | if (!tps) |
| 82 | if (tps65912 == NULL) | ||
| 83 | return -ENOMEM; | 38 | return -ENOMEM; |
| 84 | 39 | ||
| 85 | i2c_set_clientdata(i2c, tps65912); | 40 | i2c_set_clientdata(client, tps); |
| 86 | tps65912->dev = &i2c->dev; | 41 | tps->dev = &client->dev; |
| 87 | tps65912->control_data = i2c; | 42 | tps->irq = client->irq; |
| 88 | tps65912->read = tps65912_i2c_read; | 43 | |
| 89 | tps65912->write = tps65912_i2c_write; | 44 | tps->regmap = devm_regmap_init_i2c(client, &tps65912_regmap_config); |
| 45 | if (IS_ERR(tps->regmap)) { | ||
| 46 | dev_err(tps->dev, "Failed to initialize register map\n"); | ||
| 47 | return PTR_ERR(tps->regmap); | ||
| 48 | } | ||
| 90 | 49 | ||
| 91 | return tps65912_device_init(tps65912); | 50 | return tps65912_device_init(tps); |
| 92 | } | 51 | } |
| 93 | 52 | ||
| 94 | static int tps65912_i2c_remove(struct i2c_client *i2c) | 53 | static int tps65912_i2c_remove(struct i2c_client *client) |
| 95 | { | 54 | { |
| 96 | struct tps65912 *tps65912 = i2c_get_clientdata(i2c); | 55 | struct tps65912 *tps = i2c_get_clientdata(client); |
| 97 | 56 | ||
| 98 | tps65912_device_exit(tps65912); | 57 | return tps65912_device_exit(tps); |
| 99 | |||
| 100 | return 0; | ||
| 101 | } | 58 | } |
| 102 | 59 | ||
| 103 | static const struct i2c_device_id tps65912_i2c_id[] = { | 60 | static const struct i2c_device_id tps65912_i2c_id_table[] = { |
| 104 | {"tps65912", 0 }, | 61 | { "tps65912", 0 }, |
| 105 | { } | 62 | { /* sentinel */ } |
| 106 | }; | 63 | }; |
| 107 | MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id); | 64 | MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id_table); |
| 108 | 65 | ||
| 109 | static struct i2c_driver tps65912_i2c_driver = { | 66 | static struct i2c_driver tps65912_i2c_driver = { |
| 110 | .driver = { | 67 | .driver = { |
| 111 | .name = "tps65912", | 68 | .name = "tps65912", |
| 69 | .of_match_table = tps65912_i2c_of_match_table, | ||
| 112 | }, | 70 | }, |
| 113 | .probe = tps65912_i2c_probe, | 71 | .probe = tps65912_i2c_probe, |
| 114 | .remove = tps65912_i2c_remove, | 72 | .remove = tps65912_i2c_remove, |
| 115 | .id_table = tps65912_i2c_id, | 73 | .id_table = tps65912_i2c_id_table, |
| 116 | }; | 74 | }; |
| 75 | module_i2c_driver(tps65912_i2c_driver); | ||
| 117 | 76 | ||
| 118 | static int __init tps65912_i2c_init(void) | 77 | MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); |
| 119 | { | 78 | MODULE_DESCRIPTION("TPS65912x I2C Interface Driver"); |
| 120 | int ret; | 79 | MODULE_LICENSE("GPL v2"); |
| 121 | |||
| 122 | ret = i2c_add_driver(&tps65912_i2c_driver); | ||
| 123 | if (ret != 0) | ||
| 124 | pr_err("Failed to register TPS65912 I2C driver: %d\n", ret); | ||
| 125 | |||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | /* init early so consumer devices can complete system boot */ | ||
| 129 | subsys_initcall(tps65912_i2c_init); | ||
| 130 | |||
| 131 | static void __exit tps65912_i2c_exit(void) | ||
| 132 | { | ||
| 133 | i2c_del_driver(&tps65912_i2c_driver); | ||
| 134 | } | ||
| 135 | module_exit(tps65912_i2c_exit); | ||
| 136 | |||
| 137 | MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>"); | ||
| 138 | MODULE_DESCRIPTION("TPS6591x chip family multi-function driver"); | ||
| 139 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/tps65912-irq.c b/drivers/mfd/tps65912-irq.c deleted file mode 100644 index db2c29cb709b..000000000000 --- a/drivers/mfd/tps65912-irq.c +++ /dev/null | |||
| @@ -1,217 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * tps65912-irq.c -- TI TPS6591x | ||
| 3 | * | ||
| 4 | * Copyright 2011 Texas Instruments Inc. | ||
| 5 | * | ||
| 6 | * Author: Margarita Olaya <magi@slimlogic.co.uk> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the | ||
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 11 | * option) any later version. | ||
| 12 | * | ||
| 13 | * This driver is based on wm8350 implementation. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/bug.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/irq.h> | ||
| 22 | #include <linux/gpio.h> | ||
| 23 | #include <linux/mfd/tps65912.h> | ||
| 24 | |||
| 25 | static inline int irq_to_tps65912_irq(struct tps65912 *tps65912, | ||
| 26 | int irq) | ||
| 27 | { | ||
| 28 | return irq - tps65912->irq_base; | ||
| 29 | } | ||
| 30 | |||
| 31 | /* | ||
| 32 | * This is a threaded IRQ handler so can access I2C/SPI. Since the | ||
| 33 | * IRQ handler explicitly clears the IRQ it handles the IRQ line | ||
| 34 | * will be reasserted and the physical IRQ will be handled again if | ||
| 35 | * another interrupt is asserted while we run - in the normal course | ||
| 36 | * of events this is a rare occurrence so we save I2C/SPI reads. We're | ||
| 37 | * also assuming that it's rare to get lots of interrupts firing | ||
| 38 | * simultaneously so try to minimise I/O. | ||
| 39 | */ | ||
| 40 | static irqreturn_t tps65912_irq(int irq, void *irq_data) | ||
| 41 | { | ||
| 42 | struct tps65912 *tps65912 = irq_data; | ||
| 43 | u32 irq_sts; | ||
| 44 | u32 irq_mask; | ||
| 45 | u8 reg; | ||
| 46 | int i; | ||
| 47 | |||
| 48 | |||
| 49 | tps65912->read(tps65912, TPS65912_INT_STS, 1, ®); | ||
| 50 | irq_sts = reg; | ||
| 51 | tps65912->read(tps65912, TPS65912_INT_STS2, 1, ®); | ||
| 52 | irq_sts |= reg << 8; | ||
| 53 | tps65912->read(tps65912, TPS65912_INT_STS3, 1, ®); | ||
| 54 | irq_sts |= reg << 16; | ||
| 55 | tps65912->read(tps65912, TPS65912_INT_STS4, 1, ®); | ||
| 56 | irq_sts |= reg << 24; | ||
| 57 | |||
| 58 | tps65912->read(tps65912, TPS65912_INT_MSK, 1, ®); | ||
| 59 | irq_mask = reg; | ||
| 60 | tps65912->read(tps65912, TPS65912_INT_MSK2, 1, ®); | ||
| 61 | irq_mask |= reg << 8; | ||
| 62 | tps65912->read(tps65912, TPS65912_INT_MSK3, 1, ®); | ||
| 63 | irq_mask |= reg << 16; | ||
| 64 | tps65912->read(tps65912, TPS65912_INT_MSK4, 1, ®); | ||
| 65 | irq_mask |= reg << 24; | ||
| 66 | |||
| 67 | irq_sts &= ~irq_mask; | ||
| 68 | if (!irq_sts) | ||
| 69 | return IRQ_NONE; | ||
| 70 | |||
| 71 | for (i = 0; i < tps65912->irq_num; i++) { | ||
| 72 | if (!(irq_sts & (1 << i))) | ||
| 73 | continue; | ||
| 74 | |||
| 75 | handle_nested_irq(tps65912->irq_base + i); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* Write the STS register back to clear IRQs we handled */ | ||
| 79 | reg = irq_sts & 0xFF; | ||
| 80 | irq_sts >>= 8; | ||
| 81 | if (reg) | ||
| 82 | tps65912->write(tps65912, TPS65912_INT_STS, 1, ®); | ||
| 83 | reg = irq_sts & 0xFF; | ||
| 84 | irq_sts >>= 8; | ||
| 85 | if (reg) | ||
| 86 | tps65912->write(tps65912, TPS65912_INT_STS2, 1, ®); | ||
| 87 | reg = irq_sts & 0xFF; | ||
| 88 | irq_sts >>= 8; | ||
| 89 | if (reg) | ||
| 90 | tps65912->write(tps65912, TPS65912_INT_STS3, 1, ®); | ||
| 91 | reg = irq_sts & 0xFF; | ||
| 92 | if (reg) | ||
| 93 | tps65912->write(tps65912, TPS65912_INT_STS4, 1, ®); | ||
| 94 | |||
| 95 | return IRQ_HANDLED; | ||
| 96 | } | ||
| 97 | |||
| 98 | static void tps65912_irq_lock(struct irq_data *data) | ||
| 99 | { | ||
| 100 | struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); | ||
| 101 | |||
| 102 | mutex_lock(&tps65912->irq_lock); | ||
| 103 | } | ||
| 104 | |||
| 105 | static void tps65912_irq_sync_unlock(struct irq_data *data) | ||
| 106 | { | ||
| 107 | struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); | ||
| 108 | u32 reg_mask; | ||
| 109 | u8 reg; | ||
| 110 | |||
| 111 | tps65912->read(tps65912, TPS65912_INT_MSK, 1, ®); | ||
| 112 | reg_mask = reg; | ||
| 113 | tps65912->read(tps65912, TPS65912_INT_MSK2, 1, ®); | ||
| 114 | reg_mask |= reg << 8; | ||
| 115 | tps65912->read(tps65912, TPS65912_INT_MSK3, 1, ®); | ||
| 116 | reg_mask |= reg << 16; | ||
| 117 | tps65912->read(tps65912, TPS65912_INT_MSK4, 1, ®); | ||
| 118 | reg_mask |= reg << 24; | ||
| 119 | |||
| 120 | if (tps65912->irq_mask != reg_mask) { | ||
| 121 | reg = tps65912->irq_mask & 0xFF; | ||
| 122 | tps65912->write(tps65912, TPS65912_INT_MSK, 1, ®); | ||
| 123 | reg = tps65912->irq_mask >> 8 & 0xFF; | ||
| 124 | tps65912->write(tps65912, TPS65912_INT_MSK2, 1, ®); | ||
| 125 | reg = tps65912->irq_mask >> 16 & 0xFF; | ||
| 126 | tps65912->write(tps65912, TPS65912_INT_MSK3, 1, ®); | ||
| 127 | reg = tps65912->irq_mask >> 24 & 0xFF; | ||
| 128 | tps65912->write(tps65912, TPS65912_INT_MSK4, 1, ®); | ||
| 129 | } | ||
| 130 | |||
| 131 | mutex_unlock(&tps65912->irq_lock); | ||
| 132 | } | ||
| 133 | |||
| 134 | static void tps65912_irq_enable(struct irq_data *data) | ||
| 135 | { | ||
| 136 | struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); | ||
| 137 | |||
| 138 | tps65912->irq_mask &= ~(1 << irq_to_tps65912_irq(tps65912, data->irq)); | ||
| 139 | } | ||
| 140 | |||
| 141 | static void tps65912_irq_disable(struct irq_data *data) | ||
| 142 | { | ||
| 143 | struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); | ||
| 144 | |||
| 145 | tps65912->irq_mask |= (1 << irq_to_tps65912_irq(tps65912, data->irq)); | ||
| 146 | } | ||
| 147 | |||
| 148 | static struct irq_chip tps65912_irq_chip = { | ||
| 149 | .name = "tps65912", | ||
| 150 | .irq_bus_lock = tps65912_irq_lock, | ||
| 151 | .irq_bus_sync_unlock = tps65912_irq_sync_unlock, | ||
| 152 | .irq_disable = tps65912_irq_disable, | ||
| 153 | .irq_enable = tps65912_irq_enable, | ||
| 154 | }; | ||
| 155 | |||
| 156 | int tps65912_irq_init(struct tps65912 *tps65912, int irq, | ||
| 157 | struct tps65912_platform_data *pdata) | ||
| 158 | { | ||
| 159 | int ret, cur_irq; | ||
| 160 | int flags = IRQF_ONESHOT; | ||
| 161 | u8 reg; | ||
| 162 | |||
| 163 | if (!irq) { | ||
| 164 | dev_warn(tps65912->dev, "No interrupt support, no core IRQ\n"); | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (!pdata || !pdata->irq_base) { | ||
| 169 | dev_warn(tps65912->dev, "No interrupt support, no IRQ base\n"); | ||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* Clear unattended interrupts */ | ||
| 174 | tps65912->read(tps65912, TPS65912_INT_STS, 1, ®); | ||
| 175 | tps65912->write(tps65912, TPS65912_INT_STS, 1, ®); | ||
| 176 | tps65912->read(tps65912, TPS65912_INT_STS2, 1, ®); | ||
| 177 | tps65912->write(tps65912, TPS65912_INT_STS2, 1, ®); | ||
| 178 | tps65912->read(tps65912, TPS65912_INT_STS3, 1, ®); | ||
| 179 | tps65912->write(tps65912, TPS65912_INT_STS3, 1, ®); | ||
| 180 | tps65912->read(tps65912, TPS65912_INT_STS4, 1, ®); | ||
| 181 | tps65912->write(tps65912, TPS65912_INT_STS4, 1, ®); | ||
| 182 | |||
| 183 | /* Mask top level interrupts */ | ||
| 184 | tps65912->irq_mask = 0xFFFFFFFF; | ||
| 185 | |||
| 186 | mutex_init(&tps65912->irq_lock); | ||
| 187 | tps65912->chip_irq = irq; | ||
| 188 | tps65912->irq_base = pdata->irq_base; | ||
| 189 | |||
| 190 | tps65912->irq_num = TPS65912_NUM_IRQ; | ||
| 191 | |||
| 192 | /* Register with genirq */ | ||
| 193 | for (cur_irq = tps65912->irq_base; | ||
| 194 | cur_irq < tps65912->irq_num + tps65912->irq_base; | ||
| 195 | cur_irq++) { | ||
| 196 | irq_set_chip_data(cur_irq, tps65912); | ||
| 197 | irq_set_chip_and_handler(cur_irq, &tps65912_irq_chip, | ||
| 198 | handle_edge_irq); | ||
| 199 | irq_set_nested_thread(cur_irq, 1); | ||
| 200 | irq_clear_status_flags(cur_irq, IRQ_NOREQUEST | IRQ_NOPROBE); | ||
| 201 | } | ||
| 202 | |||
| 203 | ret = request_threaded_irq(irq, NULL, tps65912_irq, flags, | ||
| 204 | "tps65912", tps65912); | ||
| 205 | |||
| 206 | irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | ||
| 207 | if (ret != 0) | ||
| 208 | dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret); | ||
| 209 | |||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | int tps65912_irq_exit(struct tps65912 *tps65912) | ||
| 214 | { | ||
| 215 | free_irq(tps65912->chip_irq, tps65912); | ||
| 216 | return 0; | ||
| 217 | } | ||
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index d59aa55b1495..4aeba9b6942a 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c | |||
| @@ -1,140 +1,78 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * tps65912-spi.c -- SPI access for TI TPS65912x PMIC | 2 | * SPI access driver for TI TPS65912x PMICs |
| 3 | * | 3 | * |
| 4 | * Copyright 2011 Texas Instruments Inc. | 4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ |
| 5 | * Andrew F. Davis <afd@ti.com> | ||
| 5 | * | 6 | * |
| 6 | * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk> | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 7 | * | 10 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| 9 | * under the terms of the GNU General Public License as published by the | 12 | * kind, whether expressed or implied; without even the implied warranty |
| 10 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * option) any later version. | 14 | * GNU General Public License version 2 for more details. |
| 12 | * | 15 | * |
| 13 | * This driver is based on wm8350 implementation. | 16 | * Based on the TPS65218 driver and the previous TPS65912 driver by |
| 17 | * Margarita Olaya Cabrera <magi@slimlogic.co.uk> | ||
| 14 | */ | 18 | */ |
| 15 | 19 | ||
| 16 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 17 | #include <linux/moduleparam.h> | 21 | #include <linux/regmap.h> |
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/gpio.h> | ||
| 21 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
| 22 | #include <linux/mfd/core.h> | ||
| 23 | #include <linux/mfd/tps65912.h> | ||
| 24 | |||
| 25 | static int tps65912_spi_write(struct tps65912 *tps65912, u8 addr, | ||
| 26 | int bytes, void *src) | ||
| 27 | { | ||
| 28 | struct spi_device *spi = tps65912->control_data; | ||
| 29 | u8 *data = (u8 *) src; | ||
| 30 | int ret; | ||
| 31 | /* bit 23 is the read/write bit */ | ||
| 32 | unsigned long spi_data = 1 << 23 | addr << 15 | *data; | ||
| 33 | struct spi_transfer xfer; | ||
| 34 | struct spi_message msg; | ||
| 35 | u32 tx_buf; | ||
| 36 | |||
| 37 | tx_buf = spi_data; | ||
| 38 | |||
| 39 | xfer.tx_buf = &tx_buf; | ||
| 40 | xfer.rx_buf = NULL; | ||
| 41 | xfer.len = sizeof(unsigned long); | ||
| 42 | xfer.bits_per_word = 24; | ||
| 43 | |||
| 44 | spi_message_init(&msg); | ||
| 45 | spi_message_add_tail(&xfer, &msg); | ||
| 46 | |||
| 47 | ret = spi_sync(spi, &msg); | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | static int tps65912_spi_read(struct tps65912 *tps65912, u8 addr, | ||
| 52 | int bytes, void *dest) | ||
| 53 | { | ||
| 54 | struct spi_device *spi = tps65912->control_data; | ||
| 55 | /* bit 23 is the read/write bit */ | ||
| 56 | unsigned long spi_data = 0 << 23 | addr << 15; | ||
| 57 | struct spi_transfer xfer; | ||
| 58 | struct spi_message msg; | ||
| 59 | int ret; | ||
| 60 | u8 *data = (u8 *) dest; | ||
| 61 | u32 tx_buf, rx_buf; | ||
| 62 | |||
| 63 | tx_buf = spi_data; | ||
| 64 | rx_buf = 0; | ||
| 65 | 23 | ||
| 66 | xfer.tx_buf = &tx_buf; | 24 | #include <linux/mfd/tps65912.h> |
| 67 | xfer.rx_buf = &rx_buf; | ||
| 68 | xfer.len = sizeof(unsigned long); | ||
| 69 | xfer.bits_per_word = 24; | ||
| 70 | |||
| 71 | spi_message_init(&msg); | ||
| 72 | spi_message_add_tail(&xfer, &msg); | ||
| 73 | |||
| 74 | if (spi == NULL) | ||
| 75 | return 0; | ||
| 76 | 25 | ||
| 77 | ret = spi_sync(spi, &msg); | 26 | static const struct of_device_id tps65912_spi_of_match_table[] = { |
| 78 | if (ret == 0) | 27 | { .compatible = "ti,tps65912", }, |
| 79 | *data = (u8) (rx_buf & 0xFF); | 28 | { /* sentinel */ } |
| 80 | return ret; | 29 | }; |
| 81 | } | ||
| 82 | 30 | ||
| 83 | static int tps65912_spi_probe(struct spi_device *spi) | 31 | static int tps65912_spi_probe(struct spi_device *spi) |
| 84 | { | 32 | { |
| 85 | struct tps65912 *tps65912; | 33 | struct tps65912 *tps; |
| 86 | 34 | ||
| 87 | tps65912 = devm_kzalloc(&spi->dev, | 35 | tps = devm_kzalloc(&spi->dev, sizeof(*tps), GFP_KERNEL); |
| 88 | sizeof(struct tps65912), GFP_KERNEL); | 36 | if (!tps) |
| 89 | if (tps65912 == NULL) | ||
| 90 | return -ENOMEM; | 37 | return -ENOMEM; |
| 91 | 38 | ||
| 92 | tps65912->dev = &spi->dev; | 39 | spi_set_drvdata(spi, tps); |
| 93 | tps65912->control_data = spi; | 40 | tps->dev = &spi->dev; |
| 94 | tps65912->read = tps65912_spi_read; | 41 | tps->irq = spi->irq; |
| 95 | tps65912->write = tps65912_spi_write; | ||
| 96 | 42 | ||
| 97 | spi_set_drvdata(spi, tps65912); | 43 | tps->regmap = devm_regmap_init_spi(spi, &tps65912_regmap_config); |
| 44 | if (IS_ERR(tps->regmap)) { | ||
| 45 | dev_err(tps->dev, "Failed to initialize register map\n"); | ||
| 46 | return PTR_ERR(tps->regmap); | ||
| 47 | } | ||
| 98 | 48 | ||
| 99 | return tps65912_device_init(tps65912); | 49 | return tps65912_device_init(tps); |
| 100 | } | 50 | } |
| 101 | 51 | ||
| 102 | static int tps65912_spi_remove(struct spi_device *spi) | 52 | static int tps65912_spi_remove(struct spi_device *client) |
| 103 | { | 53 | { |
| 104 | struct tps65912 *tps65912 = spi_get_drvdata(spi); | 54 | struct tps65912 *tps = spi_get_drvdata(client); |
| 105 | 55 | ||
| 106 | tps65912_device_exit(tps65912); | 56 | return tps65912_device_exit(tps); |
| 107 | |||
| 108 | return 0; | ||
| 109 | } | 57 | } |
| 110 | 58 | ||
| 59 | static const struct spi_device_id tps65912_spi_id_table[] = { | ||
| 60 | { "tps65912", 0 }, | ||
| 61 | { /* sentinel */ } | ||
| 62 | }; | ||
| 63 | MODULE_DEVICE_TABLE(spi, tps65912_spi_id_table); | ||
| 64 | |||
| 111 | static struct spi_driver tps65912_spi_driver = { | 65 | static struct spi_driver tps65912_spi_driver = { |
| 112 | .driver = { | 66 | .driver = { |
| 113 | .name = "tps65912", | 67 | .name = "tps65912", |
| 68 | .of_match_table = tps65912_spi_of_match_table, | ||
| 114 | }, | 69 | }, |
| 115 | .probe = tps65912_spi_probe, | 70 | .probe = tps65912_spi_probe, |
| 116 | .remove = tps65912_spi_remove, | 71 | .remove = tps65912_spi_remove, |
| 72 | .id_table = tps65912_spi_id_table, | ||
| 117 | }; | 73 | }; |
| 74 | module_spi_driver(tps65912_spi_driver); | ||
| 118 | 75 | ||
| 119 | static int __init tps65912_spi_init(void) | 76 | MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); |
| 120 | { | 77 | MODULE_DESCRIPTION("TPS65912x SPI Interface Driver"); |
| 121 | int ret; | 78 | MODULE_LICENSE("GPL v2"); |
| 122 | |||
| 123 | ret = spi_register_driver(&tps65912_spi_driver); | ||
| 124 | if (ret != 0) | ||
| 125 | pr_err("Failed to register TPS65912 SPI driver: %d\n", ret); | ||
| 126 | |||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | /* init early so consumer devices can complete system boot */ | ||
| 130 | subsys_initcall(tps65912_spi_init); | ||
| 131 | |||
| 132 | static void __exit tps65912_spi_exit(void) | ||
| 133 | { | ||
| 134 | spi_unregister_driver(&tps65912_spi_driver); | ||
| 135 | } | ||
| 136 | module_exit(tps65912_spi_exit); | ||
| 137 | |||
| 138 | MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>"); | ||
| 139 | MODULE_DESCRIPTION("SPI support for TPS65912 chip family mfd"); | ||
| 140 | MODULE_LICENSE("GPL"); | ||
