1 /**
2  * \file
3  *
4  * \brief I2C Master Interrupt Driver for SAMB
5  *
6  * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved.
7  *
8  * \asf_license_start
9  *
10  * \page License
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  *    this list of conditions and the following disclaimer in the documentation
20  *    and/or other materials provided with the distribution.
21  *
22  * 3. The name of Atmel may not be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * 4. This software may only be redistributed and used in connection with an
26  *    Atmel microcontroller product.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * \asf_license_stop
41  *
42  */
43 /*
44  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45  */
46 
47 #include "i2c_slave_interrupt.h"
48 
49 void *_i2c_instances;
50 
51 /**
52  * \internal
53  * Reads next data. Used by interrupt handler to get next data byte from master.
54  *
55  * \param[in,out] module  Pointer to software module structure
56  */
_i2c_slave_read(struct i2c_slave_module * const module)57 static void _i2c_slave_read(
58 		struct i2c_slave_module *const module)
59 {
60 	/* Sanity check */
61 	Assert(module);
62 	Assert(module->hw);
63 
64 	I2c *const i2c_module = module->hw;
65 
66 	/* Read byte from master and put in buffer. */
67 	*(module->buffer++) = i2c_module->RECEIVE_DATA.reg;
68 
69 	/*Decrement remaining buffer length */
70 	module->buffer_remaining--;
71 }
72 
73 /**
74  * \internal
75  * Writes next data. Used by interrupt handler to send next data byte to master.
76  *
77  * \param[in,out] module  Pointer to software module structure
78  */
_i2c_slave_write(struct i2c_slave_module * const module)79 static void _i2c_slave_write(
80 		struct i2c_slave_module *const module)
81 {
82 	/* Sanity check */
83 	Assert(module);
84 	Assert(module->hw);
85 
86 	I2c *const i2c_module = module->hw;
87 
88 	/* Write byte from buffer to master */
89 	i2c_module->TRANSMIT_DATA.reg = *(module->buffer++);
90 
91 	/*Decrement remaining buffer length */
92 	module->buffer_remaining--;
93 }
94 
95 /**
96  * \brief Registers callback for the specified callback type
97  *
98  * Associates the given callback function with the
99  * specified callback type. To enable the callback, the
100  * \ref i2c_slave_enable_callback function must be used.
101  *
102  * \param[in,out] module         Pointer to the software module struct
103  * \param[in]     callback       Pointer to the function desired for the
104  *                               specified callback
105  * \param[in]     callback_type  Callback type to register
106  */
i2c_slave_register_callback(struct i2c_slave_module * const module,i2c_slave_callback_t callback,enum i2c_slave_callback callback_type)107 void i2c_slave_register_callback(
108 		struct i2c_slave_module *const module,
109 		i2c_slave_callback_t callback,
110 		enum i2c_slave_callback callback_type)
111 {
112 	/* Sanity check. */
113 	Assert(module);
114 	Assert(module->hw);
115 	Assert(callback);
116 
117 	/* Register callback. */
118 	module->callbacks[callback_type] = callback;
119 
120 	/* Set corresponding bit to set callback as initiated. */
121 	module->registered_callback |= (1 << callback_type);
122 }
123 
124 /**
125  * \brief Unregisters callback for the specified callback type
126  *
127  * Removes the currently registered callback for the given callback
128  * type.
129  *
130  * \param[in,out]  module         Pointer to the software module struct
131  * \param[in]      callback_type  Callback type to unregister
132  */
i2c_slave_unregister_callback(struct i2c_slave_module * const module,enum i2c_slave_callback callback_type)133 void i2c_slave_unregister_callback(
134 		struct i2c_slave_module *const module,
135 		enum i2c_slave_callback callback_type)
136 {
137 	/* Sanity check. */
138 	Assert(module);
139 	Assert(module->hw);
140 
141 	/* Register callback. */
142 	module->callbacks[callback_type] = NULL;
143 
144 	/* Set corresponding bit to set callback as initiated. */
145 	module->registered_callback &= ~(1 << callback_type);
146 }
147 
148 /**
149  * \brief Initiates a reads packet operation
150  *
151  * Reads a data packet from the master. A write request must be initiated by
152  * the master before the packet can be read.
153  *
154  * The \ref I2C_SLAVE_CALLBACK_WRITE_REQUEST callback can be used to call this
155  * function.
156  *
157  * \param[in,out] module  Pointer to software module struct
158  * \param[in,out] packet  Pointer to I<SUP>2</SUP>C packet to transfer
159  *
160  * \return Status of starting asynchronously reading I<SUP>2</SUP>C packet.
161  * \retval STATUS_OK    If reading was started successfully
162  * \retval STATUS_BUSY  If module is currently busy with another transfer
163  */
i2c_slave_read_packet_job(struct i2c_slave_module * const module,struct i2c_slave_packet * const packet)164 enum status_code i2c_slave_read_packet_job(
165 		struct i2c_slave_module *const module,
166 		struct i2c_slave_packet *const packet)
167 {
168 	/* Sanity check */
169 	Assert(module);
170 	Assert(module->hw);
171 	Assert(packet);
172 
173 	I2c *const i2c_module = module->hw;
174 
175 	/* Check if the I2C module is busy doing async operation. */
176 	if (module->buffer_remaining > 0) {
177 		return STATUS_BUSY;
178 	}
179 
180 	/* Save packet to software module. */
181 	module->buffer           = packet->data;
182 	module->buffer_remaining = packet->data_length;
183 	module->buffer_length    = packet->data_length;
184 	module->status           = STATUS_BUSY;
185 
186 	/* Enable interrupts */
187 	i2c_slave_rx_interrupt(i2c_module, true);
188 
189 	return STATUS_OK;
190 }
191 
192 /**
193  * \brief Initiates a write packet operation
194  *
195  * Writes a data packet to the master. A read request must be initiated by
196  * the master before the packet can be written.
197  *
198  * The \ref I2C_SLAVE_CALLBACK_READ_REQUEST callback can be used to call this
199  * function.
200  *
201  * \param[in,out] module  Pointer to software module struct
202  * \param[in,out] packet  Pointer to I<SUP>2</SUP>C packet to transfer
203  *
204  * \return Status of starting writing I<SUP>2</SUP>C packet.
205  * \retval STATUS_OK   If writing was started successfully
206  * \retval STATUS_BUSY If module is currently busy with another transfer
207  */
i2c_slave_write_packet_job(struct i2c_slave_module * const module,struct i2c_slave_packet * const packet)208 enum status_code i2c_slave_write_packet_job(
209 		struct i2c_slave_module *const module,
210 		struct i2c_slave_packet *const packet)
211 {
212 	/* Sanity check */
213 	Assert(module);
214 	Assert(module->hw);
215 	Assert(packet);
216 
217 	I2c *const i2c_module = module->hw;
218 
219 	if (module->buffer_remaining > 0) {
220 		return STATUS_BUSY;
221 	}
222 
223 	/* Save packet to software module. */
224 	module->buffer           = packet->data;
225 	module->buffer_remaining = packet->data_length;
226 	module->buffer_length    = packet->data_length;
227 	module->status			 = STATUS_BUSY;
228 
229 	/* Enable interrupts */
230 	i2c_slave_tx_interrupt(i2c_module, true);
231 
232 	return STATUS_OK;
233 }
234 
235 /**
236  * \internal Interrupt handler for I<SUP>2</SUP>C slave
237  *
238  * \param[in] instance  I2C instance that triggered the interrupt
239  */
_i2c_slave_rx_isr_handler(void)240 void _i2c_slave_rx_isr_handler(void)
241 {
242 	/* Get software module for callback handling. */
243 	struct i2c_slave_module *module =
244 			(struct i2c_slave_module*)_i2c_instances;
245 
246 	Assert(module);
247 
248 	I2c *const i2c_module = module->hw;
249 
250 	/* Combine callback registered and enabled masks. */
251 	uint8_t callback_mask =
252 			module->enabled_callback & module->registered_callback;
253 
254 	if (i2c_module->RECEIVE_STATUS.reg & I2C_RECEIVE_STATUS_RX_FIFO_NOT_EMPTY) {
255 		if (!module->buffer_length && (module->buffer_length == module->buffer_remaining)) {
256 			module->transfer_direction = I2C_TRANSFER_WRITE;
257 			if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)) {
258 				/* Write to master complete */
259 				module->callbacks[I2C_SLAVE_CALLBACK_WRITE_REQUEST](module);
260 			}
261 		}
262 		/* Continue buffer write/read */
263 		if (module->buffer_length > 0 && module->buffer_remaining > 0) {
264 				_i2c_slave_read(module);
265 		}
266 		if (!module->buffer_remaining) {
267 			module->status = STATUS_OK;
268 			module->buffer_length = 0;
269 			if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE)) {
270 				/* Write to master complete */
271 				module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
272 			}
273 		}
274 	}
275 	if ((i2c_module->RECEIVE_STATUS.reg & I2C_RECEIVE_STATUS_NAK)) { //&&
276 			//module->transfer_direction == I2C_TRANSFER_READ) {
277 		/* Received NAK, master received completed. */
278 		i2c_module->RX_INTERRUPT_MASK.bit.NAK_MASK = 0;
279 		if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE)) {
280 			module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
281 		}
282 	}
283 
284 	if (module->hw == I2C0) {
285 		NVIC_ClearPendingIRQ(I2C0_RX_IRQn);
286 	} else if (module->hw == I2C1) {
287 		NVIC_ClearPendingIRQ(I2C1_RX_IRQn);
288 	}
289 }
290 
_i2c_slave_tx_isr_handler(void)291 void _i2c_slave_tx_isr_handler(void)
292 {
293 	/* Get software module for callback handling. */
294 	struct i2c_slave_module *module =
295 			(struct i2c_slave_module*)_i2c_instances;
296 
297 	Assert(module);
298 
299 	I2c *const i2c_module = module->hw;
300 
301 	/* Combine callback registered and enabled masks. */
302 	uint8_t callback_mask =
303 			module->enabled_callback & module->registered_callback;
304 
305 	if (!module->buffer_length && (module->buffer_length == module->buffer_remaining)) {
306 		/* First timer interrupt */
307 		module->transfer_direction = I2C_TRANSFER_READ;
308 		if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST)) {
309 			/* Write to master complete */
310 			module->callbacks[I2C_SLAVE_CALLBACK_READ_REQUEST](module);
311 		}
312 	}
313 	if (module->buffer_length > 0 && module->buffer_remaining > 0) {
314 		_i2c_slave_write(module);
315 	}
316 	if (!module->buffer_remaining) {
317 		module->status = STATUS_OK;
318 		module->buffer_length = 0;
319 		i2c_module->RX_INTERRUPT_MASK.bit.NAK_MASK = 0;
320 		if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE)) {
321 			module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
322 		}
323 	}
324 
325 	if (module->hw == I2C0) {
326 		NVIC_ClearPendingIRQ(I2C0_TX_IRQn);
327 	} else if (module->hw == I2C1) {
328 		NVIC_ClearPendingIRQ(I2C1_TX_IRQn);
329 	}
330 }