Added support for On Chip OTP in i.MX23/28
Subsystems (6)
cover Added support for On Chip OTP in i.MX23/28
From: "Christoph G. Baumann" <[email protected]>
This patch contains the ported driver from Freescale for the On Chip OTP cells in the i.MX23 and i.MX28. The OTP cells can be read and written via files in /sys/fsl_otp.
Christoph G. Baumann (3):
Added support for On Chip OTP in i.MX23/28
Added support for On Chip OTP in i.MX23/28
Added support for On Chip OTP in i.MX23/28
arch/arm/boot/dts/imx28.dtsi | 1 - arch/arm/mach-mxs/include/mach/mx23-ocotp.h | 311 +++++++++++++++++++++++++++ arch/arm/mach-mxs/include/mach/mx28-ocotp.h | 239 ++++++++++++++++++++ drivers/clk/mxs/clk-imx23.c | 2 + drivers/clk/mxs/clk-imx28.c | 1 + drivers/misc/Kconfig | 14 ++ drivers/misc/Makefile | 1 + drivers/misc/fsl_otp.c | 249 +++++++++++++++++++++ drivers/misc/fsl_otp.h | 201 +++++++++++++++++ 9 files changed, 1018 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.h
Signature · 1 line
1.7.9.5
PATCH 1/3 Added support for On Chip OTP in i.MX23/28
From: "Christoph G. Baumann" <[email protected]>
--- drivers/misc/fsl_otp.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/fsl_otp.h | 201 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.h
drivers/misc/fsl_otp.c new file +249 -0
@@ -0,0 +1,249 @@ +/* +* Freescale On-Chip OTP driver +* +* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. +* +* Ported to 3.7 by Christoph G. Baumann <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/fcntl.h> +#include <linux/mutex.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/platform_device.h> + +#include "fsl_otp.h" + +static DEFINE_MUTEX (otp_mutex); +static struct kobject *otp_kobj; +static struct attribute **attrs; +static struct kobj_attribute *kattr; +static struct attribute_group attr_group; + +static inline unsigned int get_reg_index (struct kobj_attribute *tmp) +{ +return tmp - kattr; +} + +static int otp_wait_busy (u32 flags) +{ +int count; +u32 c; + +for (count =10000 ; count >=0 ; count--) { + c =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CTRL ); +if (!(c & (BM_OCOTP_CTRL_BUSY |BM_OCOTP_CTRL_ERROR | flags))) +break ; +cpu_relax (); + } + +if (count <0 ) +return -ETIMEDOUT ; +return 0 ; +} + +static ssize_t otp_show (struct kobject *kobj,struct kobj_attribute *attr, +char *buf) +{ +unsigned int index =get_reg_index (attr); +u32 value =0 ; + +/* sanity check */ +if (index >= otp_data.fuse_num) +return 0 ; + +mutex_lock (&otp_mutex); + +if (otp_read_prepare ()) { +mutex_unlock (&otp_mutex); +return 0 ; + } + value =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CUST_N (index)); +otp_read_post (); + +mutex_unlock (&otp_mutex); +return sprintf (buf,"0x%x\n" , value); +} + +static int otp_write_bits (int addr,u32 data,u32 magic) +{ +u32 c;/* for control register */ + +/* init the control register */ + c =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CTRL ); + c &= ~BM_OCOTP_CTRL_ADDR ; + c |=BF (addr,OCOTP_CTRL_ADDR ); + c |=BF (magic,OCOTP_CTRL_WR_UNLOCK ); +__raw_writel (c,REGS_OCOTP_BASE +HW_OCOTP_CTRL ); + +/* init the data register */ +__raw_writel (data,REGS_OCOTP_BASE +HW_OCOTP_DATA ); +otp_wait_busy (0 ); + +mdelay (2 );/* Write Postamble */ +return 0 ; +} + +static ssize_t otp_store (struct kobject *kobj,struct kobj_attribute *attr, +const char *buf,size_t count) +{ +unsigned int index =get_reg_index (attr); +int value; + +/* sanity check */ +if (index >= otp_data.fuse_num) +return 0 ; + +sscanf (buf,"0x%x" , &value); + +mutex_lock (&otp_mutex); +if (otp_write_prepare ()) { +mutex_unlock (&otp_mutex); +return 0 ; + } +otp_write_bits (index, value,0x3e77 ); +otp_write_post (); +mutex_unlock (&otp_mutex); + +return count; +} + +static void free_otp_attr (void ) +{ +kfree (attrs); + attrs =NULL ; + +kfree (kattr); + kattr =NULL ; +} + +static int alloc_otp_attr (void ) +{ +int i; + +/* The last one is NULL, which is used to detect the end */ + attrs =kzalloc ((otp_data.fuse_num +1 ) *sizeof (attrs[0 ]), +GFP_KERNEL ); + kattr =kzalloc (otp_data.fuse_num *sizeof (struct kobj_attribute ), +GFP_KERNEL ); + +if (!attrs || !kattr) + goto error_out; + +for (i =0 ; i < otp_data.fuse_num; i++) { + kattr[i].attr.name = otp_data.fuse_name[i]; + kattr[i].attr.mode =0600 ; + kattr[i].show = otp_show; + kattr[i].store = otp_store; + attrs[i] = &kattr[i].attr; +sysfs_attr_init (attrs[i]); + } +memset (&attr_group,0 ,sizeof (attr_group)); + attr_group.attrs = attrs; +return 0 ; + +error_out: +free_otp_attr (); +return -ENOMEM ; +} + +static int fsl_otp_probe (struct platform_device *pdev) +{ +int retval; +struct fsl_otp_data *pdata; + + + pdata = &otp_data; +if (pdev->dev.platform_data ==NULL ) + pdev->dev.platform_data = &otp_data; + + retval =alloc_otp_attr (); +if (retval) +return retval; + + retval =map_ocotp_addr (pdev); +if (retval) + goto error; + + otp_kobj =kobject_create_and_add ("fsl_otp" ,NULL ); +if (!otp_kobj) { + retval = -ENOMEM ; + goto error; + } + + retval =sysfs_create_group (otp_kobj, &attr_group); +if (retval) + goto error; + +mutex_init (&otp_mutex); +return 0 ; +error: +kobject_put (otp_kobj); + otp_kobj =NULL ; +free_otp_attr (); +unmap_ocotp_addr (); +return retval; +} + +static int otp_remove (struct platform_device *pdev) +{ +kobject_put (otp_kobj); + otp_kobj =NULL ; + +free_otp_attr (); +unmap_ocotp_addr (); +return 0 ; +} + +static const struct of_device_id mxs_otp_dt_ids[] = { + { .compatible ="fsl,ocotp" , .data =NULL , }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, mxs_otp_dt_ids); + +static struct platform_driver ocotp_driver = { + .probe = fsl_otp_probe, + .remove = otp_remove, + .driver = { + .name ="ocotp" , + .owner =THIS_MODULE , + .of_match_table = mxs_otp_dt_ids, + }, +}; + +static int __init fsl_otp_init (void ) +{ +return platform_driver_register (&ocotp_driver); +} + +static void __exit fsl_otp_exit(void) +{ +platform_driver_unregister (&ocotp_driver); +} +module_init (fsl_otp_init); +module_exit (fsl_otp_exit); + +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Huang Shijie <[email protected]>" ); +MODULE_DESCRIPTION ("Common driver for OTP controller" );
drivers/misc/fsl_otp.h new file +201 -0
201 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 1/3 Added support for On Chip OTP in i.MX23/28
Hi Christoph,
Quoted 16 lines · Christoph G. Baumann
From: "Christoph G. Baumann" <[email protected]>
Signed-off-by Christoph G. Baumann <[email protected]>--- drivers/misc/fsl_otp.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/fsl_otp.h | 201 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.hdrivers/misc/fsl_otp.c new file +0
-0
drivers/misc/fsl_otp.c line 6
Quoted 6 lines
drivers/misc/fsl_otp.c new file +6
-0@@ -0,0 +1,249 @@ +/* +* Freescale On-Chip OTP driver +* +* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. +* +* Ported to 3.7 by Christoph G. Baumann <[email protected]>
Maybe it's not worth mentionning the version here, since it's wrong anyway.
Quoted 84 lines
drivers/misc/fsl_otp.c new file +84
-0+* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/fcntl.h> +#include <linux/mutex.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/platform_device.h> + +#include "fsl_otp.h" + +static DEFINE_MUTEX (otp_mutex); +static struct kobject *otp_kobj; +static struct attribute **attrs; +static struct kobj_attribute *kattr; +static struct attribute_group attr_group; + +static inline unsigned int get_reg_index (struct kobj_attribute *tmp) +{ +return tmp - kattr; +} + +static int otp_wait_busy (u32 flags) +{ +int count; +u32 c; + +for (count =10000 ; count >=0 ; count--) { + c =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CTRL ); +if (!(c & (BM_OCOTP_CTRL_BUSY |BM_OCOTP_CTRL_ERROR | flags))) +break ; +cpu_relax (); + } + +if (count <0 ) +return -ETIMEDOUT ; +return 0 ; +} + +static ssize_t otp_show (struct kobject *kobj,struct kobj_attribute *attr, +char *buf) +{ +unsigned int index =get_reg_index (attr); +u32 value =0 ; + +/* sanity check */ +if (index >= otp_data.fuse_num) +return 0 ; + +mutex_lock (&otp_mutex); + +if (otp_read_prepare ()) { +mutex_unlock (&otp_mutex); +return 0 ; + } + value =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CUST_N (index)); +otp_read_post (); + +mutex_unlock (&otp_mutex); +return sprintf (buf,"0x%x\n" , value); +} + +static int otp_write_bits (int addr,u32 data,u32 magic) +{ +u32 c;/* for control register */
drivers/misc/fsl_otp.c line 101
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+ +/* init the control register */ + c =__raw_readl (REGS_OCOTP_BASE +HW_OCOTP_CTRL ); + c &= ~BM_OCOTP_CTRL_ADDR ; + c |=BF (addr,OCOTP_CTRL_ADDR ); + c |=BF (magic,OCOTP_CTRL_WR_UNLOCK ); +__raw_writel (c,REGS_OCOTP_BASE +HW_OCOTP_CTRL ); + +/* init the data register */ +__raw_writel (data,REGS_OCOTP_BASE +HW_OCOTP_DATA );
You shouldn't use __raw_readl/__raw_writel directly here, but readl/writel. The __raw_* functions lack the endianness conversions and the memory barrier readl has.
drivers/misc/fsl_otp.c line 104
Quoted 3 lines
drivers/misc/fsl_otp.c new file +3
-0+otp_wait_busy (0 ); + +mdelay (2 );/* Write Postamble */
Why do you need the mdelay after your call to otp_wait_busy ?
Quoted 11 lines
drivers/misc/fsl_otp.c new file +11
-0+return 0 ; +} + +static ssize_t otp_store (struct kobject *kobj,struct kobj_attribute *attr, +const char *buf,size_t count) +{ +unsigned int index =get_reg_index (attr); +int value; + +/* sanity check */ +if (index >= otp_data.fuse_num)
drivers/misc/fsl_otp.c line 125
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+return 0 ; + +sscanf (buf,"0x%x" , &value); + +mutex_lock (&otp_mutex); +if (otp_write_prepare ()) { +mutex_unlock (&otp_mutex); +return 0 ; + } +otp_write_bits (index, value,0x3e77 );
What's that magic value?
Quoted 36 lines
drivers/misc/fsl_otp.c new file +36
-0+otp_write_post (); +mutex_unlock (&otp_mutex); + +return count; +} + +static void free_otp_attr (void ) +{ +kfree (attrs); + attrs =NULL ; + +kfree (kattr); + kattr =NULL ; +} + +static int alloc_otp_attr (void ) +{ +int i; + +/* The last one is NULL, which is used to detect the end */ + attrs =kzalloc ((otp_data.fuse_num +1 ) *sizeof (attrs[0 ]), +GFP_KERNEL ); + kattr =kzalloc (otp_data.fuse_num *sizeof (struct kobj_attribute ), +GFP_KERNEL ); + +if (!attrs || !kattr) + goto error_out; + +for (i =0 ; i < otp_data.fuse_num; i++) { + kattr[i].attr.name = otp_data.fuse_name[i]; + kattr[i].attr.mode =0600 ; + kattr[i].show = otp_show; + kattr[i].store = otp_store; + attrs[i] = &kattr[i].attr; +sysfs_attr_init (attrs[i]); + }
drivers/misc/fsl_otp.c line 171
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+memset (&attr_group,0 ,sizeof (attr_group)); + attr_group.attrs = attrs; +return 0 ; + +error_out: +free_otp_attr (); +return -ENOMEM ; +} + +static int fsl_otp_probe (struct platform_device *pdev)
Your function names could use some common prefix, it's a bit messy for now. You have:
- free_otp_*
- otp_*
- fsl_otp_*
You could use the prefix mxs_otp for all your functions, for example.
drivers/misc/fsl_otp.c line 179
Quoted 8 lines
drivers/misc/fsl_otp.c new file +8
-0+{ +int retval; +struct fsl_otp_data *pdata; + + + pdata = &otp_data; +if (pdev->dev.platform_data ==NULL ) + pdev->dev.platform_data = &otp_data;
Where is that otp_data coming from?
Quoted 16 lines
drivers/misc/fsl_otp.c new file +16
-0+ + retval =alloc_otp_attr (); +if (retval) +return retval; + + retval =map_ocotp_addr (pdev); +if (retval) + goto error; + + otp_kobj =kobject_create_and_add ("fsl_otp" ,NULL ); +if (!otp_kobj) { + retval = -ENOMEM ; + goto error; + } + + retval =sysfs_create_group (otp_kobj, &attr_group);
drivers/misc/fsl_otp.c line 205
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+if (retval) + goto error; + +mutex_init (&otp_mutex); +return 0 ; +error: +kobject_put (otp_kobj); + otp_kobj =NULL ; +free_otp_attr (); +unmap_ocotp_addr ();
Where is that unmap_ocotp_addr function declared?
drivers/misc/fsl_otp.c line 215
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+return retval; +} + +static int otp_remove (struct platform_device *pdev) +{ +kobject_put (otp_kobj); + otp_kobj =NULL ; + +free_otp_attr (); +unmap_ocotp_addr ();
Ditto.
Quoted 20 lines
drivers/misc/fsl_otp.c new file +20
-0+return 0 ; +} + +static const struct of_device_id mxs_otp_dt_ids[] = { + { .compatible ="fsl,ocotp" , .data =NULL , }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, mxs_otp_dt_ids); + +static struct platform_driver ocotp_driver = { + .probe = fsl_otp_probe, + .remove = otp_remove, + .driver = { + .name ="ocotp" , + .owner =THIS_MODULE , + .of_match_table = mxs_otp_dt_ids, + }, +}; + +static int __init fsl_otp_init (void )
drivers/misc/fsl_otp.c line 245
Quoted 10 lines
drivers/misc/fsl_otp.c new file +10
-0+{ +return platform_driver_register (&ocotp_driver); +} + +static void __exit fsl_otp_exit(void) +{ +platform_driver_unregister (&ocotp_driver); +} +module_init (fsl_otp_init); +module_exit (fsl_otp_exit);
You can use module_platform_driver here to remove all this boilerplate code.
Quoted 42 lines
drivers/misc/fsl_otp.c new file +3
-0+MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Huang Shijie <[email protected]>" ); +MODULE_DESCRIPTION ("Common driver for OTP controller" );drivers/misc/fsl_otp.h new file +33
-0@@ -0,0 +1,201 @@ +/* +* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. +* +* Ported to 3.7 by Christoph G. Baumann <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef __FREESCALE_OTP__ +#define __FREESCALE_OTP__ + + +static int otp_wait_busy (u32 flags); + +/* IMX23 and IMX28 share most of the defination ========================= */ +#if (defined(CONFIG_SOC_IMX23 ) || defined(CONFIG_SOC_IMX28 )) + +#if defined(CONFIG_SOC_IMX28 ) && defined(CONFIG_SOC_IMX23 ) +#undef CONFIG_SOC_IMX23 +#endif + +#include <linux/regulator/consumer.h>
drivers/misc/fsl_otp.h line 43
Quoted 10 lines
drivers/misc/fsl_otp.h new file +10
-0+#include <mach/hardware.h> +#include <mach/mxs.h> + +#if defined(CONFIG_SOC_IMX23 ) +#include <mach/mx23.h> +#include <mach/mx23-ocotp.h> +#else +#include <mach/mx28.h> +#include <mach/mx28-ocotp.h> +#endif
Are you even sure it compiles? These headers don't exist.
Also, now that the mxs platform enabled multi-platform support, you have to keep in mind that this driver can be used on both an imx23 *and* an imx28 at run time, so all these compile-time options should be removed.
Quoted 143 lines
drivers/misc/fsl_otp.h new file +143
-0+#define OCOTP_PHYS_ADDR MXS_OCOTP_BASE_ADDR +#define REGS_OCOTP_BASE (MXS_IO_ADDRESS(OCOTP_PHYS_ADDR)) +#define BF (value, field) (((value) << BP_##field) & BM_##field) + +#if defined(CONFIG_SOC_IMX28 ) +/* Building up eight registers's names of a bank */ +#define MXS_OTP_BANK (a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define MXS_OTP_BANKS (5) +#define MXS_OTP_BANK_ITEMS (8) +static const char *bank_reg_desc[MXS_OTP_BANKS ][MXS_OTP_BANK_ITEMS ] = { +MXS_OTP_BANK (CUST0 ,CUST1 ,CUST2 ,CUST3 ,CRYPTO0 ,CRYPTO1 ,CRYPTO2 ,CRYPTO3 ), +MXS_OTP_BANK (HWCAP0 ,HWCAP1 ,HWCAP2 ,HWCAP3 ,HWCAP4 ,HWCAP5 ,SWCAP ,CUSTCAP ), +MXS_OTP_BANK (LOCK ,OPS0 ,OPS1 ,OPS2 ,OPS3 ,UN0 ,UN1 ,UN2 ), +MXS_OTP_BANK (ROM0 ,ROM1 ,ROM2 ,ROM3 ,ROM4 ,ROM5 ,ROM6 ,ROM7 ), +MXS_OTP_BANK (SRK0 ,SRK1 ,SRK2 ,SRK3 ,SRK4 ,SRK5 ,SRK6 ,SRK7 ), +}; +#endif /* if defined(CONFIG_SOC_IMX28) */ + + +#if defined(CONFIG_SOC_IMX23 ) +/* Building up eight registers's names of a bank */ +#define MXS_OTP_BANK (a, b, c, d, e, f, g, h) \ + {\ + ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \ + ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \ + } + +#define MXS_OTP_BANKS (4) +#define MXS_OTP_BANK_ITEMS (8) +static const char *bank_reg_desc[MXS_OTP_BANKS ][MXS_OTP_BANK_ITEMS ] = { +MXS_OTP_BANK (CUST0 ,CUST1 ,CUST2 ,CUST3 ,CRYPTO0 ,CRYPTO1 ,CRYPTO2 ,CRYPTO3 ), +MXS_OTP_BANK (HWCAP0 ,HWCAP1 ,HWCAP2 ,HWCAP3 ,HWCAP4 ,HWCAP5 ,SWCAP ,CUSTCAP ), +MXS_OTP_BANK (LOCK ,OPS0 ,OPS1 ,OPS2 ,OPS3 ,UN0 ,UN1 ,UN2 ), +MXS_OTP_BANK (ROM0 ,ROM1 ,ROM2 ,ROM3 ,ROM4 ,ROM5 ,ROM6 ,ROM7 ), +}; + +#endif /* if defined(CONFIG_SOC_IMX23) */ + +static unsigned long otp_hclk_saved; +static u32 otp_voltage_saved; +struct regulator *regu; + +struct fsl_otp_data { +char **fuse_name; +char *regulator_name; +unsigned int fuse_num; +}; + +static struct fsl_otp_data otp_data = { + .fuse_name = (char **)bank_reg_desc, + .regulator_name ="vddio-sd0" , + .fuse_num =MXS_OTP_BANKS *MXS_OTP_BANK_ITEMS , +}; + +/* open the bank for the imx23/imx28 */ +static int otp_read_prepare (void ) +{ +int r; + +/* [1] set the HCLK */ +/* [2] check BUSY and ERROR bit */ + r =otp_wait_busy (0 ); +if (r <0 ) + goto error; + +/* [3] open bank */ +__raw_writel (BM_OCOTP_CTRL_RD_BANK_OPEN , +REGS_OCOTP_BASE +HW_OCOTP_CTRL_SET ); +udelay (10 ); + +/* [4] wait for BUSY */ + r =otp_wait_busy (0 ); +return 0 ; +error: +return r; +} + +static int otp_read_post (void ) +{ +/* [5] close bank */ +__raw_writel (BM_OCOTP_CTRL_RD_BANK_OPEN , +REGS_OCOTP_BASE +HW_OCOTP_CTRL_CLR ); +return 0 ; +} + +static int otp_write_prepare (void ) +{ +struct clk *hclk; +int err =0 ; + +/* [1] HCLK to 24MHz. */ + hclk =clk_get_sys ("hbus" ,NULL ); +if (IS_ERR (hclk)) { + err =PTR_ERR (hclk); + goto out; + } +/* +WARNING ACHTUNG UWAGA + +the code below changes HCLK clock rate to 24M. This is +required to write OTP bits (7.2.2 in STMP378x Target +Specification), and might affect LCD operation, for example. +Moreover, this hacky code changes VDDIO to 2.8V; and resto- +res it only on otp_close(). This may affect... anything. + +You are warned now. +*/ + otp_hclk_saved =clk_get_rate (hclk); +clk_set_rate (hclk,24000000 ); + +/* [2] The voltage is set to 2.8V */ + regu =regulator_get (NULL , otp_data.regulator_name); + otp_voltage_saved =regulator_get_voltage (regu); +regulator_set_voltage (regu,2800000 ,2800000 ); + +/* [3] wait for BUSY and ERROR */ + err =otp_wait_busy (BM_OCOTP_CTRL_RD_BANK_OPEN ); +out: +return err; +} + +static int otp_write_post (void ) +{ +struct clk *hclk; + + hclk =clk_get_sys ("hbus" ,NULL ); +if (IS_ERR (hclk)) +return PTR_ERR (hclk); + +/* restore the clock and voltage */ +clk_set_rate (hclk, otp_hclk_saved); +regulator_set_voltage (regu, otp_voltage_saved, otp_voltage_saved); +otp_wait_busy (0 ); + +/* reset */ +__raw_writel (BM_OCOTP_CTRL_RELOAD_SHADOWS , +REGS_OCOTP_BASE +HW_OCOTP_CTRL_SET ); +otp_wait_busy (BM_OCOTP_CTRL_RELOAD_SHADOWS );
drivers/misc/fsl_otp.h line 197
Quoted 10 lines
drivers/misc/fsl_otp.h new file +10
-0+return 0 ; +} + +static int __init map_ocotp_addr (struct platform_device *pdev) +{ +return 0 ; +} +static void unmap_ocotp_addr (void ) +{ +}
Ah, so here are your functions and structures. Putting !inline functions in a header is considered a bad practice, so you should move them in the driver directly.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/4bca9dbb/attachment.sig>
PATCH 2/3 Added support for On Chip OTP in i.MX23/28
In reply to Christoph G. BaumannFrom: "Christoph G. Baumann" <[email protected]>
--- arch/arm/mach-mxs/include/mach/mx23-ocotp.h | 311 +++++++++++++++++++++++++++ arch/arm/mach-mxs/include/mach/mx28-ocotp.h | 239 ++++++++++++++++++++ 2 files changed, 550 insertions(+) create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h
arch/arm/mach-mxs/include/mach/mx23-ocotp.h new file +311 -0
@@ -0,0 +1,311 @@ +/* +* Freescale OCOTP Register Definitions +* +* Copyright 2008-2010 Freescale Semiconductor, Inc. +* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* This file is created by xml file. Don't Edit it. +* +* Xml Revision: 1.21 +* Template revision: 26195 +*/ + +#ifndef __ARCH_ARM___OCOTP_H +#define __ARCH_ARM___OCOTP_H + + +#define HW_OCOTP_CTRL (0x00000000) +#define HW_OCOTP_CTRL_SET (0x00000004) +#define HW_OCOTP_CTRL_CLR (0x00000008) +#define HW_OCOTP_CTRL_TOG (0x0000000c) + +#define BP_OCOTP_CTRL_WR_UNLOCK 16 +#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000 +#define BF_OCOTP_CTRL_WR_UNLOCK (v) \ + (((v) << 16) & BM_OCOTP_CTRL_WR_UNLOCK) +#define BV_OCOTP_CTRL_WR_UNLOCK__KEY 0x3E77 +#define BP_OCOTP_CTRL_RSRVD2 14 +#define BM_OCOTP_CTRL_RSRVD2 0x0000C000 +#define BF_OCOTP_CTRL_RSRVD2 (v) \ + (((v) << 14) & BM_OCOTP_CTRL_RSRVD2) +#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00002000 +#define BM_OCOTP_CTRL_RD_BANK_OPEN 0x00001000 +#define BP_OCOTP_CTRL_RSRVD1 10 +#define BM_OCOTP_CTRL_RSRVD1 0x00000C00 +#define BF_OCOTP_CTRL_RSRVD1 (v) \ + (((v) << 10) & BM_OCOTP_CTRL_RSRVD1) +#define BM_OCOTP_CTRL_ERROR 0x00000200 +#define BM_OCOTP_CTRL_BUSY 0x00000100 +#define BP_OCOTP_CTRL_RSRVD0 5 +#define BM_OCOTP_CTRL_RSRVD0 0x000000E0 +#define BF_OCOTP_CTRL_RSRVD0 (v) \ + (((v) << 5) & BM_OCOTP_CTRL_RSRVD0) +#define BP_OCOTP_CTRL_ADDR 0 +#define BM_OCOTP_CTRL_ADDR 0x0000001F +#define BF_OCOTP_CTRL_ADDR (v) \ + (((v) << 0) & BM_OCOTP_CTRL_ADDR) + +#define HW_OCOTP_DATA (0x00000010) + +#define BP_OCOTP_DATA_DATA 0 +#define BM_OCOTP_DATA_DATA 0xFFFFFFFF +#define BF_OCOTP_DATA_DATA (v) (v) + +/* +* multi-register-define name HW_OCOTP_CUST_N +* base 0x00000020 +* count 4 +* offset 0x10 +*/ +#define HW_OCOTP_CUST_N (n) (0x00000020 + (n) * 0x10) +#define BP_OCOTP_CUST_N_BITS 0 +#define BM_OCOTP_CUST_N_BITS 0xFFFFFFFF +#define BF_OCOTP_CUST_N_BITS (v) (v) + +/* +* multi-register-define name HW_OCOTP_CRYPTO_N +* base 0x00000060 +* count 4 +* offset 0x10 +*/ +#define HW_OCOTP_CRYPTO_N (n) (0x00000060 + (n) * 0x10) +#define BP_OCOTP_CRYPTO_N_BITS 0 +#define BM_OCOTP_CRYPTO_N_BITS 0xFFFFFFFF +#define BF_OCOTP_CRYPTO_N_BITS (v) (v) + +/* +* multi-register-define name HW_OCOTP_HWCAP_N +* base 0x000000A0 +* count 6 +* offset 0x10 +*/ +#define HW_OCOTP_HWCAP_N (n) (0x000000a0 + (n) * 0x10) +#define BP_OCOTP_HWCAP_N_BITS 0 +#define BM_OCOTP_HWCAP_N_BITS 0xFFFFFFFF +#define BF_OCOTP_HWCAP_N_BITS (v) (v) + +#define HW_OCOTP_SWCAP (0x00000100) + +#define BP_OCOTP_SWCAP_BITS 0 +#define BM_OCOTP_SWCAP_BITS 0xFFFFFFFF +#define BF_OCOTP_SWCAP_BITS (v) (v) + +#define HW_OCOTP_CUSTCAP (0x00000110) + +#define BM_OCOTP_CUSTCAP_CUST_DISABLE_WMADRM9 0x80000000 +#define BM_OCOTP_CUSTCAP_CUST_DISABLE_JANUSDRM10 0x40000000 +#define BP_OCOTP_CUSTCAP_RSRVD1 5 +#define BM_OCOTP_CUSTCAP_RSRVD1 0x3FFFFFE0 +#define BF_OCOTP_CUSTCAP_RSRVD1 (v) \ + (((v) << 5) & BM_OCOTP_CUSTCAP_RSRVD1) +#define BM_OCOTP_CUSTCAP_ENABLE_SJTAG_12MA_DRIVE 0x00000010 +#define BM_OCOTP_CUSTCAP_USE_PARALLEL_JTAG 0x00000008 +#define BM_OCOTP_CUSTCAP_RTC_XTAL_32768_PRESENT 0x00000004 +#define BM_OCOTP_CUSTCAP_RTC_XTAL_32000_PRESENT 0x00000002 +#define BM_OCOTP_CUSTCAP_RSRVD0 0x00000001 + +#define HW_OCOTP_LOCK (0x00000120) + +#define BM_OCOTP_LOCK_ROM7 0x80000000 +#define BM_OCOTP_LOCK_ROM6 0x40000000 +#define BM_OCOTP_LOCK_ROM5 0x20000000 +#define BM_OCOTP_LOCK_ROM4 0x10000000 +#define BM_OCOTP_LOCK_ROM3 0x08000000 +#define BM_OCOTP_LOCK_ROM2 0x04000000 +#define BM_OCOTP_LOCK_ROM1 0x02000000 +#define BM_OCOTP_LOCK_ROM0 0x01000000 +#define BM_OCOTP_LOCK_HWSW_SHADOW_ALT 0x00800000 +#define BM_OCOTP_LOCK_CRYPTODCP_ALT 0x00400000 +#define BM_OCOTP_LOCK_CRYPTOKEY_ALT 0x00200000 +#define BM_OCOTP_LOCK_PIN 0x00100000 +#define BM_OCOTP_LOCK_OPS 0x00080000 +#define BM_OCOTP_LOCK_UN2 0x00040000 +#define BM_OCOTP_LOCK_UN1 0x00020000 +#define BM_OCOTP_LOCK_UN0 0x00010000 +#define BP_OCOTP_LOCK_UNALLOCATED 11 +#define BM_OCOTP_LOCK_UNALLOCATED 0x0000F800 +#define BF_OCOTP_LOCK_UNALLOCATED (v) \ + (((v) << 11) & BM_OCOTP_LOCK_UNALLOCATED) +#define BM_OCOTP_LOCK_ROM_SHADOW 0x00000400 +#define BM_OCOTP_LOCK_CUSTCAP 0x00000200 +#define BM_OCOTP_LOCK_HWSW 0x00000100 +#define BM_OCOTP_LOCK_CUSTCAP_SHADOW 0x00000080 +#define BM_OCOTP_LOCK_HWSW_SHADOW 0x00000040 +#define BM_OCOTP_LOCK_CRYPTODCP 0x00000020 +#define BM_OCOTP_LOCK_CRYPTOKEY 0x00000010 +#define BM_OCOTP_LOCK_CUST3 0x00000008 +#define BM_OCOTP_LOCK_CUST2 0x00000004 +#define BM_OCOTP_LOCK_CUST1 0x00000002 +#define BM_OCOTP_LOCK_CUST0 0x00000001 + +/* +* multi-register-define name HW_OCOTP_OPS_N +* base 0x00000130 +* count 4 +* offset 0x10 +*/ +#define HW_OCOTP_OPS_N (n) (0x00000130 + (n) * 0x10) +#define BP_OCOTP_OPS_N_BITS 0 +#define BM_OCOTP_OPS_N_BITS 0xFFFFFFFF +#define BF_OCOTP_OPS_N_BITS (v) (v) + +/* +* multi-register-define name HW_OCOTP_UN_N +* base 0x00000170 +* count 3 +* offset 0x10 +*/ +#define HW_OCOTP_UN_N (n) (0x00000170 + (n) * 0x10) +#define BP_OCOTP_UN_N_BITS 0 +#define BM_OCOTP_UN_N_BITS 0xFFFFFFFF +#define BF_OCOTP_UN_N_BITS (v) (v) + +#define HW_OCOTP_ROM0 (0x000001a0) + +#define BP_OCOTP_ROM0_BOOT_MODE 24 +#define BM_OCOTP_ROM0_BOOT_MODE 0xFF000000 +#define BF_OCOTP_ROM0_BOOT_MODE (v) \ + (((v) << 24) & BM_OCOTP_ROM0_BOOT_MODE) +#define BM_OCOTP_ROM0_ENABLE_PJTAG_12MA_DRIVE 0x00800000 +#define BM_OCOTP_ROM0_USE_PARALLEL_JTAG 0x00400000 +#define BP_OCOTP_ROM0_SD_POWER_GATE_GPIO 20 +#define BM_OCOTP_ROM0_SD_POWER_GATE_GPIO 0x00300000 +#define BF_OCOTP_ROM0_SD_POWER_GATE_GPIO (v) \ + (((v) << 20) & BM_OCOTP_ROM0_SD_POWER_GATE_GPIO) +#define BP_OCOTP_ROM0_SD_POWER_UP_DELAY 14 +#define BM_OCOTP_ROM0_SD_POWER_UP_DELAY 0x000FC000 +#define BF_OCOTP_ROM0_SD_POWER_UP_DELAY (v) \ + (((v) << 14) & BM_OCOTP_ROM0_SD_POWER_UP_DELAY) +#define BP_OCOTP_ROM0_SD_BUS_WIDTH 12 +#define BM_OCOTP_ROM0_SD_BUS_WIDTH 0x00003000 +#define BF_OCOTP_ROM0_SD_BUS_WIDTH (v) \ + (((v) << 12) & BM_OCOTP_ROM0_SD_BUS_WIDTH) +#define BP_OCOTP_ROM0_SSP_SCK_INDEX 8 +#define BM_OCOTP_ROM0_SSP_SCK_INDEX 0x00000F00 +#define BF_OCOTP_ROM0_SSP_SCK_INDEX (v) \ + (((v) << 8) & BM_OCOTP_ROM0_SSP_SCK_INDEX) +#define BM_OCOTP_ROM0_RSRVD3 0x00000080 +#define BM_OCOTP_ROM0_DISABLE_SPI_NOR_FAST_READ 0x00000040 +#define BM_OCOTP_ROM0_ENABLE_USB_BOOT_SERIAL_NUM 0x00000020 +#define BM_OCOTP_ROM0_ENABLE_UNENCRYPTED_BOOT 0x00000010 +#define BM_OCOTP_ROM0_SD_MBR_BOOT 0x00000008 +#define BM_OCOTP_ROM0_RSRVD2 0x00000004 +#define BM_OCOTP_ROM0_RSRVD1 0x00000002 +#define BM_OCOTP_ROM0_RSRVD0 0x00000001 + +#define HW_OCOTP_ROM1 (0x000001b0) + +#define BP_OCOTP_ROM1_RSRVD1 30 +#define BM_OCOTP_ROM1_RSRVD1 0xC0000000 +#define BF_OCOTP_ROM1_RSRVD1 (v) \ + (((v) << 30) & BM_OCOTP_ROM1_RSRVD1) +#define BP_OCOTP_ROM1_USE_ALT_GPMI_RDY3 28 +#define BM_OCOTP_ROM1_USE_ALT_GPMI_RDY3 0x30000000 +#define BF_OCOTP_ROM1_USE_ALT_GPMI_RDY3 (v) \ + (((v) << 28) & BM_OCOTP_ROM1_USE_ALT_GPMI_RDY3) +#define BP_OCOTP_ROM1_USE_ALT_GPMI_CE3 26 +#define BM_OCOTP_ROM1_USE_ALT_GPMI_CE3 0x0C000000 +#define BF_OCOTP_ROM1_USE_ALT_GPMI_CE3 (v) \ + (((v) << 26) & BM_OCOTP_ROM1_USE_ALT_GPMI_CE3) +#define BM_OCOTP_ROM1_USE_ALT_GPMI_RDY2 0x02000000 +#define BM_OCOTP_ROM1_USE_ALT_GPMI_CE2 0x01000000 +#define BM_OCOTP_ROM1_ENABLE_NAND3_CE_RDY_PULLUP 0x00800000 +#define BM_OCOTP_ROM1_ENABLE_NAND2_CE_RDY_PULLUP 0x00400000 +#define BM_OCOTP_ROM1_ENABLE_NAND1_CE_RDY_PULLUP 0x00200000 +#define BM_OCOTP_ROM1_ENABLE_NAND0_CE_RDY_PULLUP 0x00100000 +#define BM_OCOTP_ROM1_UNTOUCH_INTERNAL_SSP_PULLUP 0x00080000 +#define BM_OCOTP_ROM1_SSP2_EXT_PULLUP 0x00040000 +#define BM_OCOTP_ROM1_SSP1_EXT_PULLUP 0x00020000 +#define BM_OCOTP_ROM1_SD_INCREASE_INIT_SEQ_TIME 0x00010000 +#define BM_OCOTP_ROM1_SD_INIT_SEQ_2_ENABLE 0x00008000 +#define BM_OCOTP_ROM1_SD_CMD0_DISABLE 0x00004000 +#define BM_OCOTP_ROM1_SD_INIT_SEQ_1_DISABLE 0x00002000 +#define BM_OCOTP_ROM1_USE_ALT_SSP1_DATA4_7 0x00001000 +#define BP_OCOTP_ROM1_BOOT_SEARCH_COUNT 8 +#define BM_OCOTP_ROM1_BOOT_SEARCH_COUNT 0x00000F00 +#define BF_OCOTP_ROM1_BOOT_SEARCH_COUNT (v) \ + (((v) << 8) & BM_OCOTP_ROM1_BOOT_SEARCH_COUNT) +#define BP_OCOTP_ROM1_RSRVD0 3 +#define BM_OCOTP_ROM1_RSRVD0 0x000000F8 +#define BF_OCOTP_ROM1_RSRVD0 (v) \ + (((v) << 3) & BM_OCOTP_ROM1_RSRVD0) +#define BP_OCOTP_ROM1_NUMBER_OF_NANDS 0 +#define BM_OCOTP_ROM1_NUMBER_OF_NANDS 0x00000007 +#define BF_OCOTP_ROM1_NUMBER_OF_NANDS (v) \ + (((v) << 0) & BM_OCOTP_ROM1_NUMBER_OF_NANDS) + +#define HW_OCOTP_ROM2 (0x000001c0) + +#define BP_OCOTP_ROM2_USB_VID 16 +#define BM_OCOTP_ROM2_USB_VID 0xFFFF0000 +#define BF_OCOTP_ROM2_USB_VID (v) \ + (((v) << 16) & BM_OCOTP_ROM2_USB_VID) +#define BP_OCOTP_ROM2_USB_PID 0 +#define BM_OCOTP_ROM2_USB_PID 0x0000FFFF +#define BF_OCOTP_ROM2_USB_PID (v) \ + (((v) << 0) & BM_OCOTP_ROM2_USB_PID) + +#define HW_OCOTP_ROM3 (0x000001d0) + +#define BP_OCOTP_ROM3_RSRVD1 10 +#define BM_OCOTP_ROM3_RSRVD1 0xFFFFFC00 +#define BF_OCOTP_ROM3_RSRVD1 (v) \ + (((v) << 10) & BM_OCOTP_ROM3_RSRVD1) +#define BP_OCOTP_ROM3_RSRVD0 0 +#define BM_OCOTP_ROM3_RSRVD0 0x000003FF +#define BF_OCOTP_ROM3_RSRVD0 (v) \ + (((v) << 0) & BM_OCOTP_ROM3_RSRVD0) + +#define HW_OCOTP_ROM4 (0x000001e0) + +#define BP_OCOTP_ROM4_BITS 0 +#define BM_OCOTP_ROM4_BITS 0xFFFFFFFF +#define BF_OCOTP_ROM4_BITS (v) (v) + +#define HW_OCOTP_ROM5 (0x000001f0) + +#define BP_OCOTP_ROM5_BITS 0 +#define BM_OCOTP_ROM5_BITS 0xFFFFFFFF +#define BF_OCOTP_ROM5_BITS (v) (v) + +#define HW_OCOTP_ROM6 (0x00000200) + +#define BP_OCOTP_ROM6_BITS 0 +#define BM_OCOTP_ROM6_BITS 0xFFFFFFFF +#define BF_OCOTP_ROM6_BITS (v) (v) + +#define HW_OCOTP_ROM7 (0x00000210) + +#define BP_OCOTP_ROM7_BITS 0 +#define BM_OCOTP_ROM7_BITS 0xFFFFFFFF +#define BF_OCOTP_ROM7_BITS (v) (v) + +#define HW_OCOTP_VERSION (0x00000220) + +#define BP_OCOTP_VERSION_MAJOR 24 +#define BM_OCOTP_VERSION_MAJOR 0xFF000000 +#define BF_OCOTP_VERSION_MAJOR (v) \ + (((v) << 24) & BM_OCOTP_VERSION_MAJOR) +#define BP_OCOTP_VERSION_MINOR 16 +#define BM_OCOTP_VERSION_MINOR 0x00FF0000 +#define BF_OCOTP_VERSION_MINOR (v) \ + (((v) << 16) & BM_OCOTP_VERSION_MINOR) +#define BP_OCOTP_VERSION_STEP 0 +#define BM_OCOTP_VERSION_STEP 0x0000FFFF +#define BF_OCOTP_VERSION_STEP (v) \ + (((v) << 0) & BM_OCOTP_VERSION_STEP) +#endif /* __ARCH_ARM___OCOTP_H */
arch/arm/mach-mxs/include/mach/mx28-ocotp.h new file +239 -0
239 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH 2/3 Added support for On Chip OTP in i.MX23/28
Hi Christoph,
Quoted 9 lines · Christoph G. Baumann
From: "Christoph G. Baumann" <[email protected]>
Signed-off-by Christoph G. Baumann <[email protected]>--- arch/arm/mach-mxs/include/mach/mx23-ocotp.h | 311 +++++++++++++++++++++++++++ arch/arm/mach-mxs/include/mach/mx28-ocotp.h | 239 ++++++++++++++++++++ 2 files changed, 550 insertions(+) create mode 100644 arch/arm/mach-mxs/include/mach/mx23-ocotp.h create mode 100644 arch/arm/mach-mxs/include/mach/mx28-ocotp.h
Ah. Here are your includes.
Two things then:
- Like I said in my previous mail, the include/mach doesn't play well with the multi-platform kernels. How should you choose one header instead of another in this case, or even one mach/ directory or another if you have several platforms enabled.
- From what I can recall, the OCOTP is only something like a few MMIO bytes to access, with a bit of logic when writing, but nothing more than a few registers and a few bits in there. Are you sure you actually need 550 lines of define for only a dozen defines or so?
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/db5ffe9a/attachment.sig>
PATCH 3/3 Added support for On Chip OTP in i.MX23/28
In reply to Christoph G. BaumannFrom: "Christoph G. Baumann" <[email protected]>
--- arch/arm/boot/dts/imx28.dtsi | 1 - drivers/clk/mxs/clk-imx23.c | 2 ++ drivers/clk/mxs/clk-imx28.c | 1 + drivers/misc/Kconfig | 14 ++++++++++++++ drivers/misc/Makefile | 1 + 5 files changed, 18 insertions(+), 1 deletion(-)
arch/arm/boot/dts/imx28.dtsi +0 -1
@@ -711,7 +711,6 @@ ocotp at 8002c000 { compatible = "fsl,ocotp"; reg = <0x8002c000 0x2000>; - status = "disabled"; }; axi-ahb at 8002e000 {
drivers/clk/mxs/clk-imx23.c +2 -0
@@ -168,6 +168,8 @@ int __init mx23_clocks_init(void) clk_data.clk_num =ARRAY_SIZE (clks);of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data); +clk_register_clkdev (clks[hbus],NULL ,"hbus" ); +for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);
drivers/clk/mxs/clk-imx28.c +1 -0
@@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data);clk_register_clkdev (clks[enet_out],NULL ,"enet_out" ); +clk_register_clkdev (clks[hbus],NULL ,"hbus" );for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);
drivers/misc/Kconfig +14 -0
@@ -527,6 +527,20 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config FSL_OTP + tristate "Freescale On-Chip OTP Memory Support" + depends on SOC_IMX23 || SOC_IMX28 + default n + help + If you say Y here, you will get support for a SysFS interface for + the One Time Programmable memory pages that are stored on the + iMX23/28 processor. + + To compile this driver as a module, choose M here: the module + will be called fsl_otp. + + If unsure, it is safe to say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig"
drivers/misc/Makefile +1 -0
@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o +obj-$(CONFIG_FSL_OTP) += fsl_otp.o
Signature · 1 line
1.7.9.5
PATCH 3/3 Added support for On Chip OTP in i.MX23/28
Hi Christoph,
Quoted 16 lines · Christoph G. Baumann
From: "Christoph G. Baumann" <[email protected]>
Signed-off-by Christoph G. Baumann <[email protected]>--- arch/arm/boot/dts/imx28.dtsi | 1 - drivers/clk/mxs/clk-imx23.c | 2 ++ drivers/clk/mxs/clk-imx28.c | 1 + drivers/misc/Kconfig | 14 ++++++++++++++ drivers/misc/Makefile | 1 + 5 files changed, 18 insertions(+), 1 deletion(-)arch/arm/boot/dts/imx28.dtsi +0
-0
arch/arm/boot/dts/imx28.dtsi line 714
Quoted 5 lines
arch/arm/boot/dts/imx28.dtsi +0
-1@@ -711,7 +711,6 @@ ocotp at 8002c000 { compatible = "fsl,ocotp"; reg = <0x8002c000 0x2000>; - status = "disabled"; };
Why do you enable it only for imx28?
Quoted 19 lines
arch/arm/boot/dts/imx28.dtsi +0
-0axi-ahb at 8002e000 {drivers/clk/mxs/clk-imx23.c +2
-0@@ -168,6 +168,8 @@ int __init mx23_clocks_init(void) clk_data.clk_num =ARRAY_SIZE (clks);of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data); +clk_register_clkdev (clks[hbus],NULL ,"hbus" ); +for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);drivers/clk/mxs/clk-imx28.c +0
-0
drivers/clk/mxs/clk-imx28.c int __init mx28_clocks_init(void) · line 253
Quoted 7 lines
drivers/clk/mxs/clk-imx28.c +1
-0@@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data);clk_register_clkdev (clks[enet_out],NULL ,"enet_out" ); +clk_register_clkdev (clks[hbus],NULL ,"hbus" );for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);
These two should go in a separate patch (with details on why it's needed).
Quoted 30 lines
drivers/misc/Kconfig +14
-0@@ -527,6 +527,20 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config FSL_OTP + tristate "Freescale On-Chip OTP Memory Support" + depends on SOC_IMX23 || SOC_IMX28 + default n + help + If you say Y here, you will get support for a SysFS interface for + the One Time Programmable memory pages that are stored on the + iMX23/28 processor. + + To compile this driver as a module, choose M here: the module + will be called fsl_otp. + + If unsure, it is safe to say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig"drivers/misc/Makefile +0
-0
drivers/misc/Makefile obj-$(CONFIG_INTEL_MEI) += mei/ · line 56
Quoted 4 lines
drivers/misc/Makefile +1
-0@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o +obj-$(CONFIG_FSL_OTP) += fsl_otp.o
And this should be merged with the first patch.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/b1828b3d/attachment.sig>
cover Added support for On Chip OTP in i.MX23/28
In reply to Christoph G. BaumannHi Christoph,
Quoted 10 lines · Christoph G. Baumann
From: "Christoph G. Baumann" <[email protected]>
This patch contains the ported driver from Freescale for the On Chip OTP cells in the i.MX23 and i.MX28. The OTP cells can be read and written via files in
/sys/fsl_otp.Christoph G. Baumann (3):
Added support for On Chip OTP in i.MX23/28
Added support for On Chip OTP in i.MX23/28
Added support for On Chip OTP in i.MX23/28
You should use better commit logs here. There's no way to get what each patch actually does from only looking at those lines.
You should probably have something like:
misc: Add Freescale mxs On Chip OTP driver
ARM: mxs: dt: Enable the OTP in the DTSI
...
This has two advantages: the review is easier since the reviewer actually knows what each patch is doing and what to review, and most of all, you get a cleaner and more complete history, so that in a few month/years, you can get (ideally) all the context of this patch and what it's actually doing without having to look into the code.
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130705/bf3a310e/attachment.sig>
cover Added support for On Chip OTP in i.MX23/28
Hello Maxime,
thanks for all your hints. My approach on porting the Freescale code may have been a bit too straight forward.
I will do some refactoring and try to follow your comments.
Regards
Christoph
v2 cover mxs: add driver for On Chip OTP
In reply to Christoph G. BaumannFrom: "Christoph G. Baumann" <[email protected]>
This patch brings read/write support for the On Chip OTP cells in the i.MX23 and i.MX28 processor. The driver uses files (one for each cell) in /sys/fsl_otp as interface. The original code from Freescale was stripped down to the required minimum and ported to 3.x kernels.
Christoph G. Baumann (3):
mxs: enable ocotp in device tree
mxs: register clkdev "hbus" as it is required by OCOTP driver
mxs: added driver for OCOTP in i.MX23 and i.MX28
arch/arm/boot/dts/imx23.dtsi | 1 - arch/arm/boot/dts/imx28.dtsi | 1 - drivers/clk/mxs/clk-imx23.c | 2 + drivers/clk/mxs/clk-imx28.c | 1 + drivers/misc/Kconfig | 14 ++ drivers/misc/Makefile | 1 + drivers/misc/fsl_otp.c | 363 ++++++++++++++++++++++++++++++++++++++++++ drivers/misc/fsl_otp.h | 126 +++++++++++++++ 8 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.h
Signature · 1 line
1.7.9.5
PATCH v2 1/3 mxs: enable ocotp in device tree
From: "Christoph G. Baumann" <[email protected]>
--- arch/arm/boot/dts/imx23.dtsi | 1 - arch/arm/boot/dts/imx28.dtsi | 1 - 2 files changed, 2 deletions(-)
arch/arm/boot/dts/imx23.dtsi +0 -1
@@ -348,7 +348,6 @@ ocotp at 8002c000 { compatible = "fsl,ocotp"; reg = <0x8002c000 0x2000>; - status = "disabled"; }; axi-ahb at 8002e000 {
arch/arm/boot/dts/imx28.dtsi +0 -1
@@ -748,7 +748,6 @@ ocotp at 8002c000 { compatible = "fsl,ocotp"; reg = <0x8002c000 0x2000>; - status = "disabled"; }; axi-ahb at 8002e000 {
Signature · 1 line
1.7.9.5
PATCH v2 2/3 mxs: register clkdev "hbus" as it is required by OCOTP
In reply to Christoph G. BaumannFrom: "Christoph G. Baumann" <[email protected]>
The OCOTP driver needs to switch the HBUS clock when burning OTP bits. For this purpose it uses the CLK-API and requests a handler for "hbus". Trying to burn bits without registered "hbus" CLK results in a blocked user process.
--- drivers/clk/mxs/clk-imx23.c | 2 ++ drivers/clk/mxs/clk-imx28.c | 1 + 2 files changed, 3 insertions(+)
drivers/clk/mxs/clk-imx23.c +2 -0
@@ -168,6 +168,8 @@ int __init mx23_clocks_init(void) clk_data.clk_num =ARRAY_SIZE (clks);of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data); +clk_register_clkdev (clks[hbus],NULL ,"hbus" ); +for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);
drivers/clk/mxs/clk-imx28.c +1 -0
@@ -247,6 +247,7 @@ int __init mx28_clocks_init(void)of_clk_add_provider (np, of_clk_src_onecell_get, &clk_data);clk_register_clkdev (clks[enet_out],NULL ,"enet_out" ); +clk_register_clkdev (clks[hbus],NULL ,"hbus" );for (i =0 ; i <ARRAY_SIZE (clks_init_on); i++)clk_prepare_enable (clks[clks_init_on[i]]);
Signature · 1 line
1.7.9.5
PATCH v2 3/3 mxs: added driver for OCOTP in i.MX23 and i.MX28
In reply to Christoph G. BaumannFrom: "Christoph G. Baumann" <[email protected]>
--- drivers/misc/Kconfig | 14 ++ drivers/misc/Makefile | 1 + drivers/misc/fsl_otp.c | 363 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/fsl_otp.h | 126 +++++++++++++++++ 4 files changed, 504 insertions(+) create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.h
drivers/misc/Kconfig +14 -0
@@ -528,6 +528,20 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config FSL_OTP + tristate "Freescale On-Chip OTP Memory Support" + depends on SOC_IMX23 || SOC_IMX28 + default n + help + If you say Y here, you will get support for a SysFS interface for + the One Time Programmable memory pages that are stored on the + iMX23/28 processor. + + To compile this driver as a module, choose M here: the module + will be called fsl_otp. + + If unsure, it is safe to say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig"
drivers/misc/Makefile +1 -0
@@ -53,3 +53,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o +obj-$(CONFIG_FSL_OTP) += fsl_otp.o
drivers/misc/fsl_otp.c new file +363 -0
363 lines not on this page · raw message
drivers/misc/fsl_otp.h new file +126 -0
126 lines not on this page · raw message
Signature · 1 line
1.7.9.5
Sascha Hauer
maintainerPATCH v2 3/3 mxs: added driver for OCOTP in i.MX23 and i.MX28
Hi Christoph,
Several comments inline.
Quoted 17 lines · Christoph G. Baumann
From: "Christoph G. Baumann" <[email protected]>
Signed-off-by "Christoph G. Baumann" <[email protected]>--- drivers/misc/Kconfig | 14 ++ drivers/misc/Makefile | 1 + drivers/misc/fsl_otp.c | 363 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/fsl_otp.h | 126 +++++++++++++++++ 4 files changed, 504 insertions(+) create mode 100644 drivers/misc/fsl_otp.c create mode 100644 drivers/misc/fsl_otp.hdrivers/misc/Kconfig +0
-0
drivers/misc/Kconfig config SRAM · line 534
Quoted 7 lines
drivers/misc/Kconfig +4
-0@@ -528,6 +528,20 @@ config SRAM the genalloc API. It is supposed to be used for small on-chip SRAM areas found on many SoCs. +config FSL_OTP + tristate "Freescale On-Chip OTP Memory Support" + depends on SOC_IMX23 || SOC_IMX28 + default n
default n is the default. You can drop this.
drivers/misc/Kconfig config SRAM · line 540
Quoted 6 lines
drivers/misc/Kconfig +6
-0+ * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */
Please drop the address. It's wrong already.
drivers/misc/Kconfig config SRAM
Quoted 9 lines
drivers/misc/Kconfig +9
-0+static DEFINE_MUTEX(otp_mutex); +static struct kobject *otp_kobj; +static struct attribute **attrs; +static struct kobj_attribute *kattr; +static struct attribute_group attr_group; +static unsigned long otp_hclk_saved; +static u32 otp_voltage_saved; +static resource_size_t otp_base_address; +struct regulator *regu;
Collect your driver data in a struct and pass it around in functions calls. No need to limit this driver to a single instance.
Quoted 1 line
+/* forward declaration */
Who would have guessed that? Drop this, it contains no information.
Quoted 1 line
+static int
otp_wait_busy(u32 flags);
You should reorder the functions so that forward declarations are not necessary.
Quoted 29 lines
drivers/misc/Kconfig +29
-0+ +/* open the bank for the imx23/imx28 */ +static int otp_read_prepare(void) +{ + int r; + + /* [1] set the HCLK */ + /* [2] check BUSY and ERROR bit */ + r = otp_wait_busy(0); + if (r < 0) + goto error; + + /* [3] open bank */ + __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN, + REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET); + udelay(10); + + /* [4] wait for BUSY */ + r = otp_wait_busy(0); + return 0; +error: + return r; +} + +static int otp_read_post(void) +{ + /* [5] close bank */ + __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN, + REGS_OCOTP_BASE + HW_OCOTP_CTRL_CLR);
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ return 0; +} + +static int otp_write_prepare(void) +{ + struct clk *hclk; + int err = 0; + + /* [1] HCLK to 24MHz. */ + hclk = clk_get_sys("hbus", NULL);
This is a driver, so you should use regular clk_get, not clk_get_sys. Besides, this has to be done during probe. clk_get takes a reference to the clock which has to be released.
Quoted 7 lines
drivers/misc/Kconfig +7
-0+ if (IS_ERR(hclk)) { + err = PTR_ERR(hclk); + goto out; + } + /* + WARNING ACHTUNG UWAGA +
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ the code below changes HCLK clock rate to 24M. This is + required to write OTP bits (7.2.2 in STMP378x Target + Specification), and might affect LCD operation, for example. + Moreover, this hacky code changes VDDIO to 2.8V; and resto- + res it only on otp_close(). This may affect... anything. + + You are warned now. + */ + otp_hclk_saved = clk_get_rate(hclk); + clk_set_rate(hclk, 24000000);
You should check the return value.
drivers/misc/Kconfig
Quoted 3 lines
drivers/misc/Kconfig +3
-0+ + /* [2] The voltage is set to 2.8V */ + regu = regulator_get(NULL, otp_data.regulator_name);
Same as with clk_get. Do it during probe time.
drivers/misc/Kconfig
Quoted 2 lines
drivers/misc/Kconfig +2
-0+ otp_voltage_saved = regulator_get_voltage(regu); + regulator_set_voltage(regu, 2800000, 2800000);
Check the return value.
Quoted 21 lines
drivers/misc/Kconfig +21
-0+ + /* [3] wait for BUSY and ERROR */ + err = otp_wait_busy(BM_OCOTP_CTRL_RD_BANK_OPEN); +out: + return err; +} + +static int otp_write_post(void) +{ + struct clk *hclk; + + hclk = clk_get_sys("hbus", NULL); + if (IS_ERR(hclk)) + return PTR_ERR(hclk); + + /* restore the clock and voltage */ + clk_set_rate(hclk, otp_hclk_saved); + regulator_set_voltage(regu, otp_voltage_saved, otp_voltage_saved); + otp_wait_busy(0); + + /* reset */
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ __raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS, + REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET); + otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS); + return 0; +} + +static int __init map_ocotp_addr(struct platform_device *pdev) +{ + return 0; +}
What's this? Drop this.
drivers/misc/Kconfig
Quoted 3 lines
drivers/misc/Kconfig +3
-0+static void unmap_ocotp_addr(void) +{ +}
ditto
Quoted 130 lines
drivers/misc/Kconfig +130
-0+ +static inline unsigned int get_reg_index(struct kobj_attribute *tmp) +{ + return tmp - kattr; +} + +static int otp_wait_busy(u32 flags) +{ + int count; + u32 c; + + for (count = 10000; count >= 0; count--) { + c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL); + if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags))) + break; + cpu_relax(); + } + + if (count < 0) + return -ETIMEDOUT; + return 0; +} + +static ssize_t otp_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + unsigned int index = get_reg_index(attr); + u32 value = 0; + + /* sanity check */ + if (index >= otp_data.fuse_num) + return 0; + + mutex_lock(&otp_mutex); + + if (otp_read_prepare()) { + mutex_unlock(&otp_mutex); + return 0; + } + value = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUST_N(index)); + otp_read_post(); + + mutex_unlock(&otp_mutex); + return sprintf(buf, "0x%x\n", value); +} + +static int otp_write_bits(int addr, u32 data, u32 magic) +{ + u32 c; /* for control register */ + + /* init the control register */ + c = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL); + c &= ~BM_OCOTP_CTRL_ADDR; + c |= BF(addr, OCOTP_CTRL_ADDR); + c |= BF(magic, OCOTP_CTRL_WR_UNLOCK); + __raw_writel(c, REGS_OCOTP_BASE + HW_OCOTP_CTRL); + + /* init the data register */ + __raw_writel(data, REGS_OCOTP_BASE + HW_OCOTP_DATA); + otp_wait_busy(0); + + mdelay(2); /* Write Postamble */ + return 0; +} + +static ssize_t otp_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned int index = get_reg_index(attr); + int value; + + /* sanity check */ + if (index >= otp_data.fuse_num) + return 0; + + sscanf(buf, "0x%x", &value); + + mutex_lock(&otp_mutex); + if (otp_write_prepare()) { + mutex_unlock(&otp_mutex); + return 0; + } + otp_write_bits(index, value, 0x3e77); + otp_write_post(); + mutex_unlock(&otp_mutex); + + return count; +} + +static void free_otp_attr(void) +{ + kfree(attrs); + attrs = NULL; + + kfree(kattr); + kattr = NULL; +} + +static int alloc_otp_attr(void) +{ + int i; + + /* The last one is NULL, which is used to detect the end */ + attrs = kzalloc((otp_data.fuse_num + 1) * sizeof(attrs[0]), + GFP_KERNEL); + kattr = kzalloc(otp_data.fuse_num * sizeof(struct kobj_attribute), + GFP_KERNEL); + + if (!attrs || !kattr) + goto error_out; + + for (i = 0; i < otp_data.fuse_num; i++) { + kattr[i].attr.name = otp_data.fuse_name[i]; + kattr[i].attr.mode = 0600; + kattr[i].show = otp_show; + kattr[i].store = otp_store; + attrs[i] = &kattr[i].attr; + sysfs_attr_init(attrs[i]); + } + memset(&attr_group, 0, sizeof(attr_group)); + attr_group.attrs = attrs; + return 0; + +error_out: + free_otp_attr(); + return -ENOMEM; +} + +static int fsl_otp_probe(struct platform_device *pdev) +{
drivers/misc/Kconfig
Quoted 10 lines
drivers/misc/Kconfig +10
-0+ int retval; + struct fsl_otp_data *pdata; + + /* get device base address */ + otp_base_address = pdev->resource->start; + dev_info(&pdev->dev, "i.MX23/28 OCOTP at %p\n", otp_base_address); + + pdata = &otp_data; + if (pdev->dev.platform_data == NULL) + pdev->dev.platform_data = &otp_data;
You shouldn't manipulate the platform_data pointer in the driver. platform_data contains data passed to the driver.
Quoted 84 lines
drivers/misc/Kconfig +70
-0+ + retval = alloc_otp_attr(); + if (retval) + return retval; + + retval = map_ocotp_addr(pdev); + if (retval) + goto error; + + otp_kobj = kobject_create_and_add("fsl_otp", NULL); + if (!otp_kobj) { + retval = -ENOMEM; + goto error; + } + + retval = sysfs_create_group(otp_kobj, &attr_group); + if (retval) + goto error; + + mutex_init(&otp_mutex); + return 0; +error: + kobject_put(otp_kobj); + otp_kobj = NULL; + free_otp_attr(); + unmap_ocotp_addr(); + return retval; +} + +static int otp_remove(struct platform_device *pdev) +{ + kobject_put(otp_kobj); + otp_kobj = NULL; + + free_otp_attr(); + unmap_ocotp_addr(); + return 0; +} + +static const struct of_device_id mxs_otp_dt_ids[] = { + { .compatible = "fsl,ocotp", .data = NULL, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_otp_dt_ids); + +static struct platform_driver ocotp_driver = { + .probe = fsl_otp_probe, + .remove = otp_remove, + .driver = { + .name = "ocotp", + .owner = THIS_MODULE, + .of_match_table = mxs_otp_dt_ids, + }, +}; + +static int __init fsl_otp_init(void) +{ + return platform_driver_register(&ocotp_driver); +} + +static void __exit fsl_otp_exit(void) +{ + platform_driver_unregister(&ocotp_driver); +} +module_init(fsl_otp_init); +module_exit(fsl_otp_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christoph G. Baumann <[email protected]>"); +MODULE_DESCRIPTION("driver for OCOTP in i.MX23 and i.MX28");drivers/misc/fsl_otp.h new file +8
-0@@ -0,0 +1,126 @@ +/* +* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. +* +* Ported to 3.7 by Christoph G. Baumann <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or
drivers/misc/fsl_otp.h line 18
Quoted 10 lines
drivers/misc/fsl_otp.h new file +10
-0+* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Here's another address of the FSF. That's the reason for not including it.
drivers/misc/fsl_otp.h line 29
Quoted 11 lines
drivers/misc/fsl_otp.h new file +11
-0+*/ +#ifndef __FREESCALE_OTP__ +#define __FREESCALE_OTP__ + + +/* IMX23 and IMX28 share most of the defination ========================= */ +#if (defined(CONFIG_SOC_IMX23 ) || defined(CONFIG_SOC_IMX28 )) + +#if defined(CONFIG_SOC_IMX28 ) && defined(CONFIG_SOC_IMX23 ) +#undef CONFIG_SOC_IMX23 +#endif
So if the kernel supports both i.MX23 and i.MX28 you choose to make the driver work on i.MX28 only. You have to make this a runtime decision. See some other driver how this can be made, for example drivers/spi/spi-imx.c. Look for the usage of of_match_device().
drivers/misc/fsl_otp.h line 33
Quoted 4 lines
drivers/misc/fsl_otp.h new file +4
-0+ + +#define OCOTP_PHYS_ADDR otp_base_address +#define REGS_OCOTP_BASE (MXS_IO_ADDRESS(OCOTP_PHYS_ADDR))
Drop this and use ioremap in the driver.
Quoted 5 lines
drivers/misc/fsl_otp.h new file +5
-0+#define BF (value, field) (((value) << BP_##field) & BM_##field) + +/* MXS IO mappings */ + +/*
drivers/misc/fsl_otp.h line 48
Quoted 10 lines
drivers/misc/fsl_otp.h new file +10
-0+* It maps the whole address space to [0xf4000000, 0xf50fffff]. +* +* OCRAM 0x00000000+0x020000 -> 0xf4000000+0x020000 +* IO 0x80000000+0x100000 -> 0xf5000000+0x100000 +*/ +#define MXS_IO_P2V (x) (0xf4000000 + \ + (((x) & 0x80000000) >> 7) + \ + (((x) & 0x000fffff))) + +#define MXS_IO_ADDRESS (x) IOMEM(MXS_IO_P2V(x))
This also shouldn't be in a driver.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH v2 3/3 mxs: added driver for OCOTP in i.MX23 and i.MX28
Hello Sascha,
thanks for your input. I must admit that I didn't do a thorough review of the FSL code...
Quoted 15 lines
Sascha Hauer <[email protected]> hat am 17. Juli 2013 um 21:26 geschrieben:
[...]drivers/misc/fsl_otp.c line 48
Quoted 9 lines
drivers/misc/fsl_otp.c new file +9
-0+static DEFINE_MUTEX (otp_mutex); +static struct kobject *otp_kobj; +static struct attribute **attrs; +static struct kobj_attribute *kattr; +static struct attribute_group attr_group; +static unsigned long otp_hclk_saved; +static u32 otp_voltage_saved; +static resource_size_t otp_base_address; +struct regulator *regu;Collect your driver data in a struct and pass it around in functions calls. No need to limit this driver to a single instance.
The OTP device is unique in the CPU and several instances i.e. potential concurrent access is considered harmful. So I kept this construction from FSL.
Quoted 11 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+static int otp_write_prepare(void) +{ +? ? ?struct clk *hclk; +? ? ?int err = 0; + +? ? ?/* [1] HCLK to 24MHz. */ +? ? ?hclk = clk_get_sys("hbus", NULL);This is a driver, so you should use regular
clk_get, notclk_get_sys. Besides, this has to be done during probe.clk_gettakes a reference to the clock which has to be released.
As far as I remember testing clk_get didn't work in this place. In the API doc I only found the warning:
"clk_get_sys should not be called from within interrupt context.".
Regards,
Christoph
Sascha Hauer
maintainerPATCH v2 3/3 mxs: added driver for OCOTP in i.MX23 and i.MX28
Quoted 22 lines · Christoph G. Baumann
Hello Sascha,
thanks for your input. I must admit that I didn't do a thorough review of the FSL code...
Quoted 15 lines
Sascha Hauer <[email protected]> hat am 17. Juli 2013 um 21:26 geschrieben:
[...]drivers/misc/fsl_otp.c line 48
Quoted 9 lines
drivers/misc/fsl_otp.c new file +9
-0+static DEFINE_MUTEX (otp_mutex); +static struct kobject *otp_kobj; +static struct attribute **attrs; +static struct kobj_attribute *kattr; +static struct attribute_group attr_group; +static unsigned long otp_hclk_saved; +static u32 otp_voltage_saved; +static resource_size_t otp_base_address; +struct regulator *regu;Collect your driver data in a struct and pass it around in functions calls. No need to limit this driver to a single instance.
Quoted 3 lines
The OTP device is unique in the CPU and several instances i.e. potential concurrent access is considered harmful. So I kept this construction from FSL.
Yes, this is single instance only in current SoCs. This is no reason though to make the driver single instance capabable only. It's not much work to change and it raises less eyebrows if it's properly written.
In the end I never thought that there ever would be two instances of the i.MX graphics subsystem (IPU). Now the i.MX6 has two of them...
Quoted 14 lines
Quoted 13 lines
Review
Quoted 9 lines
(quoted diff) +7
-0+static int otp_write_prepare(void) +{ +? ? ?struct clk *hclk; +? ? ?int err = 0; + +? ? ?/* [1] HCLK to 24MHz. */ +? ? ?hclk = clk_get_sys("hbus", NULL);This is a driver, so you should use regular
clk_get, notclk_get_sys. Besides, this has to be done during probe.clk_gettakes a reference to the clock which has to be released.
Quoted 1 line
As far as I remember testing
clk_getdidn't work in this place.
That is because the clk_register_clkdev() in your other patch is wrong.
Look at the 'clocks' and 'clock-names' properties in the devicetree. Also look at Documentation/devicetree/bindings/clock/imx28-clock.txt.
In short you have to add a clock to your devicetree node and then use clk_get(). The struct device * passed to clk_get will make the bridge between the device and the devicenode and the id argument will be the same name as in the devicetree.
Sascha
Signature · 4 lines
Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
PATCH v2 3/3 mxs: added driver for OCOTP in i.MX23 and i.MX28
Hello Sascha,
unfortunately I don't have the time at the moment to further fix the FSL code. Maybe someone else feels inclined?
Regards
Christoph