2 * Blackfin On-Chip OTP Memory Interface
4 * Copyright 2007-2009 Analog Devices Inc.
6 * Enter bugs at http://blackfin.uclinux.org/
8 * Licensed under the GPL-2 or later.
11 #include <linux/device.h>
12 #include <linux/errno.h>
14 #include <linux/init.h>
15 #include <linux/miscdevice.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/types.h>
19 #include <mtd/mtd-abi.h>
21 #include <asm/blackfin.h>
22 #include <asm/bfrom.h>
23 #include <linux/uaccess.h>
25 #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
26 #define stampit() stamp("here i am")
27 #define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
29 #define DRIVER_NAME "bfin-otp"
30 #define PFX DRIVER_NAME ": "
32 static DEFINE_MUTEX(bfin_otp_lock
);
35 * bfin_otp_read - Read OTP pages
37 * All reads must be in half page chunks (half page == 64 bits).
39 static ssize_t
bfin_otp_read(struct file
*file
, char __user
*buff
, size_t count
, loff_t
*pos
)
47 if (count
% sizeof(u64
))
50 if (mutex_lock_interruptible(&bfin_otp_lock
))
54 page
= *pos
/ (sizeof(u64
) * 2);
55 while (bytes_done
< count
) {
56 flags
= (*pos
% (sizeof(u64
) * 2) ? OTP_UPPER_HALF
: OTP_LOWER_HALF
);
57 stamp("processing page %i (0x%x:%s)", page
, flags
,
58 (flags
& OTP_UPPER_HALF
? "upper" : "lower"));
59 ret
= bfrom_OtpRead(page
, flags
, &content
);
60 if (ret
& OTP_MASTER_ERROR
) {
61 stamp("error from otp: 0x%x", ret
);
65 if (copy_to_user(buff
+ bytes_done
, &content
, sizeof(content
))) {
69 if (flags
& OTP_UPPER_HALF
)
71 bytes_done
+= sizeof(content
);
72 *pos
+= sizeof(content
);
75 mutex_unlock(&bfin_otp_lock
);
80 #ifdef CONFIG_BFIN_OTP_WRITE_ENABLE
81 static bool allow_writes
;
84 * bfin_otp_init_timing - setup OTP timing parameters
86 * Required before doing any write operation. Algorithms from HRM.
88 static u32
bfin_otp_init_timing(void)
90 u32 tp1
, tp2
, tp3
, timing
;
92 tp1
= get_sclk() / 1000000;
93 tp2
= (2 * get_sclk() / 10000000) << 8;
95 timing
= tp1
| tp2
| tp3
;
96 if (bfrom_OtpCommand(OTP_INIT
, timing
))
103 * bfin_otp_deinit_timing - set timings to only allow reads
105 * Should be called after all writes are done.
107 static void bfin_otp_deinit_timing(u32 timing
)
109 /* mask bits [31:15] so that any attempts to write fail */
110 bfrom_OtpCommand(OTP_CLOSE
, 0);
111 bfrom_OtpCommand(OTP_INIT
, timing
& ~(-1 << 15));
112 bfrom_OtpCommand(OTP_CLOSE
, 0);
116 * bfin_otp_write - write OTP pages
118 * All writes must be in half page chunks (half page == 64 bits).
120 static ssize_t
bfin_otp_write(struct file
*filp
, const char __user
*buff
, size_t count
, loff_t
*pos
)
123 u32 timing
, page
, base_flags
, flags
, ret
;
129 if (count
% sizeof(u64
))
132 if (mutex_lock_interruptible(&bfin_otp_lock
))
137 timing
= bfin_otp_init_timing();
139 mutex_unlock(&bfin_otp_lock
);
143 base_flags
= OTP_CHECK_FOR_PREV_WRITE
;
146 page
= *pos
/ (sizeof(u64
) * 2);
147 while (bytes_done
< count
) {
148 flags
= base_flags
| (*pos
% (sizeof(u64
) * 2) ? OTP_UPPER_HALF
: OTP_LOWER_HALF
);
149 stamp("processing page %i (0x%x:%s) from %p", page
, flags
,
150 (flags
& OTP_UPPER_HALF
? "upper" : "lower"), buff
+ bytes_done
);
151 if (copy_from_user(&content
, buff
+ bytes_done
, sizeof(content
))) {
152 bytes_done
= -EFAULT
;
155 ret
= bfrom_OtpWrite(page
, flags
, &content
);
156 if (ret
& OTP_MASTER_ERROR
) {
157 stamp("error from otp: 0x%x", ret
);
161 if (flags
& OTP_UPPER_HALF
)
163 bytes_done
+= sizeof(content
);
164 *pos
+= sizeof(content
);
167 bfin_otp_deinit_timing(timing
);
169 mutex_unlock(&bfin_otp_lock
);
174 static long bfin_otp_ioctl(struct file
*filp
, unsigned cmd
, unsigned long arg
)
186 if (mutex_lock_interruptible(&bfin_otp_lock
))
189 timing
= bfin_otp_init_timing();
191 u32 otp_result
= bfrom_OtpWrite(arg
, OTP_LOCK
, NULL
);
192 stamp("locking page %lu resulted in 0x%x", arg
, otp_result
);
193 if (!(otp_result
& OTP_MASTER_ERROR
))
196 bfin_otp_deinit_timing(timing
);
199 mutex_unlock(&bfin_otp_lock
);
205 allow_writes
= false;
216 # define bfin_otp_write NULL
217 # define bfin_otp_ioctl NULL
220 static const struct file_operations bfin_otp_fops
= {
221 .owner
= THIS_MODULE
,
222 .unlocked_ioctl
= bfin_otp_ioctl
,
223 .read
= bfin_otp_read
,
224 .write
= bfin_otp_write
,
225 .llseek
= default_llseek
,
228 static struct miscdevice bfin_otp_misc_device
= {
229 .minor
= MISC_DYNAMIC_MINOR
,
231 .fops
= &bfin_otp_fops
,
233 module_misc_device(bfin_otp_misc_device
);
235 MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
236 MODULE_DESCRIPTION("Blackfin OTP Memory Interface");
237 MODULE_LICENSE("GPL");