diff options
author | Marcel Tunnissen <Marcel.Tuennissen@stericsson.com> | 2010-11-23 14:18:31 +0100 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-01-13 15:01:12 +0100 |
commit | 9fea1f4de7def62ffa3f17a8efb83459a3d6cd79 (patch) | |
tree | 75e772419e4d10fb8cfddfe6d56e68bfdfe37040 /drivers/mfd | |
parent | 61fb260d091262be3b7988d8c4012f1c4ab33605 (diff) |
Remove singleton assumption for AB8500 DENC driver
Adjust the AB8500 display driver in MCDE to the new interface in AB8500 DENC.
ST-Ericsson ID: AP 280588
Linux-next: ST-Ericsson ID: ER 282779
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: If72b8371521b13513f83431c3ae54926e54195d9
Signed-off-by: Marcel Tunnissen <Marcel.Tuennissen@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/12213
Tested-by: Marcel TUNNISSEN <marcel.tuennissen@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/ab8500-denc.c | 325 |
1 files changed, 185 insertions, 140 deletions
diff --git a/drivers/mfd/ab8500-denc.c b/drivers/mfd/ab8500-denc.c index c79aa57021e..c7c3749ce41 100644 --- a/drivers/mfd/ab8500-denc.c +++ b/drivers/mfd/ab8500-denc.c @@ -12,10 +12,12 @@ #include <linux/kernel.h> #include <linux/device.h> #include <linux/debugfs.h> +#include <linux/list.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/delay.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/err.h> #include <linux/uaccess.h> @@ -27,115 +29,149 @@ #define AB8500_NAME "ab8500" #define AB8500_DENC_NAME "ab8500_denc" -static struct platform_device *ab8500_denc_dev; +struct device_usage { + struct list_head list; + struct platform_device *pdev; + bool taken; +}; +static LIST_HEAD(device_list); +/* To get rid of the extra bank parameter: */ #define AB8500_REG_BANK_NR(__reg) ((0xff00 & (__reg)) >> 8) -static inline u8 ab8500_rreg(u32 reg) +static inline u8 ab8500_rreg(struct device *dev, u32 reg) { - int ret; u8 val; + if (abx500_get_register_interruptible(dev, AB8500_REG_BANK_NR(reg), + reg, &val) < 0) + return 0; + else + return val; +} + +static inline int ab8500_wreg(struct device *dev, u32 reg, u8 val) +{ + return abx500_set_register_interruptible(dev, AB8500_REG_BANK_NR(reg), + reg, val); +} - if (!ab8500_denc_dev || !&ab8500_denc_dev->dev) - return -ENODEV; +/* Only use in the macro below: */ +static inline int _ab8500_wreg_fld(struct device *dev, u32 reg, u8 val, + u8 mask, u8 shift) +{ + int ret; + u8 org_val; - ret = abx500_get_register_interruptible(&ab8500_denc_dev->dev, - AB8500_REG_BANK_NR(reg), reg, &val); + ret = abx500_get_register_interruptible(dev, AB8500_REG_BANK_NR(reg), + reg, &org_val); if (ret < 0) return ret; else - return val; + ab8500_wreg(dev, reg, + (org_val & ~mask) | ((val << shift) & mask)); + return 0; } -static inline void ab8500_wreg(u32 reg, u8 val) -{ - if (!ab8500_denc_dev || !&ab8500_denc_dev->dev) { - printk(KERN_ERR "AB8500_denc error. No device found.\n"); - return; - } - abx500_set_register_interruptible(&ab8500_denc_dev->dev, - AB8500_REG_BANK_NR(reg), reg, val); -} +#define ab8500_wr_fld(__d, __reg, __fld, __val) \ + _ab8500_wreg_fld(__d, __reg, __val, __reg##_##__fld##_MASK, \ + __reg##_##__fld##_SHIFT) -#define ab8500_set_fld(__cur_val, __reg, __fld, __val) \ - (((__cur_val) & ~__reg##_##__fld##_MASK) |\ +#define ab8500_set_fld(__cur_val, __reg, __fld, __val) \ + (((__cur_val) & ~__reg##_##__fld##_MASK) | \ (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK)) -#define ab8500_wr_fld(__reg, __fld, __val) \ - ab8500_wreg(__reg, \ - ((ab8500_rreg(__reg) & ~__reg##_##__fld##_MASK) |\ - (((__val) << __reg##_##__fld##_SHIFT) &\ - __reg##_##__fld##_MASK))) - -#define AB8500_DENC_TRACE pr_debug("%s\n", __func__) +#define AB8500_DENC_TRACE(__pd) dev_dbg(&(__pd)->dev, "%s\n", __func__) #ifdef CONFIG_DEBUG_FS static struct dentry *debugfs_ab8500_denc_dir; static struct dentry *debugfs_ab8500_dump_regs_file; -static void ab8500_denc_conf_ddr(void); +static void ab8500_denc_conf_ddr(struct platform_device *pdev); static int debugfs_ab8500_open_file(struct inode *inode, struct file *file); static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf, size_t count, loff_t *f_pos); -static ssize_t debugfs_ab8500_write_file_dummy(struct file *file, - const char __user *ubuf, - size_t count, loff_t *ppos); static const struct file_operations debugfs_ab8500_dump_regs_fops = { .owner = THIS_MODULE, .open = debugfs_ab8500_open_file, .read = debugfs_ab8500_dump_regs, - .write = debugfs_ab8500_write_file_dummy }; #endif /* CONFIG_DEBUG_FS */ -static void setup_27mhz(bool enable); -static u32 map_tv_std(enum ab8500_denc_TV_std std); -static u32 map_cr_filter(enum ab8500_denc_cr_filter_bandwidth bw); -static u32 map_phase_rst_mode(enum ab8500_denc_phase_reset_mode mode); -static u32 map_plug_time(enum ab8500_denc_plug_time time); - static int __devinit ab8500_denc_probe(struct platform_device *pdev) { int ret = 0; struct ab8500_platform_data *ab8500_pdata = dev_get_platdata(pdev->dev.parent); struct ab8500_denc_platform_data *pdata; + struct device_usage *device_data; + + AB8500_DENC_TRACE(pdev); if (ab8500_pdata == NULL) { dev_err(&pdev->dev, "AB8500 platform data missing\n"); - ret = -EINVAL; - goto no_pdata; + return -EINVAL; } pdata = ab8500_pdata->denc; if (pdata == NULL) { dev_err(&pdev->dev, "Denc platform data missing\n"); - ret = -EINVAL; - goto no_pdata; + return -EINVAL; } - ab8500_denc_dev = pdev; - AB8500_DENC_TRACE; /* note this needs ab8500_denc_dev to be set */ + device_data = kzalloc(sizeof(struct device_usage), GFP_KERNEL); + if (!device_data) { + dev_err(&pdev->dev, "Failed to allocate device data\n"); + return -ENOMEM; + } + device_data->pdev = pdev; + list_add_tail(&device_data->list, &device_list); #ifdef CONFIG_DEBUG_FS debugfs_ab8500_denc_dir = debugfs_create_dir(pdev->name, NULL); debugfs_ab8500_dump_regs_file = debugfs_create_file( "dumpregs", S_IRUGO, - debugfs_ab8500_denc_dir, 0, + debugfs_ab8500_denc_dir, &pdev->dev, &debugfs_ab8500_dump_regs_fops ); #endif /* CONFIG_DEBUG_FS */ -out: return ret; +} + +static int __devexit ab8500_denc_remove(struct platform_device *pdev) +{ + struct list_head *element; + struct device_usage *device_data; -no_pdata: - goto out; + AB8500_DENC_TRACE(pdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove(debugfs_ab8500_dump_regs_file); + debugfs_remove(debugfs_ab8500_denc_dir); +#endif /* CONFIG_DEBUG_FS */ + + list_for_each(element, &device_list) { + device_data = list_entry(element, struct device_usage, list); + if (device_data->pdev == pdev) { + list_del(element); + kzfree(device_data); + } + } + + return 0; } -static void setup_27mhz(bool enable) +static struct platform_driver ab8500_denc_driver = { + .probe = ab8500_denc_probe, + .remove = ab8500_denc_remove, + .driver = { + .name = "ab8500-denc", + }, +}; + +static void setup_27mhz(struct platform_device *pdev, bool enable) { - u8 data = ab8500_rreg(AB8500_SYS_ULP_CLK_CONF); + u8 data = ab8500_rreg(&pdev->dev, AB8500_SYS_ULP_CLK_CONF); - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); /* TODO: check if this field needs to be set */ data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_PD_ENA, true); @@ -147,14 +183,14 @@ static void setup_27mhz(bool enable) false); data = ab8500_set_fld(data, AB8500_SYS_ULP_CLK_CONF, CLK_27MHZ_STRE, 1); - ab8500_wreg(AB8500_SYS_ULP_CLK_CONF, data); + ab8500_wreg(&pdev->dev, AB8500_SYS_ULP_CLK_CONF, data); - data = ab8500_rreg(AB8500_SYS_CLK_CTRL); + data = ab8500_rreg(&pdev->dev, AB8500_SYS_CLK_CTRL); data = ab8500_set_fld(data, AB8500_SYS_CLK_CTRL, TVOUT_CLK_VALID, enable); data = ab8500_set_fld(data, AB8500_SYS_CLK_CTRL, TVOUT_PLL_ENA, enable); - ab8500_wreg(AB8500_SYS_CLK_CTRL, data); + ab8500_wreg(&pdev->dev, AB8500_SYS_CLK_CTRL, data); } static u32 map_tv_std(enum ab8500_denc_TV_std std) @@ -225,79 +261,92 @@ static u32 map_plug_time(enum ab8500_denc_plug_time time) } } -static int __devexit ab8500_denc_remove(struct platform_device *pdev) +struct platform_device *ab8500_denc_get_device(void) { - AB8500_DENC_TRACE; -#ifdef CONFIG_DEBUG_FS - debugfs_remove(debugfs_ab8500_dump_regs_file); - debugfs_remove(debugfs_ab8500_denc_dir); -#endif /* CONFIG_DEBUG_FS */ - - ab8500_denc_dev = NULL; - - return 0; + struct list_head *element; + struct device_usage *device_data; + + pr_debug("%s\n", __func__); + list_for_each(element, &device_list) { + device_data = list_entry(element, struct device_usage, list); + if (!device_data->taken) { + device_data->taken = true; + return device_data->pdev; + } + } + return NULL; } +EXPORT_SYMBOL(ab8500_denc_get_device); -static struct platform_driver ab8500_denc_driver = { - .probe = ab8500_denc_probe, - .remove = ab8500_denc_remove, - .driver = { - .name = "ab8500-denc", - }, -}; +void ab8500_denc_put_device(struct platform_device *pdev) +{ + struct list_head *element; + struct device_usage *device_data; + + AB8500_DENC_TRACE(pdev); + list_for_each(element, &device_list) { + device_data = list_entry(element, struct device_usage, list); + if (device_data->pdev == pdev) + device_data->taken = false; + } +} +EXPORT_SYMBOL(ab8500_denc_put_device); -void ab8500_denc_reset(bool hard) +void ab8500_denc_reset(struct platform_device *pdev, bool hard) { - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); if (hard) { - u8 data = ab8500_rreg(AB8500_CTRL3); + u8 data = ab8500_rreg(&pdev->dev, AB8500_CTRL3); /* reset start */ - ab8500_wreg(AB8500_CTRL3, + ab8500_wreg(&pdev->dev, AB8500_CTRL3, ab8500_set_fld(data, AB8500_CTRL3, RESET_DENC_N, 0) ); /* reset done */ - ab8500_wreg(AB8500_CTRL3, + ab8500_wreg(&pdev->dev, AB8500_CTRL3, ab8500_set_fld(data, AB8500_CTRL3, RESET_DENC_N, 1) ); } else { - ab8500_wr_fld(AB8500_DENC_CONF6, SOFT_RESET, 1); + ab8500_wr_fld(&pdev->dev, AB8500_DENC_CONF6, SOFT_RESET, 1); mdelay(10); } } EXPORT_SYMBOL(ab8500_denc_reset); -void ab8500_denc_power_up(void) +void ab8500_denc_power_up(struct platform_device *pdev) { - setup_27mhz(true); + setup_27mhz(pdev, true); } EXPORT_SYMBOL(ab8500_denc_power_up); -void ab8500_denc_power_down(void) +void ab8500_denc_power_down(struct platform_device *pdev) { - setup_27mhz(false); + setup_27mhz(pdev, false); } EXPORT_SYMBOL(ab8500_denc_power_down); -void ab8500_denc_regu_setup(bool enable_v_tv, bool enable_lp_mode) +void ab8500_denc_regu_setup(struct platform_device *pdev, + bool enable_v_tv, bool enable_lp_mode) { - u8 data = ab8500_rreg(AB8500_REGU_MISC1); + u8 data; - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); + data = ab8500_rreg(&pdev->dev, AB8500_REGU_MISC1); data = ab8500_set_fld(data, AB8500_REGU_MISC1, V_TVOUT_LP, enable_lp_mode); data = ab8500_set_fld(data, AB8500_REGU_MISC1, V_TVOUT_ENA, enable_v_tv); - ab8500_wreg(AB8500_REGU_MISC1, data); + ab8500_wreg(&pdev->dev, AB8500_REGU_MISC1, data); } EXPORT_SYMBOL(ab8500_denc_regu_setup); -void ab8500_denc_conf(struct ab8500_denc_conf *conf) +void ab8500_denc_conf(struct platform_device *pdev, + struct ab8500_denc_conf *conf) { u8 data; - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); - ab8500_wreg(AB8500_DENC_CONF0, + ab8500_wreg(&pdev->dev, AB8500_DENC_CONF0, AB8500_VAL2REG(AB8500_DENC_CONF0, STD, map_tv_std(conf->TV_std)) | AB8500_VAL2REG(AB8500_DENC_CONF0, SYNC, @@ -305,7 +354,7 @@ void ab8500_denc_conf(struct ab8500_denc_conf *conf) AB8500_DENC_CONF0_SYNC_F_BASED_SLAVE ) ); - ab8500_wreg(AB8500_DENC_CONF1, + ab8500_wreg(&pdev->dev, AB8500_DENC_CONF1, AB8500_VAL2REG(AB8500_DENC_CONF1, BLK_LI, !conf->partial_blanking) | @@ -319,12 +368,12 @@ void ab8500_denc_conf(struct ab8500_denc_conf *conf) /* TODO: handle cc field: set to 0 now */ ); - data = ab8500_rreg(AB8500_DENC_CONF2); + data = ab8500_rreg(&pdev->dev, AB8500_DENC_CONF2); data = ab8500_set_fld(data, AB8500_DENC_CONF2, N_INTRL, conf->progressive); - ab8500_wreg(AB8500_DENC_CONF2, data); + ab8500_wreg(&pdev->dev, AB8500_DENC_CONF2, data); - ab8500_wreg(AB8500_DENC_CONF8, + ab8500_wreg(&pdev->dev, AB8500_DENC_CONF8, AB8500_VAL2REG(AB8500_DENC_CONF8, PH_RST_MODE, map_phase_rst_mode(conf->phase_reset_mode)) | @@ -334,76 +383,70 @@ void ab8500_denc_conf(struct ab8500_denc_conf *conf) AB8500_VAL2REG(AB8500_DENC_CONF8, BLK_ALL, conf->blank_all) ); - data = ab8500_rreg(AB8500_TVOUT_CTRL); + data = ab8500_rreg(&pdev->dev, AB8500_TVOUT_CTRL); data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, DAC_CTRL0, conf->dac_enable); data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, DAC_CTRL1, conf->act_dc_output); - ab8500_wreg(AB8500_TVOUT_CTRL, data); + ab8500_wreg(&pdev->dev, AB8500_TVOUT_CTRL, data); /* no support for DDR in early versions */ - if (AB8500_REG2VAL(AB8500_REV, FULL_MASK, ab8500_rreg(AB8500_REV)) > 0) - ab8500_denc_conf_ddr(); + if (AB8500_REG2VAL(AB8500_REV, FULL_MASK, + ab8500_rreg(&pdev->dev, AB8500_REV)) > 0) + ab8500_denc_conf_ddr(pdev); } EXPORT_SYMBOL(ab8500_denc_conf); -void ab8500_denc_conf_plug_detect(bool enable, bool load_RC, +void ab8500_denc_conf_plug_detect(struct platform_device *pdev, + bool enable, bool load_RC, enum ab8500_denc_plug_time time) { - u8 data = ab8500_rreg(AB8500_TVOUT_CTRL); + u8 data; - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); + data = ab8500_rreg(&pdev->dev, AB8500_TVOUT_CTRL); data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, TV_PLUG_ON, enable); data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, TV_LOAD_RC, load_RC); data = ab8500_set_fld(data, AB8500_TVOUT_CTRL, PLUG_TV_TIME, map_plug_time(time)); - ab8500_wreg(AB8500_TVOUT_CTRL, data); + ab8500_wreg(&pdev->dev, AB8500_TVOUT_CTRL, data); } EXPORT_SYMBOL(ab8500_denc_conf_plug_detect); -void ab8500_denc_mask_int_plug_det(bool plug, bool unplug) +void ab8500_denc_mask_int_plug_det(struct platform_device *pdev, bool plug, + bool unplug) { - u8 data = ab8500_rreg(AB8500_IT_MASK1); + u8 data = ab8500_rreg(&pdev->dev, AB8500_IT_MASK1); - AB8500_DENC_TRACE; + AB8500_DENC_TRACE(pdev); data = ab8500_set_fld(data, AB8500_IT_MASK1, PLUG_TV_DET, plug); data = ab8500_set_fld(data, AB8500_IT_MASK1, UNPLUG_TV_DET, unplug); - ab8500_wreg(AB8500_IT_MASK1, data); + ab8500_wreg(&pdev->dev, AB8500_IT_MASK1, data); } EXPORT_SYMBOL(ab8500_denc_mask_int_plug_det); -static void ab8500_denc_conf_ddr(void) +static void ab8500_denc_conf_ddr(struct platform_device *pdev) { - struct ab8500_platform_data *ab8500_pdata; - struct ab8500_denc_platform_data *pdata; - - AB8500_DENC_TRACE; - if (ab8500_denc_dev) { - ab8500_pdata = dev_get_platdata(ab8500_denc_dev->dev.parent); - pdata = ab8500_pdata->denc; - ab8500_wreg(AB8500_TVOUT_CTRL2, - AB8500_VAL2REG(AB8500_TVOUT_CTRL2, - DENC_DDR, pdata->ddr_enable) - | - AB8500_VAL2REG(AB8500_TVOUT_CTRL2, SWAP_DDR_DATA_IN, - pdata->ddr_little_endian) - ); - } + struct ab8500_platform_data *core_pdata; + struct ab8500_denc_platform_data *denc_pdata; + + AB8500_DENC_TRACE(pdev); + core_pdata = dev_get_platdata(pdev->dev.parent); + denc_pdata = core_pdata->denc; + ab8500_wreg(&pdev->dev, AB8500_TVOUT_CTRL2, + AB8500_VAL2REG(AB8500_TVOUT_CTRL2, + DENC_DDR, denc_pdata->ddr_enable) | + AB8500_VAL2REG(AB8500_TVOUT_CTRL2, SWAP_DDR_DATA_IN, + denc_pdata->ddr_little_endian)); } #ifdef CONFIG_DEBUG_FS static int debugfs_ab8500_open_file(struct inode *inode, struct file *file) { + file->private_data = inode->i_private; return 0; } -static ssize_t debugfs_ab8500_write_file_dummy(struct file *file, - const char __user *ubuf, - size_t count, loff_t *ppos) -{ - return count; -} - #define DEBUG_BUF_SIZE 900 static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf, @@ -412,6 +455,7 @@ static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf, int ret = 0; size_t data_size = 0; char buffer[DEBUG_BUF_SIZE]; + struct device *dev = file->private_data; data_size += sprintf(buffer + data_size, "AB8500 DENC registers:\n" @@ -430,20 +474,21 @@ static ssize_t debugfs_ab8500_dump_regs(struct file *file, char __user *buf, "TVOUT_CTRL2 : 0x%04x = 0x%02x\n" "IT_MASK1 : 0x%04x = 0x%02x\n" , - AB8500_CTRL3, ab8500_rreg(AB8500_CTRL3), - AB8500_SYS_ULP_CLK_CONF, ab8500_rreg(AB8500_SYS_ULP_CLK_CONF), - AB8500_SYS_CLK_CTRL, ab8500_rreg(AB8500_SYS_CLK_CTRL), - AB8500_REGU_MISC1, ab8500_rreg(AB8500_REGU_MISC1), - AB8500_VAUX12_REGU, ab8500_rreg(AB8500_VAUX12_REGU), - AB8500_VAUX1_SEL, ab8500_rreg(AB8500_VAUX1_SEL), - AB8500_DENC_CONF0, ab8500_rreg(AB8500_DENC_CONF0), - AB8500_DENC_CONF1, ab8500_rreg(AB8500_DENC_CONF1), - AB8500_DENC_CONF2, ab8500_rreg(AB8500_DENC_CONF2), - AB8500_DENC_CONF6, ab8500_rreg(AB8500_DENC_CONF6), - AB8500_DENC_CONF8, ab8500_rreg(AB8500_DENC_CONF8), - AB8500_TVOUT_CTRL, ab8500_rreg(AB8500_TVOUT_CTRL), - AB8500_TVOUT_CTRL2, ab8500_rreg(AB8500_TVOUT_CTRL2), - AB8500_IT_MASK1, ab8500_rreg(AB8500_IT_MASK1) + AB8500_CTRL3, ab8500_rreg(dev, AB8500_CTRL3), + AB8500_SYS_ULP_CLK_CONF, ab8500_rreg(dev, + AB8500_SYS_ULP_CLK_CONF), + AB8500_SYS_CLK_CTRL, ab8500_rreg(dev, AB8500_SYS_CLK_CTRL), + AB8500_REGU_MISC1, ab8500_rreg(dev, AB8500_REGU_MISC1), + AB8500_VAUX12_REGU, ab8500_rreg(dev, AB8500_VAUX12_REGU), + AB8500_VAUX1_SEL, ab8500_rreg(dev, AB8500_VAUX1_SEL), + AB8500_DENC_CONF0, ab8500_rreg(dev, AB8500_DENC_CONF0), + AB8500_DENC_CONF1, ab8500_rreg(dev, AB8500_DENC_CONF1), + AB8500_DENC_CONF2, ab8500_rreg(dev, AB8500_DENC_CONF2), + AB8500_DENC_CONF6, ab8500_rreg(dev, AB8500_DENC_CONF6), + AB8500_DENC_CONF8, ab8500_rreg(dev, AB8500_DENC_CONF8), + AB8500_TVOUT_CTRL, ab8500_rreg(dev, AB8500_TVOUT_CTRL), + AB8500_TVOUT_CTRL2, ab8500_rreg(dev, AB8500_TVOUT_CTRL2), + AB8500_IT_MASK1, ab8500_rreg(dev, AB8500_IT_MASK1) ); if (data_size >= DEBUG_BUF_SIZE) { printk(KERN_EMERG "AB8500 DENC: Buffer overrun\n"); |