| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Maxim MAX1110/1111 ADC chip emulation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2006 Openedhand Ltd. | 
					
						
							|  |  |  |  * Written by Andrzej Zaborowski <balrog@zabor.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This code is licensed under the GNU GPLv2. | 
					
						
							| 
									
										
										
										
											2012-01-13 17:44:23 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Contributions after 2012-01-13 are licensed under the terms of the | 
					
						
							|  |  |  |  * GNU GPL, version 2 or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:17 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-18 15:54:52 -05:00
										 |  |  | #include "hw/adc/max111x.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:42 +02:00
										 |  |  | #include "hw/irq.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:45 +02:00
										 |  |  | #include "migration/vmstate.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  | #include "hw/qdev-properties.h"
 | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Control-byte bitfields */ | 
					
						
							|  |  |  | #define CB_PD0		(1 << 0)
 | 
					
						
							|  |  |  | #define CB_PD1		(1 << 1)
 | 
					
						
							|  |  |  | #define CB_SGL		(1 << 2)
 | 
					
						
							|  |  |  | #define CB_UNI		(1 << 3)
 | 
					
						
							|  |  |  | #define CB_SEL0		(1 << 4)
 | 
					
						
							|  |  |  | #define CB_SEL1		(1 << 5)
 | 
					
						
							|  |  |  | #define CB_SEL2		(1 << 6)
 | 
					
						
							|  |  |  | #define CB_START	(1 << 7)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define CHANNEL_NUM(v, b0, b1, b2)	\
 | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |                         ((((v) >> (2 + (b0))) & 4) |	\ | 
					
						
							|  |  |  |                          (((v) >> (3 + (b1))) & 2) |	\ | 
					
						
							|  |  |  |                          (((v) >> (4 + (b2))) & 1)) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | static uint32_t max111x_read(MAX111xState *s) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!s->tb1) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (s->cycle ++) { | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |         return s->rb2; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |         return s->rb3; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Interpret a control-byte */ | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | static void max111x_write(MAX111xState *s, uint32_t value) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int measure, chan; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Ignore the value if START bit is zero */ | 
					
						
							|  |  |  |     if (!(value & CB_START)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->cycle = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(value & CB_PD1)) { | 
					
						
							|  |  |  |         s->tb1 = 0; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->tb1 = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->inputs == 8) | 
					
						
							|  |  |  |         chan = CHANNEL_NUM(value, 1, 0, 2); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (value & CB_SGL) | 
					
						
							|  |  |  |         measure = s->input[chan] - s->com; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         measure = s->input[chan] - s->input[chan ^ 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(value & CB_UNI)) | 
					
						
							|  |  |  |         measure ^= 0x80; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->rb2 = (measure >> 2) & 0x3f; | 
					
						
							|  |  |  |     s->rb3 = (measure << 6) & 0xc0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |     /* FIXME: When should the IRQ be lowered?  */ | 
					
						
							|  |  |  |     qemu_irq_raise(s->interrupt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static uint32_t max111x_transfer(SSIPeripheral *dev, uint32_t value) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:35 -08:00
										 |  |  |     MAX111xState *s = MAX_111X(dev); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |     max111x_write(s, value); | 
					
						
							|  |  |  |     return max111x_read(s); | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-03 01:03:59 +01:00
										 |  |  | static const VMStateDescription vmstate_max111x = { | 
					
						
							|  |  |  |     .name = "max111x", | 
					
						
							| 
									
										
										
										
											2012-07-24 12:23:22 +10:00
										 |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							| 
									
										
										
										
											2014-05-13 16:09:35 +01:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |         VMSTATE_SSI_PERIPHERAL(parent_obj, MAX111xState), | 
					
						
							| 
									
										
										
										
											2010-12-03 01:03:59 +01:00
										 |  |  |         VMSTATE_UINT8(tb1, MAX111xState), | 
					
						
							|  |  |  |         VMSTATE_UINT8(rb2, MAX111xState), | 
					
						
							|  |  |  |         VMSTATE_UINT8(rb3, MAX111xState), | 
					
						
							| 
									
										
										
										
											2017-06-23 16:48:23 +02:00
										 |  |  |         VMSTATE_INT32_EQUAL(inputs, MAX111xState, NULL), | 
					
						
							| 
									
										
										
										
											2010-12-03 01:03:59 +01:00
										 |  |  |         VMSTATE_INT32(com, MAX111xState), | 
					
						
							|  |  |  |         VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs, | 
					
						
							|  |  |  |                                    vmstate_info_uint8, uint8_t), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:45 +01:00
										 |  |  | static void max111x_input_set(void *opaque, int line, int value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MAX111xState *s = MAX_111X(opaque); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(line >= 0 && line < s->inputs); | 
					
						
							|  |  |  |     s->input[line] = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static int max111x_init(SSIPeripheral *d, int inputs) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:27:50 -08:00
										 |  |  |     DeviceState *dev = DEVICE(d); | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:35 -08:00
										 |  |  |     MAX111xState *s = MAX_111X(dev); | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-11 16:27:50 -08:00
										 |  |  |     qdev_init_gpio_out(dev, &s->interrupt, 1); | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:45 +01:00
										 |  |  |     qdev_init_gpio_in(dev, max111x_input_set, inputs); | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  |     s->inputs = inputs; | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-14 10:36:05 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static void max1110_realize(SSIPeripheral *dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-04 13:06:37 +01:00
										 |  |  |     max111x_init(dev, 8); | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  | static void max1111_realize(SSIPeripheral *dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-04 13:06:37 +01:00
										 |  |  |     max111x_init(dev, 4); | 
					
						
							| 
									
										
										
										
											2007-04-30 02:14:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  | static void max111x_reset(DeviceState *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MAX111xState *s = MAX_111X(dev); | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < s->inputs; i++) { | 
					
						
							|  |  |  |         s->input[i] = s->reset_input[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s->com = 0; | 
					
						
							|  |  |  |     s->tb1 = 0; | 
					
						
							|  |  |  |     s->rb2 = 0; | 
					
						
							|  |  |  |     s->rb3 = 0; | 
					
						
							|  |  |  |     s->cycle = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Property max1110_properties[] = { | 
					
						
							|  |  |  |     /* Reset values for ADC inputs */ | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), | 
					
						
							|  |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Property max1111_properties[] = { | 
					
						
							|  |  |  |     /* Reset values for ADC inputs */ | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90), | 
					
						
							|  |  |  |     DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80), | 
					
						
							|  |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  | static void max111x_class_init(ObjectClass *klass, void *data) | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     k->transfer = max111x_transfer; | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     dc->reset = max111x_reset; | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     dc->vmsd = &vmstate_max111x; | 
					
						
							| 
									
										
										
										
											2020-11-12 20:58:24 +08:00
										 |  |  |     set_bit(DEVICE_CATEGORY_MISC, dc->categories); | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  | static const TypeInfo max111x_info = { | 
					
						
							|  |  |  |     .name          = TYPE_MAX_111X, | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     .parent        = TYPE_SSI_PERIPHERAL, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .instance_size = sizeof(MAX111xState), | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  |     .class_init    = max111x_class_init, | 
					
						
							|  |  |  |     .abstract      = true, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void max1110_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 13:06:37 +01:00
										 |  |  |     k->realize = max1110_realize; | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     device_class_set_props(dc, max1110_properties); | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo max1110_info = { | 
					
						
							|  |  |  |     .name          = TYPE_MAX_1110, | 
					
						
							|  |  |  |     .parent        = TYPE_MAX_111X, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .class_init    = max1110_class_init, | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | static void max1111_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-12 14:49:55 +02:00
										 |  |  |     SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 13:06:37 +01:00
										 |  |  |     k->realize = max1111_realize; | 
					
						
							| 
									
										
										
										
											2020-07-03 16:59:44 +01:00
										 |  |  |     device_class_set_props(dc, max1111_properties); | 
					
						
							| 
									
										
										
										
											2011-12-16 13:36:39 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo max1111_info = { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  |     .name          = TYPE_MAX_1111, | 
					
						
							|  |  |  |     .parent        = TYPE_MAX_111X, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .class_init    = max1111_class_init, | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | static void max111x_register_types(void) | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-11 16:29:00 -08:00
										 |  |  |     type_register_static(&max111x_info); | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     type_register_static(&max1110_info); | 
					
						
							|  |  |  |     type_register_static(&max1111_info); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | type_init(max111x_register_types) |