Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pwm: Move TWL6030 PWM driver to PWM framework

This commit moves the driver to drivers/pwm and converts it to the new
PWM framework. In order for this to work properly, register the PWM as
child of the multi-function TWL6030 device.

Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Thierry Reding and committed by
Samuel Ortiz
48a364b7 f78959cf

+201 -176
-10
drivers/mfd/Kconfig
··· 298 298 select MFD_CORE 299 299 default n 300 300 301 - config TWL6030_PWM 302 - tristate "TWL6030 PWM (Pulse Width Modulator) Support" 303 - depends on TWL4030_CORE 304 - select HAVE_PWM 305 - depends on !PWM 306 - default n 307 - help 308 - Say yes here if you want support for TWL6030 PWM. 309 - This is used to control charging LED brightness. 310 - 311 301 config TWL6040_CORE 312 302 bool "Support for TWL6040 audio codec" 313 303 depends on I2C=y && GENERIC_HARDIRQS
-1
drivers/mfd/Makefile
··· 63 63 obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o 64 64 obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o 65 65 obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o 66 - obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o 67 66 obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o 68 67 69 68 obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
+7
drivers/mfd/twl-core.c
··· 670 670 return PTR_ERR(child); 671 671 } 672 672 673 + if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { 674 + child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, 675 + false, 0, 0); 676 + if (IS_ERR(child)) 677 + return PTR_ERR(child); 678 + } 679 + 673 680 if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && 674 681 twl_class_is_4030()) { 675 682
-165
drivers/mfd/twl6030-pwm.c
··· 1 - /* 2 - * twl6030_pwm.c 3 - * Driver for PHOENIX (TWL6030) Pulse Width Modulator 4 - * 5 - * Copyright (C) 2010 Texas Instruments 6 - * Author: Hemanth V <hemanthv@ti.com> 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 version 2 as published by 10 - * the Free Software Foundation. 11 - * 12 - * This program is distributed in the hope that it will be useful, but WITHOUT 13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 - * more details. 16 - * 17 - * You should have received a copy of the GNU General Public License along with 18 - * this program. If not, see <http://www.gnu.org/licenses/>. 19 - */ 20 - 21 - #include <linux/module.h> 22 - #include <linux/platform_device.h> 23 - #include <linux/i2c/twl.h> 24 - #include <linux/slab.h> 25 - 26 - #define LED_PWM_CTRL1 0xF4 27 - #define LED_PWM_CTRL2 0xF5 28 - 29 - /* Max value for CTRL1 register */ 30 - #define PWM_CTRL1_MAX 255 31 - 32 - /* Pull down disable */ 33 - #define PWM_CTRL2_DIS_PD (1 << 6) 34 - 35 - /* Current control 2.5 milli Amps */ 36 - #define PWM_CTRL2_CURR_02 (2 << 4) 37 - 38 - /* LED supply source */ 39 - #define PWM_CTRL2_SRC_VAC (1 << 2) 40 - 41 - /* LED modes */ 42 - #define PWM_CTRL2_MODE_HW (0 << 0) 43 - #define PWM_CTRL2_MODE_SW (1 << 0) 44 - #define PWM_CTRL2_MODE_DIS (2 << 0) 45 - 46 - #define PWM_CTRL2_MODE_MASK 0x3 47 - 48 - struct pwm_device { 49 - const char *label; 50 - unsigned int pwm_id; 51 - }; 52 - 53 - int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 54 - { 55 - u8 duty_cycle; 56 - int ret; 57 - 58 - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) 59 - return -EINVAL; 60 - 61 - duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; 62 - 63 - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); 64 - 65 - if (ret < 0) { 66 - pr_err("%s: Failed to configure PWM, Error %d\n", 67 - pwm->label, ret); 68 - return ret; 69 - } 70 - return 0; 71 - } 72 - EXPORT_SYMBOL(pwm_config); 73 - 74 - int pwm_enable(struct pwm_device *pwm) 75 - { 76 - u8 val; 77 - int ret; 78 - 79 - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 80 - if (ret < 0) { 81 - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); 82 - return ret; 83 - } 84 - 85 - /* Change mode to software control */ 86 - val &= ~PWM_CTRL2_MODE_MASK; 87 - val |= PWM_CTRL2_MODE_SW; 88 - 89 - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 90 - if (ret < 0) { 91 - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); 92 - return ret; 93 - } 94 - 95 - twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 96 - return 0; 97 - } 98 - EXPORT_SYMBOL(pwm_enable); 99 - 100 - void pwm_disable(struct pwm_device *pwm) 101 - { 102 - u8 val; 103 - int ret; 104 - 105 - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 106 - if (ret < 0) { 107 - pr_err("%s: Failed to disable PWM, Error %d\n", 108 - pwm->label, ret); 109 - return; 110 - } 111 - 112 - val &= ~PWM_CTRL2_MODE_MASK; 113 - val |= PWM_CTRL2_MODE_HW; 114 - 115 - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 116 - if (ret < 0) { 117 - pr_err("%s: Failed to disable PWM, Error %d\n", 118 - pwm->label, ret); 119 - return; 120 - } 121 - return; 122 - } 123 - EXPORT_SYMBOL(pwm_disable); 124 - 125 - struct pwm_device *pwm_request(int pwm_id, const char *label) 126 - { 127 - u8 val; 128 - int ret; 129 - struct pwm_device *pwm; 130 - 131 - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); 132 - if (pwm == NULL) { 133 - pr_err("%s: failed to allocate memory\n", label); 134 - return NULL; 135 - } 136 - 137 - pwm->label = label; 138 - pwm->pwm_id = pwm_id; 139 - 140 - /* Configure PWM */ 141 - val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | 142 - PWM_CTRL2_MODE_HW; 143 - 144 - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 145 - 146 - if (ret < 0) { 147 - pr_err("%s: Failed to configure PWM, Error %d\n", 148 - pwm->label, ret); 149 - 150 - kfree(pwm); 151 - return NULL; 152 - } 153 - 154 - return pwm; 155 - } 156 - EXPORT_SYMBOL(pwm_request); 157 - 158 - void pwm_free(struct pwm_device *pwm) 159 - { 160 - pwm_disable(pwm); 161 - kfree(pwm); 162 - } 163 - EXPORT_SYMBOL(pwm_free); 164 - 165 - MODULE_LICENSE("GPL");
+9
drivers/pwm/Kconfig
··· 96 96 To compile this driver as a module, choose M here: the module 97 97 will be called pwm-tiehrpwm. 98 98 99 + config PWM_TWL6030 100 + tristate "TWL6030 PWM support" 101 + depends on TWL4030_CORE 102 + help 103 + Generic PWM framework driver for TWL6030. 104 + 105 + To compile this driver as a module, choose M here: the module 106 + will be called pwm-twl6030. 107 + 99 108 config PWM_VT8500 100 109 tristate "vt8500 pwm support" 101 110 depends on ARCH_VT8500
+1
drivers/pwm/Makefile
··· 8 8 obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o 9 9 obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o 10 10 obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o 11 + obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o 11 12 obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
+184
drivers/pwm/pwm-twl6030.c
··· 1 + /* 2 + * twl6030_pwm.c 3 + * Driver for PHOENIX (TWL6030) Pulse Width Modulator 4 + * 5 + * Copyright (C) 2010 Texas Instruments 6 + * Author: Hemanth V <hemanthv@ti.com> 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 version 2 as published by 10 + * the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along with 18 + * this program. If not, see <http://www.gnu.org/licenses/>. 19 + */ 20 + 21 + #include <linux/module.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/pwm.h> 24 + #include <linux/i2c/twl.h> 25 + #include <linux/slab.h> 26 + 27 + #define LED_PWM_CTRL1 0xF4 28 + #define LED_PWM_CTRL2 0xF5 29 + 30 + /* Max value for CTRL1 register */ 31 + #define PWM_CTRL1_MAX 255 32 + 33 + /* Pull down disable */ 34 + #define PWM_CTRL2_DIS_PD (1 << 6) 35 + 36 + /* Current control 2.5 milli Amps */ 37 + #define PWM_CTRL2_CURR_02 (2 << 4) 38 + 39 + /* LED supply source */ 40 + #define PWM_CTRL2_SRC_VAC (1 << 2) 41 + 42 + /* LED modes */ 43 + #define PWM_CTRL2_MODE_HW (0 << 0) 44 + #define PWM_CTRL2_MODE_SW (1 << 0) 45 + #define PWM_CTRL2_MODE_DIS (2 << 0) 46 + 47 + #define PWM_CTRL2_MODE_MASK 0x3 48 + 49 + struct twl6030_pwm_chip { 50 + struct pwm_chip chip; 51 + }; 52 + 53 + static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 54 + { 55 + int ret; 56 + u8 val; 57 + 58 + /* Configure PWM */ 59 + val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | 60 + PWM_CTRL2_MODE_HW; 61 + 62 + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 63 + if (ret < 0) { 64 + dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n", 65 + pwm->label, ret); 66 + return ret; 67 + } 68 + 69 + return 0; 70 + } 71 + 72 + static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 73 + int duty_ns, int period_ns) 74 + { 75 + u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; 76 + int ret; 77 + 78 + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); 79 + if (ret < 0) { 80 + pr_err("%s: Failed to configure PWM, Error %d\n", 81 + pwm->label, ret); 82 + return ret; 83 + } 84 + 85 + return 0; 86 + } 87 + 88 + static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 89 + { 90 + int ret; 91 + u8 val; 92 + 93 + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 94 + if (ret < 0) { 95 + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", 96 + pwm->label, ret); 97 + return ret; 98 + } 99 + 100 + /* Change mode to software control */ 101 + val &= ~PWM_CTRL2_MODE_MASK; 102 + val |= PWM_CTRL2_MODE_SW; 103 + 104 + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 105 + if (ret < 0) { 106 + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", 107 + pwm->label, ret); 108 + return ret; 109 + } 110 + 111 + twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 112 + return 0; 113 + } 114 + 115 + static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 116 + { 117 + int ret; 118 + u8 val; 119 + 120 + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); 121 + if (ret < 0) { 122 + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", 123 + pwm->label, ret); 124 + return; 125 + } 126 + 127 + val &= ~PWM_CTRL2_MODE_MASK; 128 + val |= PWM_CTRL2_MODE_HW; 129 + 130 + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); 131 + if (ret < 0) { 132 + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", 133 + pwm->label, ret); 134 + } 135 + } 136 + 137 + static const struct pwm_ops twl6030_pwm_ops = { 138 + .request = twl6030_pwm_request, 139 + .config = twl6030_pwm_config, 140 + .enable = twl6030_pwm_enable, 141 + .disable = twl6030_pwm_disable, 142 + }; 143 + 144 + static int twl6030_pwm_probe(struct platform_device *pdev) 145 + { 146 + struct twl6030_pwm_chip *twl6030; 147 + int ret; 148 + 149 + twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL); 150 + if (!twl6030) 151 + return -ENOMEM; 152 + 153 + twl6030->chip.dev = &pdev->dev; 154 + twl6030->chip.ops = &twl6030_pwm_ops; 155 + twl6030->chip.base = -1; 156 + twl6030->chip.npwm = 1; 157 + 158 + ret = pwmchip_add(&twl6030->chip); 159 + if (ret < 0) 160 + return ret; 161 + 162 + platform_set_drvdata(pdev, twl6030); 163 + 164 + return 0; 165 + } 166 + 167 + static int twl6030_pwm_remove(struct platform_device *pdev) 168 + { 169 + struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev); 170 + 171 + return pwmchip_remove(&twl6030->chip); 172 + } 173 + 174 + static struct platform_driver twl6030_pwm_driver = { 175 + .driver = { 176 + .name = "twl6030-pwm", 177 + }, 178 + .probe = twl6030_pwm_probe, 179 + .remove = __devexit_p(twl6030_pwm_remove), 180 + }; 181 + module_platform_driver(twl6030_pwm_driver); 182 + 183 + MODULE_ALIAS("platform:twl6030-pwm"); 184 + MODULE_LICENSE("GPL");