Patrick Georgi | 7051707 | 2020-05-10 18:47:05 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: BSD-3-Clause */ |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 2 | |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 3 | #include <console/console.h> |
Nico Huber | 0f2dd1e | 2017-08-01 14:02:40 +0200 | [diff] [blame] | 4 | #include <device/i2c_simple.h> |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 5 | #include <string.h> |
| 6 | #include <soc/gsbi.h> |
| 7 | #include <soc/qup.h> |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 8 | |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 9 | static qup_config_t gsbi1_qup_config = { |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 10 | QUP_MINICORE_I2C_MASTER, |
| 11 | 100000, |
| 12 | 24000000, |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 13 | QUP_MODE_FIFO, |
| 14 | 0 |
| 15 | }; |
| 16 | |
| 17 | static qup_config_t gsbi4_qup_config = { |
| 18 | QUP_MINICORE_I2C_MASTER, |
| 19 | 100000, |
| 20 | 24000000, |
| 21 | QUP_MODE_FIFO, |
| 22 | 0 |
| 23 | }; |
| 24 | |
| 25 | static qup_config_t gsbi7_qup_config = { |
| 26 | QUP_MINICORE_I2C_MASTER, |
| 27 | 100000, |
| 28 | 24000000, |
| 29 | QUP_MODE_FIFO, |
| 30 | 0 |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 31 | }; |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 32 | |
| 33 | static int i2c_read(uint32_t gsbi_id, uint8_t slave, |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 34 | uint8_t *data, int data_len) |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 35 | { |
| 36 | qup_data_t obj; |
| 37 | qup_return_t qup_ret = 0; |
| 38 | |
| 39 | memset(&obj, 0, sizeof(obj)); |
| 40 | obj.protocol = QUP_MINICORE_I2C_MASTER; |
| 41 | obj.p.iic.addr = slave; |
| 42 | obj.p.iic.data_len = data_len; |
| 43 | obj.p.iic.data = data; |
| 44 | qup_ret = qup_recv_data(gsbi_id, &obj); |
| 45 | |
| 46 | if (QUP_SUCCESS != qup_ret) |
| 47 | return 1; |
| 48 | else |
| 49 | return 0; |
| 50 | } |
| 51 | |
| 52 | static int i2c_write(uint32_t gsbi_id, uint8_t slave, |
| 53 | uint8_t *data, int data_len, uint8_t stop_seq) |
| 54 | { |
| 55 | qup_data_t obj; |
| 56 | qup_return_t qup_ret = 0; |
| 57 | |
| 58 | memset(&obj, 0, sizeof(obj)); |
| 59 | obj.protocol = QUP_MINICORE_I2C_MASTER; |
| 60 | obj.p.iic.addr = slave; |
| 61 | obj.p.iic.data_len = data_len; |
| 62 | obj.p.iic.data = data; |
| 63 | qup_ret = qup_send_data(gsbi_id, &obj, stop_seq); |
| 64 | |
| 65 | if (QUP_SUCCESS != qup_ret) |
| 66 | return 1; |
| 67 | else |
| 68 | return 0; |
| 69 | } |
| 70 | |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 71 | static int i2c_init(unsigned int bus) |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 72 | { |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 73 | unsigned int gsbi_id = bus; |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 74 | qup_config_t *qup_config; |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 75 | |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 76 | switch (gsbi_id) { |
| 77 | case GSBI_ID_1: |
| 78 | qup_config = &gsbi1_qup_config; |
| 79 | break; |
| 80 | case GSBI_ID_4: |
| 81 | qup_config = &gsbi4_qup_config; |
| 82 | break; |
| 83 | case GSBI_ID_7: |
| 84 | qup_config = &gsbi7_qup_config; |
| 85 | break; |
| 86 | default: |
Martin Roth | 26f97f9 | 2021-10-01 14:53:22 -0600 | [diff] [blame] | 87 | printk(BIOS_ERR, "QUP configuration not defined for GSBI%d.\n", |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 88 | gsbi_id); |
| 89 | return 1; |
| 90 | } |
| 91 | |
| 92 | if (qup_config->initialized) |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 93 | return 0; |
| 94 | |
| 95 | if (gsbi_init(gsbi_id, GSBI_PROTO_I2C_ONLY)) { |
| 96 | printk(BIOS_ERR, "failed to initialize gsbi\n"); |
| 97 | return 1; |
| 98 | } |
| 99 | |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 100 | if (qup_init(gsbi_id, qup_config)) { |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 101 | printk(BIOS_ERR, "failed to initialize qup\n"); |
| 102 | return 1; |
| 103 | } |
| 104 | |
| 105 | if (qup_reset_i2c_master_status(gsbi_id)) { |
| 106 | printk(BIOS_ERR, "failed to reset i2c master status\n"); |
| 107 | return 1; |
| 108 | } |
| 109 | |
Sourabh Banerjee | 8920865 | 2015-02-19 16:43:26 +0530 | [diff] [blame] | 110 | qup_config->initialized = 1; |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 111 | return 0; |
| 112 | } |
| 113 | |
Martin Roth | 57e8909 | 2019-10-23 21:45:23 -0600 | [diff] [blame] | 114 | int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, |
Nico Huber | 029dfff | 2017-07-12 17:59:16 +0200 | [diff] [blame] | 115 | int seg_count) |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 116 | { |
Nico Huber | 029dfff | 2017-07-12 17:59:16 +0200 | [diff] [blame] | 117 | struct i2c_msg *seg = segments; |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 118 | int ret = 0; |
| 119 | |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 120 | if (i2c_init(bus)) |
| 121 | return 1; |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 122 | |
Sourabh Banerjee | 54cc8ba | 2015-02-27 19:11:19 +0530 | [diff] [blame] | 123 | while (!ret && seg_count--) { |
Nico Huber | 029dfff | 2017-07-12 17:59:16 +0200 | [diff] [blame] | 124 | if (seg->flags & I2C_M_RD) |
| 125 | ret = i2c_read(bus, seg->slave, seg->buf, seg->len); |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 126 | else |
Nico Huber | 029dfff | 2017-07-12 17:59:16 +0200 | [diff] [blame] | 127 | ret = i2c_write(bus, seg->slave, seg->buf, seg->len, |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 128 | (seg_count ? 0 : 1)); |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 129 | seg++; |
| 130 | } |
| 131 | |
Vadim Bendebury | 6fe4e5e | 2014-12-06 10:44:58 -0800 | [diff] [blame] | 132 | if (ret) { |
| 133 | qup_set_state(bus, QUP_STATE_RESET); |
Daisuke Nojiri | 0594914 | 2014-11-21 15:33:26 -0800 | [diff] [blame] | 134 | return 1; |
| 135 | } |
| 136 | |
| 137 | return 0; |
| 138 | } |